Commit a550bb16 authored by Hersen Wu's avatar Hersen Wu Committed by Alex Deucher
Browse files

drm/amd/display: dsc engine not disabled after unplug dsc mst hub



[WHY]
If timing and bpp of displays on mst hub are not changed,
pbn, slot_num for displays should not be changed. Linux
user mode may initiate atomic_check with different display
configuration after set mode finished. This will call to
amdgpu_dm to re-compute payload, slot_num of displays and
saved to dm_connect_state. stream->timing.flags.dsc, pbn,
slot_num are updated to values which may be different from
that were used for set mode. when dsc hub with 3 4k@60hz dp
connected, 3 dsc engines are enabled. timing.flags.dsc = 1.
timing.flags.dsc are changed to 0 due to atomic check. when
dsc hub is unplugged, amdgpu driver check timing.flags.dsc
for last mode set and find out flags.dsc = 0, then does not
disable dsc.

[HOW]
check status of  displays on dsc mst hubs. re-compute pbn,
slot_num, timing.flags.dsc only if there is mode, connect
or enable/disable change.

Acked-by: default avatarAurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: default avatarHersen Wu <hersenwu@amd.com>
Reviewed-by: default avatarMikita Lipski <Mikita.Lipski@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 93cec184
Loading
Loading
Loading
Loading
+19 −12
Original line number Diff line number Diff line
@@ -7249,8 +7249,8 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
	struct drm_connector_state *new_con_state;
	struct amdgpu_dm_connector *aconnector;
	struct dm_connector_state *dm_conn_state;
	int i, j, clock;
	int vcpi, pbn_div, pbn = 0;
	int i, j;
	int vcpi, pbn_div, pbn, slot_num = 0;

	for_each_new_connector_in_state(state, connector, new_con_state, i) {

@@ -7278,17 +7278,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
		if (!stream)
			continue;

		if (stream->timing.flags.DSC != 1) {
			drm_dp_mst_atomic_enable_dsc(state,
						     aconnector->port,
						     dm_conn_state->pbn,
						     0,
						     false);
			continue;
		}

		pbn_div = dm_mst_get_pbn_divider(stream->link);
		clock = stream->timing.pix_clk_100hz / 10;
		/* pbn is calculated by compute_mst_dsc_configs_for_state*/
		for (j = 0; j < dc_state->stream_count; j++) {
			if (vars[j].aconnector == aconnector) {
@@ -7297,6 +7287,23 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
			}
		}

		if (j == dc_state->stream_count)
			continue;

		slot_num = DIV_ROUND_UP(pbn, pbn_div);

		if (stream->timing.flags.DSC != 1) {
			dm_conn_state->pbn = pbn;
			dm_conn_state->vcpi_slots = slot_num;

			drm_dp_mst_atomic_enable_dsc(state,
						     aconnector->port,
						     dm_conn_state->pbn,
						     0,
						     false);
			continue;
		}

		vcpi = drm_dp_mst_atomic_enable_dsc(state,
						    aconnector->port,
						    pbn, pbn_div,
+119 −31
Original line number Diff line number Diff line
@@ -534,13 +534,14 @@ static int kbps_to_peak_pbn(int kbps)

static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params,
		struct dsc_mst_fairness_vars *vars,
		int count)
		int count,
		int k)
{
	int i;

	for (i = 0; i < count; i++) {
		memset(&params[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg));
		if (vars[i].dsc_enabled && dc_dsc_compute_config(
		if (vars[i + k].dsc_enabled && dc_dsc_compute_config(
					params[i].sink->ctx->dc->res_pool->dscs[0],
					&params[i].sink->dsc_caps.dsc_dec_caps,
					params[i].sink->ctx->dc->debug.dsc_min_slice_height_override,
@@ -553,7 +554,7 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p
			if (params[i].bpp_overwrite)
				params[i].timing->dsc_cfg.bits_per_pixel = params[i].bpp_overwrite;
			else
				params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16;
				params[i].timing->dsc_cfg.bits_per_pixel = vars[i + k].bpp_x16;

			if (params[i].num_slices_h)
				params[i].timing->dsc_cfg.num_slices_h = params[i].num_slices_h;
@@ -586,7 +587,8 @@ static void increase_dsc_bpp(struct drm_atomic_state *state,
			     struct dc_link *dc_link,
			     struct dsc_mst_fairness_params *params,
			     struct dsc_mst_fairness_vars *vars,
			     int count)
			     int count,
			     int k)
{
	int i;
	bool bpp_increased[MAX_PIPES];
@@ -601,8 +603,9 @@ static void increase_dsc_bpp(struct drm_atomic_state *state,
	pbn_per_timeslot = dm_mst_get_pbn_divider(dc_link);

	for (i = 0; i < count; i++) {
		if (vars[i].dsc_enabled) {
			initial_slack[i] = kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i].pbn;
		if (vars[i + k].dsc_enabled) {
			initial_slack[i] =
			kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i + k].pbn;
			bpp_increased[i] = false;
			remaining_to_increase += 1;
		} else {
@@ -629,7 +632,7 @@ static void increase_dsc_bpp(struct drm_atomic_state *state,
		link_timeslots_used = 0;

		for (i = 0; i < count; i++)
			link_timeslots_used += DIV_ROUND_UP(vars[i].pbn, pbn_per_timeslot);
			link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, pbn_per_timeslot);

		fair_pbn_alloc = (63 - link_timeslots_used) / remaining_to_increase * pbn_per_timeslot;

@@ -682,7 +685,8 @@ static void try_disable_dsc(struct drm_atomic_state *state,
			    struct dc_link *dc_link,
			    struct dsc_mst_fairness_params *params,
			    struct dsc_mst_fairness_vars *vars,
			    int count)
			    int count,
			    int k)
{
	int i;
	bool tried[MAX_PIPES];
@@ -692,8 +696,8 @@ static void try_disable_dsc(struct drm_atomic_state *state,
	int remaining_to_try = 0;

	for (i = 0; i < count; i++) {
		if (vars[i].dsc_enabled
				&& vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16
		if (vars[i + k].dsc_enabled
				&& vars[i + k].bpp_x16 == params[i].bw_range.max_target_bpp_x16
				&& params[i].clock_force_enable == DSC_CLK_FORCE_DEFAULT) {
			kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps;
			tried[i] = false;
@@ -748,9 +752,10 @@ static void try_disable_dsc(struct drm_atomic_state *state,
static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
					     struct dc_state *dc_state,
					     struct dc_link *dc_link,
					     struct dsc_mst_fairness_vars *vars)
					     struct dsc_mst_fairness_vars *vars,
					     int *link_vars_start_index)
{
	int i;
	int i, k;
	struct dc_stream_state *stream;
	struct dsc_mst_fairness_params params[MAX_PIPES];
	struct amdgpu_dm_connector *aconnector;
@@ -768,11 +773,17 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
		if (stream->link != dc_link)
			continue;

		aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
		if (!aconnector)
			continue;

		if (!aconnector->port)
			continue;

		stream->timing.flags.DSC = 0;

		params[count].timing = &stream->timing;
		params[count].sink = stream->sink;
		aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
		params[count].aconnector = aconnector;
		params[count].port = aconnector->port;
		params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable;
@@ -794,44 +805,55 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,

		count++;
	}

	if (count == 0) {
		ASSERT(0);
		return true;
	}

	/* k is start index of vars for current phy link used by mst hub */
	k = *link_vars_start_index;
	/* set vars start index for next mst hub phy link */
	*link_vars_start_index += count;

	/* Try no compression */
	for (i = 0; i < count; i++) {
		vars[i].aconnector = params[i].aconnector;
		vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
		vars[i].dsc_enabled = false;
		vars[i].bpp_x16 = 0;
		vars[i + k].aconnector = params[i].aconnector;
		vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
		vars[i + k].dsc_enabled = false;
		vars[i + k].bpp_x16 = 0;
		if (drm_dp_atomic_find_vcpi_slots(state,
						 params[i].port->mgr,
						 params[i].port,
						 vars[i].pbn,
						 vars[i + k].pbn,
						 dm_mst_get_pbn_divider(dc_link)) < 0)
			return false;
	}
	if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) {
		set_dsc_configs_from_fairness_vars(params, vars, count);
		set_dsc_configs_from_fairness_vars(params, vars, count, k);
		return true;
	}

	/* Try max compression */
	for (i = 0; i < count; i++) {
		if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) {
			vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
			vars[i].dsc_enabled = true;
			vars[i].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
			vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
			vars[i + k].dsc_enabled = true;
			vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
			if (drm_dp_atomic_find_vcpi_slots(state,
							  params[i].port->mgr,
							  params[i].port,
							  vars[i].pbn,
							  vars[i + k].pbn,
							  dm_mst_get_pbn_divider(dc_link)) < 0)
				return false;
		} else {
			vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
			vars[i].dsc_enabled = false;
			vars[i].bpp_x16 = 0;
			vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
			vars[i + k].dsc_enabled = false;
			vars[i + k].bpp_x16 = 0;
			if (drm_dp_atomic_find_vcpi_slots(state,
							  params[i].port->mgr,
							  params[i].port,
							  vars[i].pbn,
							  vars[i + k].pbn,
							  dm_mst_get_pbn_divider(dc_link)) < 0)
				return false;
		}
@@ -840,15 +862,76 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
		return false;

	/* Optimize degree of compression */
	increase_dsc_bpp(state, dc_link, params, vars, count);
	increase_dsc_bpp(state, dc_link, params, vars, count, k);

	try_disable_dsc(state, dc_link, params, vars, count);
	try_disable_dsc(state, dc_link, params, vars, count, k);

	set_dsc_configs_from_fairness_vars(params, vars, count);
	set_dsc_configs_from_fairness_vars(params, vars, count, k);

	return true;
}

static bool is_dsc_need_re_compute(
	struct drm_atomic_state *state,
	struct dc_state *dc_state,
	struct dc_link *dc_link)
{
	int i;
	bool is_dsc_need_re_compute = false;

	/* only check phy used by mst branch */
	if (dc_link->type != dc_connection_mst_branch)
		return false;

	/* check if there is mode change in new request */
	for (i = 0; i < dc_state->stream_count; i++) {
		struct amdgpu_dm_connector *aconnector;
		struct dc_stream_state *stream;
		struct drm_crtc_state *new_crtc_state;
		struct drm_connector_state *new_conn_state;

		stream = dc_state->streams[i];

		if (!stream)
			continue;

		/* check if stream using the same link for mst */
		if (stream->link != dc_link)
			continue;

		aconnector = (struct amdgpu_dm_connector *) stream->dm_stream_context;
		if (!aconnector)
			continue;

		new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base);

		if (!new_conn_state)
			continue;

		if (IS_ERR(new_conn_state))
			continue;

		if (!new_conn_state->crtc)
			continue;

		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);

		if (!new_crtc_state)
			continue;

		if (IS_ERR(new_crtc_state))
			continue;

		if (new_crtc_state->enable && new_crtc_state->active) {
			if (new_crtc_state->mode_changed || new_crtc_state->active_changed ||
				new_crtc_state->connectors_changed)
				is_dsc_need_re_compute = true;
		}
	}

	return is_dsc_need_re_compute;
}

bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
				       struct dc_state *dc_state,
				       struct dsc_mst_fairness_vars *vars)
@@ -857,6 +940,7 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
	struct dc_stream_state *stream;
	bool computed_streams[MAX_PIPES];
	struct amdgpu_dm_connector *aconnector;
	int link_vars_start_index = 0;

	for (i = 0; i < dc_state->stream_count; i++)
		computed_streams[i] = false;
@@ -881,8 +965,12 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
		if (dcn20_remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK)
			return false;

		if (!is_dsc_need_re_compute(state, dc_state, stream->link))
			continue;

		mutex_lock(&aconnector->mst_mgr.lock);
		if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars)) {
		if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link,
			vars, &link_vars_start_index)) {
			mutex_unlock(&aconnector->mst_mgr.lock);
			return false;
		}