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

Commit 6fbefb84 authored by Harry Wentland's avatar Harry Wentland Committed by Alex Deucher
Browse files

drm/amd/display: Add DC core changes for DCN2



Core DC changes for DCN2.

Signed-off-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 7ed4e635
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@

DC_LIBS = basics bios calcs clk_mgr dce gpio irq virtual

ifdef CONFIG_DRM_AMD_DC_DCN2_0
DC_LIBS += dcn20
endif



ifdef CONFIG_DRM_AMD_DC_DCN1_0
DC_LIBS += dcn10 dml
endif
+140 −1
Original line number Diff line number Diff line
@@ -56,6 +56,10 @@

#include "dc_link_dp.h"

#ifdef CONFIG_DRM_AMD_DC_DCN2_0
#include "vm_helper.h"
#endif

#include "dce/dce_i2c.h"

#define DC_LOGGER \
@@ -528,6 +532,11 @@ static void destruct(struct dc *dc)
	kfree(dc->dcn_ip);
	dc->dcn_ip = NULL;

#endif
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
	kfree(dc->vm_helper);
	dc->vm_helper = NULL;

#endif
}

@@ -545,6 +554,11 @@ static bool construct(struct dc *dc,
	enum dce_version dc_version = DCE_VERSION_UNKNOWN;
	dc->config = init_params->flags;

#ifdef CONFIG_DRM_AMD_DC_DCN2_0
	// Allocate memory for the vm_helper
	dc->vm_helper = kzalloc(sizeof(struct vm_helper), GFP_KERNEL);

#endif
	memcpy(&dc->bb_overrides, &init_params->bb_overrides, sizeof(dc->bb_overrides));

	dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL);
@@ -578,6 +592,9 @@ static bool construct(struct dc *dc,
	}

	dc->dcn_ip = dcn_ip;
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
	dc->soc_bounding_box = init_params->soc_bounding_box;
#endif
#endif

	dc_ctx = kzalloc(sizeof(*dc_ctx), GFP_KERNEL);
@@ -674,6 +691,21 @@ static bool construct(struct dc *dc,
	return false;
}

#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
static bool disable_all_writeback_pipes_for_stream(
		const struct dc *dc,
		struct dc_stream_state *stream,
		struct dc_state *context)
{
	int i;

	for (i = 0; i < stream->num_wb_info; i++)
		stream->writeback_info[i].wb_enabled = false;

	return true;
}
#endif

static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
{
	int i, j;
@@ -698,6 +730,9 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
		}
		if (should_disable && old_stream) {
			dc_rem_all_planes_for_stream(dc, old_stream, dangling_context);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
			disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context);
#endif
			dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context);
		}
	}
@@ -769,6 +804,26 @@ void dc_destroy(struct dc **dc)
	*dc = NULL;
}

#ifdef CONFIG_DRM_AMD_DC_DCN2_0
bool dc_init_memory_hub(struct dc *dc, struct dc_addr_space_config *config)
{
	// Memory hub init isn't done as part of dc_create because in windows, dal/dc is
	// constructed before the vm config is setup in kmd so there's no way
	// they can give it to us at boot/dc_create
	bool vmSupported;

	// Call HWSS to setup HUBBUB for address config
	dc->hwss.init_dchub(dc->hwseq, dc, config);

	// Pre-init system aperture start/end for all HUBP instances (if not gating?)
	// or cache system aperture if using power gating
	memcpy(&dc->vm_config, config, sizeof(struct dc_addr_space_config));

	vmSupported = (dc->ctx->asic_id.chip_family == FAMILY_NV) ? true : false;
	return vmSupported;
}

#endif
static void enable_timing_multisync(
		struct dc *dc,
		struct dc_state *ctx)
@@ -1598,6 +1653,19 @@ static void copy_surface_update_to_plane(
			sizeof(struct dc_transfer_func_distributed_points));
	}

#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
	if (srf_update->func_shaper &&
			(surface->in_shaper_func !=
			srf_update->func_shaper))
		memcpy(surface->in_shaper_func, srf_update->func_shaper,
		sizeof(*surface->in_shaper_func));

	if (srf_update->lut3d_func &&
			(surface->lut3d_func !=
			srf_update->lut3d_func))
		memcpy(surface->lut3d_func, srf_update->lut3d_func,
		sizeof(*surface->lut3d_func));
