Commit 663d2dae authored by Duncan Ma's avatar Duncan Ma Committed by Alex Deucher
Browse files

drm/amd/display: Add odm seamless boot support



[WHY]
Implement changes to transition from Pre-OS odm to
Post-OS odm support. Seamless boot case is also
considered.

[HOW]
Revised validation logic when marking for seamless
boot. Init resources accordingly when Pre-OS has
odm enabled. Reset odm and det size when transitioning
Pre-OS odm to Post-OS non-odm to avoid corruption.
Apply logic to set odm accordingly upon commit.

Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarPavle Kotarac <Pavle.Kotarac@amd.com>
Signed-off-by: default avatarDuncan Ma <Duncan.Ma@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 56b5b1c7
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -1569,11 +1569,24 @@ bool dc_validate_boot_timing(const struct dc *dc,

	if (dc_is_dp_signal(link->connector_signal)) {
		unsigned int pix_clk_100hz;
		uint32_t numOdmPipes = 1;
		uint32_t id_src[4] = {0};

		dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
			dc->res_pool->dp_clock_source,
			tg_inst, &pix_clk_100hz);

		if (tg->funcs->get_optc_source)
			tg->funcs->get_optc_source(tg,
						&numOdmPipes, &id_src[0], &id_src[1]);

		if (numOdmPipes == 2)
			pix_clk_100hz *= 2;
		if (numOdmPipes == 4)
			pix_clk_100hz *= 4;

		// Note: In rare cases, HW pixclk may differ from crtc's pixclk
		// slightly due to rounding issues in 10 kHz units.
		if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
			return false;

+54 −28
Original line number Diff line number Diff line
@@ -2120,6 +2120,8 @@ static int acquire_resource_from_hw_enabled_state(
{
	struct dc_link *link = stream->link;
	unsigned int i, inst, tg_inst = 0;
	uint32_t numPipes = 1;
	uint32_t id_src[4] = {0};

	/* Check for enabled DIG to identify enabled display */
	if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
@@ -2148,38 +2150,62 @@ static int acquire_resource_from_hw_enabled_state(
	if (!res_ctx->pipe_ctx[tg_inst].stream) {
		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];

		id_src[0] = tg_inst;

		if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
			pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
					&numPipes, &id_src[0], &id_src[1]);

		for (i = 0; i < numPipes; i++) {
			//Check if src id invalid
			if (id_src[i] == 0xf)
				return -1;

			pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
		pipe_ctx->plane_res.mi = pool->mis[tg_inst];
		pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
		pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
		pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
		pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
		pipe_ctx->stream_res.opp = pool->opps[tg_inst];
			pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
			pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
			pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
			pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
			pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
			pipe_ctx->stream_res.opp = pool->opps[id_src[i]];

		if (pool->dpps[tg_inst]) {
			pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
			if (pool->dpps[id_src[i]]) {
				pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;

			// Read DPP->MPCC->OPP Pipe from HW State
				if (pool->mpc->funcs->read_mpcc_state) {
					struct mpcc_state s = {0};

					pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);

					if (s.dpp_id < MAX_MPCC)
					pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = s.dpp_id;

						pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
								s.dpp_id;
					if (s.bot_mpcc_id < MAX_MPCC)
						pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
								&pool->mpc->mpcc_array[s.bot_mpcc_id];

					if (s.opp_id < MAX_OPP)
						pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
				}
			}
		pipe_ctx->pipe_idx = tg_inst;
			pipe_ctx->pipe_idx = id_src[i];

			if (id_src[i] >= pool->timing_generator_count) {
				id_src[i] = pool->timing_generator_count - 1;
				pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
				pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
			}

			pipe_ctx->stream = stream;
		return tg_inst;
		}

		if (numPipes == 2) {
			stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
			res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
			res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
			res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
			res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
		} else
			stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;

		return id_src[0];
	}

	return -1;
+1 −0
Original line number Diff line number Diff line
@@ -666,6 +666,7 @@ struct dc_debug_options {
	uint32_t edid_read_retry_times;
	bool remove_disconnect_edp;
	unsigned int force_odm_combine; //bit vector based on otg inst
	unsigned int seamless_boot_odm_combine;
#if defined(CONFIG_DRM_AMD_DC_DCN)
	unsigned int force_odm_combine_4to1; //bit vector based on otg inst
	bool disable_z9_mpc;
+1 −0
Original line number Diff line number Diff line
@@ -246,6 +246,7 @@ struct dc_stream_state {

	bool apply_edp_fast_boot_optimization;
	bool apply_seamless_boot_optimization;
	uint32_t apply_boot_odm_mode;

	uint32_t stream_id;

+21 −0
Original line number Diff line number Diff line
@@ -1259,6 +1259,7 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
{
	int i;
	struct dce_hwseq *hws = dc->hwseq;
	struct hubbub *hubbub = dc->res_pool->hubbub;
	bool can_apply_seamless_boot = false;

	for (i = 0; i < context->stream_count; i++) {
@@ -1294,6 +1295,21 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
		}
	}

	/* Reset det size */
	for (i = 0; i < dc->res_pool->pipe_count; i++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
		struct hubp *hubp = dc->res_pool->hubps[i];

		/* Do not need to reset for seamless boot */
		if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
			continue;

		if (hubbub && hubp) {
			if (hubbub->funcs->program_det_size)
				hubbub->funcs->program_det_size(hubbub, hubp->inst, 0);
		}
	}

	/* num_opp will be equal to number of mpcc */
	for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
@@ -1359,6 +1375,11 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
		pipe_ctx->stream_res.tg = NULL;
		pipe_ctx->plane_res.hubp = NULL;

		if (tg->funcs->is_tg_enabled(tg)) {
			if (tg->funcs->init_odm)
				tg->funcs->init_odm(tg);
		}

		tg->funcs->tg_init(tg);
	}

Loading