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

drm/amd/display: bandwidth update fix

parent 45209ef7
Loading
Loading
Loading
Loading
+2 −171
Original line number Diff line number Diff line
@@ -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;
+5 −10
Original line number Diff line number Diff line
@@ -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;
+163 −116
Original line number Diff line number Diff line
@@ -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)
{
	if (did_watermarks_increase(pipe_ctx, context, dc->current_context))
		program_wm_for_pipe(dc, pipe_ctx, context);
	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;
			}

static void dce110_set_bandwidth(struct core_dc *dc)
		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;

	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);

	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;

		program_wm_for_pipe(dc, pipe_ctx, dc->current_context);
	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;
	}

	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);
	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;
	}

	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,
+5 −11
Original line number Diff line number Diff line
@@ -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;
+4 −5
Original line number Diff line number Diff line
@@ -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);