#endif
	if (srf_update->input_csc_color_matrix)
		surface->input_csc_color_matrix =
			*srf_update->input_csc_color_matrix;
@@ -1646,11 +1714,20 @@ static void commit_planes_do_stream_update(struct dc *dc,
				dc_stream_program_csc_matrix(dc, stream);

			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);
#endif
				resource_build_bit_depth_reduction_params(pipe_ctx->stream,
									&pipe_ctx->stream->bit_depth_params);
				pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp,
						&stream->bit_depth_params,
						&stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
				if (odm_pipe)
					odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp,
							&stream->bit_depth_params,
							&stream->clamping);
#endif
			}

			/* Full fe update*/
@@ -1726,6 +1803,30 @@ static void commit_planes_for_stream(struct dc *dc,
		return;
	}

#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
	if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
		for (i = 0; i < surface_count; i++) {
			struct dc_plane_state *plane_state = srf_updates[i].surface;
			/*set logical flag for lock/unlock use*/
			for (j = 0; j < dc->res_pool->pipe_count; j++) {
				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
				if (!pipe_ctx->plane_state)
					continue;
				if (pipe_ctx->plane_state != plane_state)
					continue;
				plane_state->triplebuffer_flips = false;
				if (update_type == UPDATE_TYPE_FAST &&
					dc->hwss.program_triplebuffer != NULL &&
					!plane_state->flip_immediate &&
					!dc->debug.disable_tri_buf) {
						/*triple buffer for VUpdate  only*/
						plane_state->triplebuffer_flips = true;
				}
			}
		}
	}
