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

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
...@@ -7249,8 +7249,8 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, ...@@ -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 drm_connector_state *new_con_state;
struct amdgpu_dm_connector *aconnector; struct amdgpu_dm_connector *aconnector;
struct dm_connector_state *dm_conn_state; struct dm_connector_state *dm_conn_state;
int i, j, clock; int i, j;
int vcpi, pbn_div, pbn = 0; int vcpi, pbn_div, pbn, slot_num = 0;
for_each_new_connector_in_state(state, connector, new_con_state, i) { 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, ...@@ -7278,17 +7278,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
if (!stream) if (!stream)
continue; 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); 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*/ /* pbn is calculated by compute_mst_dsc_configs_for_state*/
for (j = 0; j < dc_state->stream_count; j++) { for (j = 0; j < dc_state->stream_count; j++) {
if (vars[j].aconnector == aconnector) { if (vars[j].aconnector == aconnector) {
...@@ -7297,6 +7287,23 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, ...@@ -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, vcpi = drm_dp_mst_atomic_enable_dsc(state,
aconnector->port, aconnector->port,
pbn, pbn_div, pbn, pbn_div,
......
...@@ -534,13 +534,14 @@ static int kbps_to_peak_pbn(int kbps) ...@@ -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, static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params,
struct dsc_mst_fairness_vars *vars, struct dsc_mst_fairness_vars *vars,
int count) int count,
int k)
{ {
int i; int i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
memset(&params[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg)); 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->ctx->dc->res_pool->dscs[0],
&params[i].sink->dsc_caps.dsc_dec_caps, &params[i].sink->dsc_caps.dsc_dec_caps,
params[i].sink->ctx->dc->debug.dsc_min_slice_height_override, 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 ...@@ -553,7 +554,7 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p
if (params[i].bpp_overwrite) if (params[i].bpp_overwrite)
params[i].timing->dsc_cfg.bits_per_pixel = params[i].bpp_overwrite; params[i].timing->dsc_cfg.bits_per_pixel = params[i].bpp_overwrite;
else 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) if (params[i].num_slices_h)
params[i].timing->dsc_cfg.num_slices_h = 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, ...@@ -586,7 +587,8 @@ static void increase_dsc_bpp(struct drm_atomic_state *state,
struct dc_link *dc_link, struct dc_link *dc_link,
struct dsc_mst_fairness_params *params, struct dsc_mst_fairness_params *params,
struct dsc_mst_fairness_vars *vars, struct dsc_mst_fairness_vars *vars,
int count) int count,
int k)
{ {
int i; int i;
bool bpp_increased[MAX_PIPES]; bool bpp_increased[MAX_PIPES];
...@@ -601,8 +603,9 @@ static void increase_dsc_bpp(struct drm_atomic_state *state, ...@@ -601,8 +603,9 @@ static void increase_dsc_bpp(struct drm_atomic_state *state,
pbn_per_timeslot = dm_mst_get_pbn_divider(dc_link); pbn_per_timeslot = dm_mst_get_pbn_divider(dc_link);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (vars[i].dsc_enabled) { if (vars[i + k].dsc_enabled) {
initial_slack[i] = kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i].pbn; initial_slack[i] =
kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i + k].pbn;
bpp_increased[i] = false; bpp_increased[i] = false;
remaining_to_increase += 1; remaining_to_increase += 1;
} else { } else {
...@@ -629,7 +632,7 @@ static void increase_dsc_bpp(struct drm_atomic_state *state, ...@@ -629,7 +632,7 @@ static void increase_dsc_bpp(struct drm_atomic_state *state,
link_timeslots_used = 0; link_timeslots_used = 0;
for (i = 0; i < count; i++) 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; 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, ...@@ -682,7 +685,8 @@ static void try_disable_dsc(struct drm_atomic_state *state,
struct dc_link *dc_link, struct dc_link *dc_link,
struct dsc_mst_fairness_params *params, struct dsc_mst_fairness_params *params,
struct dsc_mst_fairness_vars *vars, struct dsc_mst_fairness_vars *vars,
int count) int count,
int k)
{ {
int i; int i;
bool tried[MAX_PIPES]; bool tried[MAX_PIPES];
...@@ -692,8 +696,8 @@ static void try_disable_dsc(struct drm_atomic_state *state, ...@@ -692,8 +696,8 @@ static void try_disable_dsc(struct drm_atomic_state *state,
int remaining_to_try = 0; int remaining_to_try = 0;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (vars[i].dsc_enabled if (vars[i + k].dsc_enabled
&& vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16 && vars[i + k].bpp_x16 == params[i].bw_range.max_target_bpp_x16
&& params[i].clock_force_enable == DSC_CLK_FORCE_DEFAULT) { && params[i].clock_force_enable == DSC_CLK_FORCE_DEFAULT) {
kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps; kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps;
tried[i] = false; tried[i] = false;
...@@ -748,9 +752,10 @@ static void try_disable_dsc(struct drm_atomic_state *state, ...@@ -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, static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
struct dc_state *dc_state, struct dc_state *dc_state,
struct dc_link *dc_link, 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 dc_stream_state *stream;
struct dsc_mst_fairness_params params[MAX_PIPES]; struct dsc_mst_fairness_params params[MAX_PIPES];
struct amdgpu_dm_connector *aconnector; struct amdgpu_dm_connector *aconnector;
...@@ -768,11 +773,17 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, ...@@ -768,11 +773,17 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
if (stream->link != dc_link) if (stream->link != dc_link)
continue; continue;
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
if (!aconnector)
continue;
if (!aconnector->port)
continue;
stream->timing.flags.DSC = 0; stream->timing.flags.DSC = 0;
params[count].timing = &stream->timing; params[count].timing = &stream->timing;
params[count].sink = stream->sink; params[count].sink = stream->sink;
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
params[count].aconnector = aconnector; params[count].aconnector = aconnector;
params[count].port = aconnector->port; params[count].port = aconnector->port;
params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable; 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, ...@@ -794,44 +805,55 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
count++; 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 */ /* Try no compression */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
vars[i].aconnector = params[i].aconnector; vars[i + k].aconnector = params[i].aconnector;
vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
vars[i].dsc_enabled = false; vars[i + k].dsc_enabled = false;
vars[i].bpp_x16 = 0; vars[i + k].bpp_x16 = 0;
if (drm_dp_atomic_find_vcpi_slots(state, if (drm_dp_atomic_find_vcpi_slots(state,
params[i].port->mgr, params[i].port->mgr,
params[i].port, params[i].port,
vars[i].pbn, vars[i + k].pbn,
dm_mst_get_pbn_divider(dc_link)) < 0) dm_mst_get_pbn_divider(dc_link)) < 0)
return false; return false;
} }
if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) { 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; return true;
} }
/* Try max compression */ /* Try max compression */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) { 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 + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
vars[i].dsc_enabled = true; vars[i + k].dsc_enabled = true;
vars[i].bpp_x16 = params[i].bw_range.min_target_bpp_x16; vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
if (drm_dp_atomic_find_vcpi_slots(state, if (drm_dp_atomic_find_vcpi_slots(state,
params[i].port->mgr, params[i].port->mgr,
params[i].port, params[i].port,
vars[i].pbn, vars[i + k].pbn,
dm_mst_get_pbn_divider(dc_link)) < 0) dm_mst_get_pbn_divider(dc_link)) < 0)
return false; return false;
} else { } else {
vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
vars[i].dsc_enabled = false; vars[i + k].dsc_enabled = false;
vars[i].bpp_x16 = 0; vars[i + k].bpp_x16 = 0;
if (drm_dp_atomic_find_vcpi_slots(state, if (drm_dp_atomic_find_vcpi_slots(state,
params[i].port->mgr, params[i].port->mgr,
params[i].port, params[i].port,
vars[i].pbn, vars[i + k].pbn,
dm_mst_get_pbn_divider(dc_link)) < 0) dm_mst_get_pbn_divider(dc_link)) < 0)
return false; return false;
} }
...@@ -840,15 +862,76 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, ...@@ -840,15 +862,76 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
return false; return false;
/* Optimize degree of compression */ /* 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; 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, bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
struct dc_state *dc_state, struct dc_state *dc_state,
struct dsc_mst_fairness_vars *vars) struct dsc_mst_fairness_vars *vars)
...@@ -857,6 +940,7 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, ...@@ -857,6 +940,7 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
struct dc_stream_state *stream; struct dc_stream_state *stream;
bool computed_streams[MAX_PIPES]; bool computed_streams[MAX_PIPES];
struct amdgpu_dm_connector *aconnector; struct amdgpu_dm_connector *aconnector;
int link_vars_start_index = 0;
for (i = 0; i < dc_state->stream_count; i++) for (i = 0; i < dc_state->stream_count; i++)
computed_streams[i] = false; computed_streams[i] = false;
...@@ -881,8 +965,12 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, ...@@ -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) if (dcn20_remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK)
return false; return false;
if (!is_dsc_need_re_compute(state, dc_state, stream->link))
continue;
mutex_lock(&aconnector->mst_mgr.lock); 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); mutex_unlock(&aconnector->mst_mgr.lock);
return false; return false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment