Commit cf437593 authored by Dmytro Laktyushkin's avatar Dmytro Laktyushkin Committed by Alex Deucher

drm/amd/display: bandwidth update fix

Signed-off-by: default avatarDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 45209ef7
......@@ -795,159 +795,6 @@ static bool streams_changed(
return false;
}
static void fill_display_configs(
const struct validate_context *context,
struct dm_pp_display_configuration *pp_display_cfg)
{
int j;
int num_cfgs = 0;
for (j = 0; j < context->stream_count; j++) {
int k;
const struct core_stream *stream = context->streams[j];
struct dm_pp_single_disp_config *cfg =
&pp_display_cfg->disp_configs[num_cfgs];
const struct pipe_ctx *pipe_ctx = NULL;
for (k = 0; k < MAX_PIPES; k++)
if (stream == context->res_ctx.pipe_ctx[k].stream) {
pipe_ctx = &context->res_ctx.pipe_ctx[k];
break;
}
ASSERT(pipe_ctx != NULL);
num_cfgs++;
cfg->signal = pipe_ctx->stream->signal;
cfg->pipe_idx = pipe_ctx->pipe_idx;
cfg->src_height = stream->public.src.height;
cfg->src_width = stream->public.src.width;
cfg->ddi_channel_mapping =
stream->sink->link->ddi_channel_mapping.raw;
cfg->transmitter =
stream->sink->link->link_enc->transmitter;
cfg->link_settings.lane_count =
stream->sink->link->public.cur_link_settings.lane_count;
cfg->link_settings.link_rate =
stream->sink->link->public.cur_link_settings.link_rate;
cfg->link_settings.link_spread =
stream->sink->link->public.cur_link_settings.link_spread;
cfg->sym_clock = stream->phy_pix_clk;
/* Round v_refresh*/
cfg->v_refresh = stream->public.timing.pix_clk_khz * 1000;
cfg->v_refresh /= stream->public.timing.h_total;
cfg->v_refresh = (cfg->v_refresh + stream->public.timing.v_total / 2)
/ stream->public.timing.v_total;
}
pp_display_cfg->display_count = num_cfgs;
}
static uint32_t get_min_vblank_time_us(const struct validate_context *context)
{
uint8_t j;
uint32_t min_vertical_blank_time = -1;
for (j = 0; j < context->stream_count; j++) {
const struct dc_stream *stream = &context->streams[j]->public;
uint32_t vertical_blank_in_pixels = 0;
uint32_t vertical_blank_time = 0;
vertical_blank_in_pixels = stream->timing.h_total *
(stream->timing.v_total
- stream->timing.v_addressable);
vertical_blank_time = vertical_blank_in_pixels
* 1000 / stream->timing.pix_clk_khz;
if (min_vertical_blank_time > vertical_blank_time)
min_vertical_blank_time = vertical_blank_time;
}
return min_vertical_blank_time;
}
static int determine_sclk_from_bounding_box(
const struct core_dc *dc,
int required_sclk)
{
int i;
/*
* Some asics do not give us sclk levels, so we just report the actual
* required sclk
*/
if (dc->sclk_lvls.num_levels == 0)
return required_sclk;
for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
return dc->sclk_lvls.clocks_in_khz[i];
}
/*
* even maximum level could not satisfy requirement, this
* is unexpected at this stage, should have been caught at
* validation time
*/
ASSERT(0);
return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
}
void pplib_apply_display_requirements(
struct core_dc *dc,
const struct validate_context *context,
struct dm_pp_display_configuration *pp_display_cfg)
{
pp_display_cfg->all_displays_in_sync =
context->bw_results.all_displays_in_sync;
pp_display_cfg->nb_pstate_switch_disable =
context->bw_results.nbp_state_change_enable == false;
pp_display_cfg->cpu_cc6_disable =
context->bw_results.cpuc_state_change_enable == false;
pp_display_cfg->cpu_pstate_disable =
context->bw_results.cpup_state_change_enable == false;
pp_display_cfg->cpu_pstate_separation_time =
context->bw_results.blackout_recovery_time_us;
pp_display_cfg->min_memory_clock_khz = context->bw_results.required_yclk
/ MEMORY_TYPE_MULTIPLIER;
pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
dc,
context->bw_results.required_sclk);
pp_display_cfg->min_engine_clock_deep_sleep_khz
= context->bw_results.required_sclk_deep_sleep;
pp_display_cfg->avail_mclk_switch_time_us =
get_min_vblank_time_us(context);
/* TODO: dce11.2*/
pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
pp_display_cfg->disp_clk_khz = context->dispclk_khz;
fill_display_configs(context, pp_display_cfg);
/* TODO: is this still applicable?*/
if (pp_display_cfg->display_count == 1) {
const struct dc_crtc_timing *timing =
&context->streams[0]->public.timing;
pp_display_cfg->crtc_index =
pp_display_cfg->disp_configs[0].pipe_idx;
pp_display_cfg->line_time_in_us = timing->h_total * 1000
/ timing->pix_clk_khz;
}
if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
struct dm_pp_display_configuration)) != 0)
dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
dc->prev_display_config = *pp_display_cfg;
}
bool dc_commit_streams(
struct dc *dc,
const struct dc_stream *streams[],
......@@ -1036,9 +883,6 @@ bool dc_commit_streams(
context->streams[i]->public.timing.pix_clk_khz);
}
pplib_apply_display_requirements(core_dc,
context, &context->pp_display_cfg);
resource_validate_ctx_destruct(core_dc->current_context);
if (core_dc->temp_flip_context != core_dc->current_context) {
......@@ -1065,7 +909,6 @@ bool dc_pre_update_surfaces_to_stream(
{
int i, j;
struct core_dc *core_dc = DC_TO_CORE(dc);
int prev_disp_clk = core_dc->current_context->dispclk_khz;
struct dc_stream_status *stream_status = NULL;
struct validate_context *context;
bool ret = true;
......@@ -1150,16 +993,7 @@ bool dc_pre_update_surfaces_to_stream(
goto unexpected_fail;
}
if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)
&& prev_disp_clk < context->dispclk_khz) {
pplib_apply_display_requirements(core_dc, context,
&context->pp_display_cfg);
context->res_ctx.pool->display_clock->funcs->set_clock(
context->res_ctx.pool->display_clock,
context->dispclk_khz * 115 / 100);
core_dc->current_context->bw_results.dispclk_khz = context->dispclk_khz;
core_dc->current_context->dispclk_khz = context->dispclk_khz;
}
core_dc->hwss.set_bandwidth(core_dc, context, false);
for (i = 0; i < new_surface_count; i++)
for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
......@@ -1206,10 +1040,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
return false;
}
core_dc->hwss.set_bandwidth(core_dc);
/*TODO: dce specific*/
pplib_apply_display_requirements(core_dc, context, &context->pp_display_cfg);
core_dc->hwss.set_bandwidth(core_dc, context, true);
resource_validate_ctx_destruct(core_dc->current_context);
core_dc->current_context = context;
......
......@@ -104,22 +104,18 @@ static bool dce100_enable_display_power_gating(
return false;
}
static void set_display_mark_for_pipe_if_needed(struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
struct validate_context *context)
{
/* Do nothing until we have proper bandwitdth calcs */
}
static void set_displaymarks(
const struct core_dc *dc, struct validate_context *context)
{
/* Do nothing until we have proper bandwitdth calcs */
}
static void set_bandwidth(struct core_dc *dc)
static void set_bandwidth(
struct core_dc *dc,
struct validate_context *context,
bool decrease_allowed)
{
/* Do nothing until we have proper bandwitdth calcs */
dc->hwss.set_displaymarks(dc, context);
}
......@@ -132,7 +128,6 @@ bool dce100_hw_sequencer_construct(struct core_dc *dc)
/* TODO: dce80 is empty implementation at the moment*/
dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating;
dc->hwss.set_displaymarks = set_displaymarks;
dc->hwss.increase_watermarks_for_pipe = set_display_mark_for_pipe_if_needed;
dc->hwss.set_bandwidth = set_bandwidth;
return true;
......
......@@ -1209,93 +1209,6 @@ static uint32_t compute_pstate_blackout_duration(
return total_dest_line_time_ns;
}
/* get the index of the pipe_ctx if there were no gaps in the pipe_ctx array*/
int get_bw_result_idx(
struct resource_context *res_ctx,
int pipe_idx)
{
int i, collapsed_idx;
if (res_ctx->pipe_ctx[pipe_idx].top_pipe)
return 3;
collapsed_idx = 0;
for (i = 0; i < pipe_idx; i++) {
if (res_ctx->pipe_ctx[i].stream)
collapsed_idx++;
}
return collapsed_idx;
}
static bool is_watermark_set_a_greater(
const struct bw_watermarks *set_a,
const struct bw_watermarks *set_b)
{
if (set_a->a_mark > set_b->a_mark
|| set_a->b_mark > set_b->b_mark
|| set_a->c_mark > set_b->c_mark
|| set_a->d_mark > set_b->d_mark)
return true;
return false;
}
static bool did_watermarks_increase(
struct pipe_ctx *pipe_ctx,
struct validate_context *context,
struct validate_context *old_context)
{
int collapsed_pipe_idx = get_bw_result_idx(&context->res_ctx,
pipe_ctx->pipe_idx);
int old_collapsed_pipe_idx = get_bw_result_idx(&old_context->res_ctx,
pipe_ctx->pipe_idx);
struct pipe_ctx *old_pipe_ctx = &old_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
if (!old_pipe_ctx->stream)
return true;
if (is_watermark_set_a_greater(
&context->bw_results.nbp_state_change_wm_ns[collapsed_pipe_idx],
&old_context->bw_results.nbp_state_change_wm_ns[old_collapsed_pipe_idx]))
return true;
if (is_watermark_set_a_greater(
&context->bw_results.stutter_exit_wm_ns[collapsed_pipe_idx],
&old_context->bw_results.stutter_exit_wm_ns[old_collapsed_pipe_idx]))
return true;
if (is_watermark_set_a_greater(
&context->bw_results.urgent_wm_ns[collapsed_pipe_idx],
&old_context->bw_results.urgent_wm_ns[old_collapsed_pipe_idx]))
return true;
return false;
}
static void program_wm_for_pipe(struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
struct validate_context *context)
{
int total_dest_line_time_ns = compute_pstate_blackout_duration(
dc->bw_vbios.blackout_duration,
pipe_ctx->stream);
int bw_result_idx = get_bw_result_idx(&context->res_ctx,
pipe_ctx->pipe_idx);
pipe_ctx->mi->funcs->mem_input_program_display_marks(
pipe_ctx->mi,
context->bw_results.nbp_state_change_wm_ns[bw_result_idx],
context->bw_results.stutter_exit_wm_ns[bw_result_idx],
context->bw_results.urgent_wm_ns[bw_result_idx],
total_dest_line_time_ns);
if (pipe_ctx->top_pipe)
pipe_ctx->mi->funcs->mem_input_program_chroma_display_marks(
pipe_ctx->mi,
context->bw_results.nbp_state_change_wm_ns[bw_result_idx + 1],
context->bw_results.stutter_exit_wm_ns[bw_result_idx + 1],
context->bw_results.urgent_wm_ns[bw_result_idx + 1],
total_dest_line_time_ns);
}
void dce110_set_displaymarks(
const struct core_dc *dc,
struct validate_context *context)
......@@ -1589,7 +1502,7 @@ static void reset_hw_ctx_wrap(
}
}
/*TODO: const validate_context*/
enum dc_status dce110_apply_ctx_to_hw(
struct core_dc *dc,
struct validate_context *context)
......@@ -1768,7 +1681,7 @@ enum dc_status dce110_apply_ctx_to_hw(
return status;
}
dc->hwss.set_displaymarks(dc, context);
dc->hwss.set_bandwidth(dc, context, true);
/* to save power */
apply_min_clocks(dc, context, &clocks_state, false);
......@@ -1777,6 +1690,7 @@ enum dc_status dce110_apply_ctx_to_hw(
switch_dp_clock_sources(dc, &context->res_ctx);
return DC_OK;
}
......@@ -2135,7 +2049,6 @@ static void init_hw(struct core_dc *dc)
}
}
/* TODO: move this to apply_ctx_tohw some how?*/
static void dce110_power_on_pipe_if_needed(
struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
......@@ -2180,31 +2093,175 @@ static void dce110_power_on_pipe_if_needed(
}
}
static void dce110_increase_watermarks_for_pipe(
struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
struct validate_context *context)
static void fill_display_configs(
const struct validate_context *context,
struct dm_pp_display_configuration *pp_display_cfg)
{
int j;
int num_cfgs = 0;
for (j = 0; j < context->stream_count; j++) {
int k;
const struct core_stream *stream = context->streams[j];
struct dm_pp_single_disp_config *cfg =
&pp_display_cfg->disp_configs[num_cfgs];
const struct pipe_ctx *pipe_ctx = NULL;
for (k = 0; k < MAX_PIPES; k++)
if (stream == context->res_ctx.pipe_ctx[k].stream) {
pipe_ctx = &context->res_ctx.pipe_ctx[k];
break;
}
ASSERT(pipe_ctx != NULL);
num_cfgs++;
cfg->signal = pipe_ctx->stream->signal;
cfg->pipe_idx = pipe_ctx->pipe_idx;
cfg->src_height = stream->public.src.height;
cfg->src_width = stream->public.src.width;
cfg->ddi_channel_mapping =
stream->sink->link->ddi_channel_mapping.raw;
cfg->transmitter =
stream->sink->link->link_enc->transmitter;
cfg->link_settings.lane_count =
stream->sink->link->public.cur_link_settings.lane_count;
cfg->link_settings.link_rate =
stream->sink->link->public.cur_link_settings.link_rate;
cfg->link_settings.link_spread =
stream->sink->link->public.cur_link_settings.link_spread;
cfg->sym_clock = stream->phy_pix_clk;
/* Round v_refresh*/
cfg->v_refresh = stream->public.timing.pix_clk_khz * 1000;
cfg->v_refresh /= stream->public.timing.h_total;
cfg->v_refresh = (cfg->v_refresh + stream->public.timing.v_total / 2)
/ stream->public.timing.v_total;
}
pp_display_cfg->display_count = num_cfgs;
}
static uint32_t get_min_vblank_time_us(const struct validate_context *context)
{
if (did_watermarks_increase(pipe_ctx, context, dc->current_context))
program_wm_for_pipe(dc, pipe_ctx, context);
uint8_t j;
uint32_t min_vertical_blank_time = -1;
for (j = 0; j < context->stream_count; j++) {
const struct dc_stream *stream = &context->streams[j]->public;
uint32_t vertical_blank_in_pixels = 0;
uint32_t vertical_blank_time = 0;
vertical_blank_in_pixels = stream->timing.h_total *
(stream->timing.v_total
- stream->timing.v_addressable);
vertical_blank_time = vertical_blank_in_pixels
* 1000 / stream->timing.pix_clk_khz;
if (min_vertical_blank_time > vertical_blank_time)
min_vertical_blank_time = vertical_blank_time;
}
return min_vertical_blank_time;
}
static void dce110_set_bandwidth(struct core_dc *dc)
static int determine_sclk_from_bounding_box(
const struct core_dc *dc,
int required_sclk)
{
int i;
for (i = 0; i < dc->current_context->res_ctx.pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[i];
/*
* Some asics do not give us sclk levels, so we just report the actual
* required sclk
*/
if (dc->sclk_lvls.num_levels == 0)
return required_sclk;
if (!pipe_ctx->stream)
continue;
for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
return dc->sclk_lvls.clocks_in_khz[i];
}
/*
* even maximum level could not satisfy requirement, this
* is unexpected at this stage, should have been caught at
* validation time
*/
ASSERT(0);
return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
}
static void pplib_apply_display_requirements(
struct core_dc *dc,
struct validate_context *context)
{
struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
pp_display_cfg->all_displays_in_sync =
context->bw_results.all_displays_in_sync;
pp_display_cfg->nb_pstate_switch_disable =
context->bw_results.nbp_state_change_enable == false;
pp_display_cfg->cpu_cc6_disable =
context->bw_results.cpuc_state_change_enable == false;
pp_display_cfg->cpu_pstate_disable =
context->bw_results.cpup_state_change_enable == false;
pp_display_cfg->cpu_pstate_separation_time =
context->bw_results.blackout_recovery_time_us;
pp_display_cfg->min_memory_clock_khz = context->bw_results.required_yclk
/ MEMORY_TYPE_MULTIPLIER;
pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
dc,
context->bw_results.required_sclk);
program_wm_for_pipe(dc, pipe_ctx, dc->current_context);
pp_display_cfg->min_engine_clock_deep_sleep_khz
= context->bw_results.required_sclk_deep_sleep;
pp_display_cfg->avail_mclk_switch_time_us =
get_min_vblank_time_us(context);
/* TODO: dce11.2*/
pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
pp_display_cfg->disp_clk_khz = context->dispclk_khz;
fill_display_configs(context, pp_display_cfg);
/* TODO: is this still applicable?*/
if (pp_display_cfg->display_count == 1) {
const struct dc_crtc_timing *timing =
&context->streams[0]->public.timing;
pp_display_cfg->crtc_index =
pp_display_cfg->disp_configs[0].pipe_idx;
pp_display_cfg->line_time_in_us = timing->h_total * 1000
/ timing->pix_clk_khz;
}
if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
struct dm_pp_display_configuration)) != 0)
dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
dc->prev_display_config = *pp_display_cfg;
}
static void dce110_set_bandwidth(
struct core_dc *dc,
struct validate_context *context,
bool decrease_allowed)
{
dc->hwss.set_displaymarks(dc, context);
if (decrease_allowed || context->dispclk_khz > dc->current_context->dispclk_khz) {
context->res_ctx.pool->display_clock->funcs->set_clock(
context->res_ctx.pool->display_clock,
context->dispclk_khz * 115 / 100);
dc->current_context->bw_results.dispclk_khz = context->dispclk_khz;
dc->current_context->dispclk_khz = context->dispclk_khz;
}
dc->current_context->res_ctx.pool->display_clock->funcs->set_clock(
dc->current_context->res_ctx.pool->display_clock,
dc->current_context->dispclk_khz * 115 / 100);
pplib_apply_display_requirements(dc, context);
}
static void dce110_program_front_end_for_pipe(
......@@ -2335,15 +2392,6 @@ static void dce110_program_front_end_for_pipe(
pipe_ctx->scl_data.recout.y);
}
static void dce110_prepare_pipe_for_context(
struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
struct validate_context *context)
{
dce110_power_on_pipe_if_needed(dc, pipe_ctx, context);
dc->hwss.increase_watermarks_for_pipe(dc, pipe_ctx, context);
}
static void dce110_apply_ctx_for_surface(
struct core_dc *dc,
struct core_surface *surface,
......@@ -2388,7 +2436,7 @@ static void dce110_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
static const struct hw_sequencer_funcs dce110_funcs = {
.init_hw = init_hw,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.prepare_pipe_for_context = dce110_prepare_pipe_for_context,
.prepare_pipe_for_context = dce110_power_on_pipe_if_needed,
.apply_ctx_for_surface = dce110_apply_ctx_for_surface,
.set_plane_config = set_plane_config,
.update_plane_addr = update_plane_addr,
......@@ -2407,7 +2455,6 @@ static const struct hw_sequencer_funcs dce110_funcs = {
.power_down_front_end = dce110_power_down_fe,
.pipe_control_lock = dce_pipe_control_lock,
.set_displaymarks = dce110_set_displaymarks,
.increase_watermarks_for_pipe = dce110_increase_watermarks_for_pipe,
.set_bandwidth = dce110_set_bandwidth,
.set_drr = set_drr,
.set_static_screen_control = set_static_screen_control,
......
......@@ -106,23 +106,18 @@ static bool dce80_enable_display_power_gating(
return false;
}
static void set_display_mark_for_pipe_if_needed(struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
struct validate_context *context)
{
/* Do nothing until we have proper bandwitdth calcs */
}
static void set_displaymarks(
const struct core_dc *dc, struct validate_context *context)
{
/* Do nothing until we have proper bandwitdth calcs */
}
static void set_bandwidth(struct core_dc *dc)
static void set_bandwidth(
struct core_dc *dc,
struct validate_context *context,
bool decrease_allowed)
{
/* Do nothing until we have proper bandwitdth calcs */
dc->hwss.set_displaymarks(dc, context);
}
......@@ -133,7 +128,6 @@ bool dce80_hw_sequencer_construct(struct core_dc *dc)
dc->hwss.enable_display_power_gating = dce80_enable_display_power_gating;
dc->hwss.pipe_control_lock = dce_pipe_control_lock;
dc->hwss.set_displaymarks = set_displaymarks;
dc->hwss.increase_watermarks_for_pipe = set_display_mark_for_pipe_if_needed;
dc->hwss.set_bandwidth = set_bandwidth;
return true;
......
......@@ -124,11 +124,10 @@ struct hw_sequencer_funcs {
const struct core_dc *dc,
struct validate_context *context);
void (*increase_watermarks_for_pipe)(struct core_dc *dc,
struct pipe_ctx *pipe_ctx,
struct validate_context *context);
void (*set_bandwidth)(struct core_dc *dc);
void (*set_bandwidth)(
struct core_dc *dc,
struct validate_context *context,
bool decrease_allowed);
void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes,
int vmin, int vmax);
......
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