#endif

	// Update Type FULL, Surface updates
	for (j = 0; j < dc->res_pool->pipe_count; j++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
@@ -1744,6 +1845,16 @@ static void commit_planes_for_stream(struct dc *dc,
			if (update_type == UPDATE_TYPE_FAST)
				continue;

#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
			ASSERT(!pipe_ctx->plane_state->triplebuffer_flips);

			if (dc->hwss.program_triplebuffer != NULL &&
				!dc->debug.disable_tri_buf) {
				/*turn off triple buffer for full update*/
				dc->hwss.program_triplebuffer(
					dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
			}
#endif
			stream_status =
				stream_get_status(context, pipe_ctx->stream);

@@ -1760,7 +1871,8 @@ static void commit_planes_for_stream(struct dc *dc,
		 */
		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);

		/* Perform requested Updates */
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
		if (dc->hwss.set_flip_control_gsl)
			for (i = 0; i < surface_count; i++) {
				struct dc_plane_state *plane_state = srf_updates[i].surface;

@@ -1773,6 +1885,33 @@ static void commit_planes_for_stream(struct dc *dc,
					if (pipe_ctx->plane_state != plane_state)
						continue;

					// GSL has to be used for flip immediate
					dc->hwss.set_flip_control_gsl(pipe_ctx,
							plane_state->flip_immediate);
				}
			}
#endif
		/* Perform requested Updates */
		for (i = 0; i < surface_count; i++) {
			struct dc_plane_state *plane_state = srf_updates[i].surface;

			for (j = 0; j < dc->res_pool->pipe_count; j++) {
				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];

				if (pipe_ctx->stream != stream)
					continue;

				if (pipe_ctx->plane_state != plane_state)
					continue;
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
				/*program triple buffer after lock based on flip type*/
				if (dc->hwss.program_triplebuffer != NULL &&
					!dc->debug.disable_tri_buf) {
					/*only enable triplebuffer for  fast_update*/
					dc->hwss.program_triplebuffer(
						dc, pipe_ctx, plane_state->triplebuffer_flips);
				}
#endif
				if (srf_updates[i].flip_addr)
					dc->hwss.update_plane_addr(dc, pipe_ctx);
			}
+5 −1
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@
#include "dpcd_defs.h"
#include "dmcu.h"
#include "hw/clk_mgr.h"
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#include "resource.h"
#endif
#include "hw/clk_mgr.h"

#define DC_LOGGER_INIT(logger)

@@ -1504,6 +1508,7 @@ static enum dc_status enable_link_dp(
	if (link_settings.link_rate == LINK_RATE_LOW)
			skip_video_pattern = false;


	if (perform_link_training_with_retries(
			link,
			&link_settings,
@@ -2739,7 +2744,6 @@ void core_link_enable_stream(
		if (dc_is_dp_signal(pipe_ctx->stream->signal))
			enable_stream_features(pipe_ctx);
	}

}

void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
+62 −0
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@
#include "dc_link_dp.h"
#include "dm_helpers.h"
#include "opp.h"
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#include "resource.h"
#endif

#include "inc/core_types.h"
#include "link_hwss.h"
@@ -2547,6 +2550,7 @@ static bool retrieve_link_cap(struct dc_link *link)
		dp_hw_fw_revision.ieee_fw_rev,
		sizeof(dp_hw_fw_revision.ieee_fw_rev));


	/* Connectivity log: detection */
	CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");

@@ -2674,6 +2678,14 @@ static void set_crtc_test_pattern(struct dc_link *link,
		stream->timing.display_color_depth;
	struct bit_depth_reduction_params params;
	struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
	int width = pipe_ctx->stream->timing.h_addressable +
		pipe_ctx->stream->timing.h_border_left +
		pipe_ctx->stream->timing.h_border_right;
	int height = pipe_ctx->stream->timing.v_addressable +
		pipe_ctx->stream->timing.v_border_bottom +
		pipe_ctx->stream->timing.v_border_top;
#endif

	memset(&params, 0, sizeof(params));

@@ -2717,6 +2729,30 @@ static void set_crtc_test_pattern(struct dc_link *link,
		if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
			pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
				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);

			if (bot_odm_pipe) {
				struct output_pixel_processor *bot_opp = bot_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,
					controller_test_pattern,
					color_depth,
					NULL,
					width,
					height);
			}
			opp->funcs->opp_set_disp_pattern_generator(opp,
				controller_test_pattern,
				color_depth,
				NULL,
				width,
				height);
		}
#endif
	}
	break;
	case DP_TEST_PATTERN_VIDEO_MODE:
@@ -2729,6 +2765,30 @@ static void set_crtc_test_pattern(struct dc_link *link,
			pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
				CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
				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);

			if (bot_odm_pipe) {
				struct output_pixel_processor *bot_opp = bot_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,
					CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
					color_depth,
					NULL,
					width,
					height);
			}
			opp->funcs->opp_set_disp_pattern_generator(opp,
				CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
				color_depth,
				NULL,
				width,
				height);
		}
#endif
	}
	break;

@@ -2903,3 +2963,5 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable)

	core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
}

+185 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ static void construct(struct dc_stream_state *stream,
	/* EDID CAP translation for HDMI 2.0 */
	stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;


	update_stream_signal(stream, dc_sink_data);

	stream->out_transfer_func = dc_create_transfer_func();
@@ -355,6 +356,119 @@ bool dc_stream_set_cursor_position(
	return true;
}

#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
bool dc_stream_add_writeback(struct dc *dc,
		struct dc_stream_state *stream,
		struct dc_writeback_info *wb_info)
{
	bool isDrc = false;
	int i = 0;

	if (stream == NULL) {
		dm_error("DC: dc_stream is NULL!\n");
		return false;
	}

	if (wb_info == NULL) {
		dm_error("DC: dc_writeback_info is NULL!\n");
		return false;
	}

	if (wb_info->dwb_pipe_inst >= MAX_DWB_PIPES) {
		dm_error("DC: writeback pipe is invalid!\n");
		return false;
	}

	wb_info->dwb_params.out_transfer_func = stream->out_transfer_func;



	/* recalculate and apply DML parameters */

	for (i = 0; i < stream->num_wb_info; i++) {
		/*dynamic update*/
		if (stream->writeback_info[i].wb_enabled &&
			stream->writeback_info[i].dwb_pipe_inst == wb_info->dwb_pipe_inst) {
			stream->writeback_info[i] = *wb_info;
			isDrc = true;
		}
	}

	if (!isDrc) {
		stream->writeback_info[stream->num_wb_info++] = *wb_info;
	}

	if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
		dm_error("DC: update_bandwidth failed!\n");
		return false;
	}

	/* enable writeback */
	if (dc->hwss.enable_writeback) {
		struct dc_stream_status *stream_status = dc_stream_get_status(stream);
		struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];

		if (dwb->funcs->is_enabled(dwb)) {
			/* writeback pipe already enabled, only need to update */
			dc->hwss.update_writeback(dc, stream_status, wb_info);
		} else {
			/* Enable writeback pipe from scratch*/
			dc->hwss.enable_writeback(dc, stream_status, wb_info);
		}
	}

	return true;
}

