Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1f6d01c authored by Dmytro Laktyushkin's avatar Dmytro Laktyushkin Committed by Alex Deucher
Browse files

drm/amd/display: re structure odm to allow 4 to 1 support



Currently odm is handled using top_bottom pipe by special casing
the differing opps to differentiate from mpc combine.

Since top/bottom pipe list was made to track mpc muxing this creates
difficulties in adding a 4 pipe odm case support.

Rather than continue using mpc combine list, this change reworks odm
to use it's own linked list to keep track of odm combine pipes. This
also opens up options for using mpo with odm, if a practical use case
is ever found.

Signed-off-by: default avatarDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: default avatarCharlene Liu <Charlene.Liu@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent bad4c3e6
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -1860,9 +1860,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
	for (j = 0; j < dc->res_pool->pipe_count; j++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];

		if (!pipe_ctx->top_pipe &&
			pipe_ctx->stream &&
			pipe_ctx->stream == stream) {
		if (!pipe_ctx->top_pipe &&  !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) {

			if (stream_update->periodic_interrupt0 &&
					dc->hwss.setup_periodic_interrupt)
@@ -1888,7 +1886,7 @@ static void commit_planes_do_stream_update(struct dc *dc,

			if (stream_update->dither_option) {
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
				struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
				struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
#endif
				resource_build_bit_depth_reduction_params(pipe_ctx->stream,
									&pipe_ctx->stream->bit_depth_params);
@@ -1896,10 +1894,12 @@ static void commit_planes_do_stream_update(struct dc *dc,
						&stream->bit_depth_params,
						&stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
				if (odm_pipe)
				while (odm_pipe) {
					odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp,
							&stream->bit_depth_params,
							&stream->clamping);
					odm_pipe = odm_pipe->next_odm_pipe;
				}
#endif
			}

+21 −12
Original line number Diff line number Diff line
@@ -3095,14 +3095,19 @@ static void set_crtc_test_pattern(struct dc_link *link,
				controller_test_pattern, color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
		else if (opp->funcs->opp_set_disp_pattern_generator) {
			struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
			struct pipe_ctx *odm_pipe;
			int opp_cnt = 1;

			if (bot_odm_pipe) {
				struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp;
			for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
				opp_cnt++;

				bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
				width /= 2;
				bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
			width /= opp_cnt;

			for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
				struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;

				odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
				odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
					controller_test_pattern,
					color_depth,
					NULL,
@@ -3131,14 +3136,18 @@ static void set_crtc_test_pattern(struct dc_link *link,
				color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
		else if (opp->funcs->opp_set_disp_pattern_generator) {
			struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
			struct pipe_ctx *odm_pipe;
			int opp_cnt = 1;

			for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
				opp_cnt++;

			if (bot_odm_pipe) {
				struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp;
			width /= opp_cnt;
			for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
				struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;

				bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
				width /= 2;
				bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
				odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
				odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
					CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
					color_depth,
					NULL,
+19 −17
Original line number Diff line number Diff line
@@ -275,7 +275,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,

	for (i = 0; i < MAX_PIPES; i++) {
		if (pipes[i].stream != NULL &&
			!pipes[i].top_pipe &&
			!pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
			pipes[i].stream->link != NULL &&
			pipes[i].stream_res.stream_enc != NULL) {
			udelay(100);
@@ -381,7 +381,11 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
	struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
	struct dc *core_dc = pipe_ctx->stream->ctx->dc;
	struct dc_stream_state *stream = pipe_ctx->stream;
	struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
	struct pipe_ctx *odm_pipe;
	int opp_cnt = 1;

	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
		opp_cnt++;

	if (enable) {
		struct dsc_config dsc_cfg;
@@ -389,26 +393,24 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
		enum optc_dsc_mode optc_dsc_mode;

		/* Enable DSC hw block */
		dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
		dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
		dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
		dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
		dsc_cfg.color_depth = stream->timing.display_color_depth;
		dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
		ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
		dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;

		if (odm_pipe) {
			struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc;

			dsc_cfg.pic_width /= 2;
			ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % 2 == 0);
			dsc_cfg.dc_dsc_cfg.num_slices_h /= 2;
			dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
			bot_dsc->funcs->dsc_set_config(bot_dsc, &dsc_cfg, &dsc_optc_cfg);
			dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
			bot_dsc->funcs->dsc_enable(bot_dsc, odm_pipe->stream_res.opp->inst);
		} else {
		dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
		dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
		for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
			struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;

			odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
			odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
		}
		dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
		dsc_cfg.pic_width *= opp_cnt;

		optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;

@@ -449,7 +451,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)

		/* disable DSC block */
		pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
		if (odm_pipe)
		for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
			odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
	}
}
+50 −100
Original line number Diff line number Diff line
@@ -1117,8 +1117,9 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
{
	int i;
	for (i = 0; i < MAX_PIPES; i++) {
		if (res_ctx->pipe_ctx[i].stream == stream &&
				!res_ctx->pipe_ctx[i].top_pipe) {
		if (res_ctx->pipe_ctx[i].stream == stream
				&& !res_ctx->pipe_ctx[i].top_pipe
				&& !res_ctx->pipe_ctx[i].prev_odm_pipe) {
			return &res_ctx->pipe_ctx[i];
			break;
		}
@@ -1126,15 +1127,11 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
	return NULL;
}

static struct pipe_ctx *resource_get_tail_pipe_for_stream(
static struct pipe_ctx *resource_get_tail_pipe(
		struct resource_context *res_ctx,
		struct dc_stream_state *stream)
		struct pipe_ctx *head_pipe)
{
	struct pipe_ctx *head_pipe, *tail_pipe;
	head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);

	if (!head_pipe)
		return NULL;
	struct pipe_ctx *tail_pipe;

	tail_pipe = head_pipe->bottom_pipe;

@@ -1150,31 +1147,20 @@ static struct pipe_ctx *resource_get_tail_pipe_for_stream(
 * A free_pipe for a stream is defined here as a pipe
 * that has no surface attached yet
 */
static struct pipe_ctx *acquire_free_pipe_for_stream(
static struct pipe_ctx *acquire_free_pipe_for_head(
		struct dc_state *context,
		const struct resource_pool *pool,
		struct dc_stream_state *stream)
		struct pipe_ctx *head_pipe)
{
	int i;
	struct resource_context *res_ctx = &context->res_ctx;

	struct pipe_ctx *head_pipe = NULL;

	/* Find head pipe, which has the back end set up*/

	head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);

	if (!head_pipe) {
		ASSERT(0);
		return NULL;
	}

	if (!head_pipe->plane_state)
		return head_pipe;

	/* Re-use pipe already acquired for this stream if available*/
	for (i = pool->pipe_count - 1; i >= 0; i--) {
		if (res_ctx->pipe_ctx[i].stream == stream &&
		if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
				!res_ctx->pipe_ctx[i].plane_state) {
			return &res_ctx->pipe_ctx[i];
		}
@@ -1188,8 +1174,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream(
	if (!pool->funcs->acquire_idle_pipe_for_layer)
		return NULL;

	return pool->funcs->acquire_idle_pipe_for_layer(context, pool, stream);

	return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
}

#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
@@ -1203,7 +1188,7 @@ static int acquire_first_split_pipe(
	for (i = 0; i < pool->pipe_count; i++) {
		struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];

		if (split_pipe->top_pipe && !dc_res_is_odm_head_pipe(split_pipe) &&
		if (split_pipe->top_pipe &&
				split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
			split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
			if (split_pipe->bottom_pipe)
@@ -1264,10 +1249,14 @@ bool dc_add_plane_to_context(
		return false;
	}

	tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
	/* retain new surface, but only once per stream */
	dc_plane_state_retain(plane_state);

	while (head_pipe) {
		tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
		ASSERT(tail_pipe);

	free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
		free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);

	#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
		if (!free_pipe) {
@@ -1276,11 +1265,11 @@ bool dc_add_plane_to_context(
				free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
		}
	#endif
	if (!free_pipe)
		if (!free_pipe) {
			dc_plane_state_release(plane_state);
			return false;
		}

	/* retain new surfaces */
	dc_plane_state_retain(plane_state);
		free_pipe->plane_state = plane_state;

		if (head_pipe != free_pipe) {
@@ -1292,11 +1281,9 @@ bool dc_add_plane_to_context(
			free_pipe->clock_source = tail_pipe->clock_source;
			free_pipe->top_pipe = tail_pipe;
			tail_pipe->bottom_pipe = free_pipe;
	} else if (free_pipe->bottom_pipe && free_pipe->bottom_pipe->plane_state == NULL) {
		ASSERT(free_pipe->bottom_pipe->stream_res.opp != free_pipe->stream_res.opp);
		free_pipe->bottom_pipe->plane_state = plane_state;
		}

		head_pipe = head_pipe->next_odm_pipe;
	}
	/* assign new surfaces*/
	stream_status->plane_states[stream_status->plane_count] = plane_state;

@@ -1305,35 +1292,6 @@ bool dc_add_plane_to_context(
	return true;
}

struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx)
{
	struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe;

	/* ODM should only be updated once per otg */
	if (pipe_ctx->top_pipe)
		return NULL;

	while (bottom_pipe) {
		if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp)
			break;
		bottom_pipe = bottom_pipe->bottom_pipe;
	}

	return bottom_pipe;
}

bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx)
{
	struct pipe_ctx *top_pipe = pipe_ctx->top_pipe;

	if (!top_pipe)
		return false;
	if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp)
		return false;

	return true;
}

bool dc_remove_plane_from_context(
		const struct dc *dc,
		struct dc_stream_state *stream,
@@ -1360,12 +1318,6 @@ bool dc_remove_plane_from_context(
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];

		if (pipe_ctx->plane_state == plane_state) {
			if (dc_res_is_odm_head_pipe(pipe_ctx)) {
				pipe_ctx->plane_state = NULL;
				pipe_ctx->bottom_pipe = NULL;
				continue;
			}

			if (pipe_ctx->top_pipe)
				pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;

@@ -1380,15 +1332,12 @@ bool dc_remove_plane_from_context(
			 * For head pipe detach surfaces from pipe for tail
			 * pipe just zero it out
			 */
			if (!pipe_ctx->top_pipe) {
			if (!pipe_ctx->top_pipe)
				pipe_ctx->plane_state = NULL;
				if (!dc_res_get_odm_bottom_pipe(pipe_ctx))
					pipe_ctx->bottom_pipe = NULL;
			} else {
			else
				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
		}
	}
	}


	for (i = 0; i < stream_status->plane_count; i++) {
@@ -1755,9 +1704,6 @@ enum dc_status dc_remove_stream_from_ctx(
	for (i = 0; i < MAX_PIPES; i++) {
		if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
				!new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
			struct pipe_ctx *odm_pipe =
					dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]);

			del_pipe = &new_ctx->res_ctx.pipe_ctx[i];

			ASSERT(del_pipe->stream_res.stream_enc);
@@ -1782,8 +1728,6 @@ enum dc_status dc_remove_stream_from_ctx(
				dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);

			memset(del_pipe, 0, sizeof(*del_pipe));
			if (odm_pipe)
				memset(odm_pipe, 0, sizeof(*odm_pipe));

			break;
		}
@@ -2497,6 +2441,12 @@ void dc_resource_state_copy_construct(

		if (cur_pipe->bottom_pipe)
			cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];

		if (cur_pipe->next_odm_pipe)
			cur_pipe->next_odm_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];

		if (cur_pipe->prev_odm_pipe)
			cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
	}

	for (i = 0; i < dst_ctx->stream_count; i++) {
+4 −3
Original line number Diff line number Diff line
@@ -1341,7 +1341,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
	struct drr_params params = {0};
	unsigned int event_triggers = 0;
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
	struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
	struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
#endif

	if (dc->hwss.disable_stream_gating) {
@@ -1409,7 +1409,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
		&stream->bit_depth_params,
		&stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
	if (odm_pipe) {
	while (odm_pipe) {
		odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
				odm_pipe->stream_res.opp,
				COLOR_SPACE_YCBCR601,
@@ -1420,6 +1420,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
				odm_pipe->stream_res.opp,
				&stream->bit_depth_params,
				&stream->clamping);
		odm_pipe = odm_pipe->next_odm_pipe;
	}
#endif

@@ -2079,7 +2080,7 @@ enum dc_status dce110_apply_ctx_to_hw(
		if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
			continue;

		if (pipe_ctx->top_pipe)
		if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
			continue;

		status = apply_single_controller_ctx_to_hw(
Loading