bool dc_stream_remove_writeback(struct dc *dc,
		struct dc_stream_state *stream,
		uint32_t dwb_pipe_inst)
{
	int i = 0, j = 0;
	if (stream == NULL) {
		dm_error("DC: dc_stream is NULL!\n");
		return false;
	}

	if (dwb_pipe_inst >= MAX_DWB_PIPES) {
		dm_error("DC: writeback pipe is invalid!\n");
		return false;
	}

//	stream->writeback_info[dwb_pipe_inst].wb_enabled = false;
	for (i = 0; i < stream->num_wb_info; i++) {
		/*dynamic update*/
		if (stream->writeback_info[i].wb_enabled &&
			stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) {
			stream->writeback_info[i].wb_enabled = false;
		}
	}

	/* remove writeback info for disabled writeback pipes from stream */
	for (i = 0, j = 0; i < stream->num_wb_info; i++) {
		if (stream->writeback_info[i].wb_enabled) {
			if (i != j)
				/* trim the array */
				stream->writeback_info[j] = stream->writeback_info[i];
			j++;
		}
	}
	stream->num_wb_info = j;

	/* recalculate and apply DML parameters */
	if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
		dm_error("DC: update_bandwidth failed!\n");
		return false;
	}

	/* disable writeback */
	if (dc->hwss.disable_writeback)
		dc->hwss.disable_writeback(dc, dwb_pipe_inst);

	return true;
}
#endif

uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream)
{
	uint8_t i;
@@ -439,6 +553,77 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,

	return ret;
}
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream)
{
	bool status = true;
	struct pipe_ctx *pipe = NULL;
	int i;

	if (!dc->hwss.dmdata_status_done)
		return false;

	for (i = 0; i < MAX_PIPES; i++) {
		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
		if (pipe->stream == stream)
			break;
	}
	/* Stream not found, by default we'll assume HUBP fetched dm data */
	if (i == MAX_PIPES)
		return true;

	status = dc->hwss.dmdata_status_done(pipe);
	return status;
}

bool dc_stream_set_dynamic_metadata(struct dc *dc,
		struct dc_stream_state *stream,
		struct dc_dmdata_attributes *attr)
{
	struct pipe_ctx *pipe_ctx = NULL;
	struct hubp *hubp;
	int i;

	for (i = 0; i < MAX_PIPES; i++) {
		pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
		if (pipe_ctx->stream == stream)
			break;
	}

	if (i == MAX_PIPES)
		return false;

	hubp = pipe_ctx->plane_res.hubp;
	if (hubp == NULL)
		return false;

	pipe_ctx->stream->dmdata_address = attr->address;

	if (pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata != NULL) {
		if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
			/* if using dynamic meta, don't set up generic infopackets */
			pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
			pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata(
					pipe_ctx->stream_res.stream_enc,
					true, pipe_ctx->plane_res.hubp->inst,
					dc_is_dp_signal(pipe_ctx->stream->signal) ?
							dmdata_dp : dmdata_hdmi);
		} else
			pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata(
					pipe_ctx->stream_res.stream_enc,
					false, pipe_ctx->plane_res.hubp->inst,
					dc_is_dp_signal(pipe_ctx->stream->signal) ?
							dmdata_dp : dmdata_hdmi);
	}

	if (hubp->funcs->dmdata_set_attributes != NULL &&
			pipe_ctx->stream->dmdata_address.quad_part != 0) {
		hubp->funcs->dmdata_set_attributes(hubp, attr);
	}

	return true;
}
#endif

void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
{
Loading