Commit e779f458 authored by Joshua Aberback's avatar Joshua Aberback Committed by Alex Deucher
Browse files

drm/amd/display: Add handling for DC power mode



[Why]
Future implementations will require a distinction between AC power and
DC power (wall power and battery power, respectively). To accomplish this,
adding a power mode parameter to certain dc interfaces, and adding a
separate DML2 instance for DC mode validation. Default behaviour unchanged.

Reviewed-by: default avatarJun Lei <jun.lei@amd.com>
Reviewed-by: default avatarAric Cyr <aric.cyr@amd.com>
Acked-by: default avatarRoman Li <roman.li@amd.com>
Signed-off-by: default avatarJoshua Aberback <joshua.aberback@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent cc263c3a
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -2629,6 +2629,7 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
	int i;
	struct dc_stream_state *del_streams[MAX_PIPES];
	int del_streams_count = 0;
	struct dc_commit_streams_params params = {};

	memset(del_streams, 0, sizeof(del_streams));

@@ -2655,7 +2656,9 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
			goto fail;
	}

	res = dc_commit_streams(dc, context->streams, context->stream_count);
	params.streams = context->streams;
	params.stream_count = context->stream_count;
	res = dc_commit_streams(dc, &params);

fail:
	dc_state_release(context);
@@ -2877,6 +2880,7 @@ static int dm_resume(void *handle)
	struct dc_state *dc_state;
	int i, r, j, ret;
	bool need_hotplug = false;
	struct dc_commit_streams_params commit_params = {};

	if (dm->dc->caps.ips_support) {
		dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false);
@@ -2926,7 +2930,9 @@ static int dm_resume(void *handle)
			dc_enable_dmub_outbox(adev->dm.dc);
		}

		WARN_ON(!dc_commit_streams(dm->dc, dc_state->streams, dc_state->stream_count));
		commit_params.streams = dc_state->streams;
		commit_params.stream_count = dc_state->stream_count;
		WARN_ON(!dc_commit_streams(dm->dc, &commit_params));

		dm_gpureset_commit_state(dm->cached_dc_state, dm);

@@ -2943,7 +2949,7 @@ static int dm_resume(void *handle)
	}
	/* Recreate dc_state - DC invalidates it when setting power state to S3. */
	dc_state_release(dm_state->context);
	dm_state->context = dc_state_create(dm->dc);
	dm_state->context = dc_state_create(dm->dc, NULL);
	/* TODO: Remove dc_state->dccg, use dc->dccg directly. */

	/* Before powering on DC we need to re-initialize DMUB. */
@@ -6802,7 +6808,7 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc,
	if (!dc_plane_state)
		goto cleanup;

	dc_state = dc_state_create(dc);
	dc_state = dc_state_create(dc, NULL);
	if (!dc_state)
		goto cleanup;

@@ -8857,6 +8863,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
	struct drm_connector *connector;
	bool mode_set_reset_required = false;
	u32 i;
	struct dc_commit_streams_params params = {dc_state->streams, dc_state->stream_count};

	/* Disable writeback */
	for_each_old_connector_in_state(state, connector, old_con_state, i) {
@@ -8993,7 +9000,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,

	dm_enable_per_frame_crtc_master_sync(dc_state);
	mutex_lock(&dm->dc_lock);
	WARN_ON(!dc_commit_streams(dm->dc, dc_state->streams, dc_state->stream_count));
	WARN_ON(!dc_commit_streams(dm->dc, &params));

	/* Allow idle optimization when vblank count is 0 for display off */
	if (dm->active_vblank_irq_count == 0)
+20 −17
Original line number Diff line number Diff line
@@ -1089,8 +1089,7 @@ static bool dc_construct(struct dc *dc,
	 * is initialized in dc_create_resource_pool because
	 * on creation it copies the contents of dc->dml
	 */

	dc->current_state = dc_state_create(dc);
	dc->current_state = dc_state_create(dc, NULL);

	if (!dc->current_state) {
		dm_error("%s: failed to create validate ctx\n", __func__);
@@ -2135,9 +2134,7 @@ static bool commit_minimal_transition_state(struct dc *dc,
 * Return DC_OK if everything work as expected, otherwise, return a dc_status
 * code.
 */
enum dc_status dc_commit_streams(struct dc *dc,
				 struct dc_stream_state *streams[],
				 uint8_t stream_count)
enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params *params)
{
	int i, j;
	struct dc_state *context;
@@ -2146,18 +2143,22 @@ enum dc_status dc_commit_streams(struct dc *dc,
	struct pipe_ctx *pipe;
	bool handle_exit_odm2to1 = false;

	if (!params)
		return DC_ERROR_UNEXPECTED;

	if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW)
		return res;

	if (!streams_changed(dc, streams, stream_count))
	if (!streams_changed(dc, params->streams, params->stream_count) &&
			dc->current_state->power_source == params->power_source)
		return res;

	dc_exit_ips_for_hw_access(dc);

	DC_LOG_DC("%s: %d streams\n", __func__, stream_count);
	DC_LOG_DC("%s: %d streams\n", __func__, params->stream_count);

	for (i = 0; i < stream_count; i++) {
		struct dc_stream_state *stream = streams[i];
	for (i = 0; i < params->stream_count; i++) {
		struct dc_stream_state *stream = params->streams[i];
		struct dc_stream_status *status = dc_stream_get_status(stream);

		dc_stream_log(dc, stream);
@@ -2175,7 +2176,7 @@ enum dc_status dc_commit_streams(struct dc *dc,
	 * scenario, it uses extra pipes than needed to reduce power consumption
	 * We need to switch off this feature to make room for new streams.
	 */
	if (stream_count > dc->current_state->stream_count &&
	if (params->stream_count > dc->current_state->stream_count &&
			dc->current_state->stream_count == 1) {
		for (i = 0; i < dc->res_pool->pipe_count; i++) {
			pipe = &dc->current_state->res_ctx.pipe_ctx[i];
@@ -2191,7 +2192,9 @@ enum dc_status dc_commit_streams(struct dc *dc,
	if (!context)
		goto context_alloc_fail;

	res = dc_validate_with_context(dc, set, stream_count, context, false);
	context->power_source = params->power_source;

	res = dc_validate_with_context(dc, set, params->stream_count, context, false);
	if (res != DC_OK) {
		BREAK_TO_DEBUGGER();
		goto fail;
@@ -2199,16 +2202,16 @@ enum dc_status dc_commit_streams(struct dc *dc,

	res = dc_commit_state_no_check(dc, context);

	for (i = 0; i < stream_count; i++) {
	for (i = 0; i < params->stream_count; i++) {
		for (j = 0; j < context->stream_count; j++) {
			if (streams[i]->stream_id == context->streams[j]->stream_id)
				streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst;
			if (params->streams[i]->stream_id == context->streams[j]->stream_id)
				params->streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst;

			if (dc_is_embedded_signal(streams[i]->signal)) {
				struct dc_stream_status *status = dc_state_get_stream_status(context, streams[i]);
			if (dc_is_embedded_signal(params->streams[i]->signal)) {
				struct dc_stream_status *status = dc_state_get_stream_status(context, params->streams[i]);

				if (dc->hwss.is_abm_supported)
					status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, streams[i]);
					status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, params->streams[i]);
				else
					status->is_abm_supported = true;
			}
+26 −3
Original line number Diff line number Diff line
@@ -188,8 +188,11 @@ static void init_state(struct dc *dc, struct dc_state *state)
}

/* Public dc_state functions */
struct dc_state *dc_state_create(struct dc *dc)
struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params)
{
#ifdef CONFIG_DRM_AMD_DC_FP
	struct dml2_configuration_options dml2_opt = dc->dml2_options;
#endif
	struct dc_state *state = kvzalloc(sizeof(struct dc_state),
			GFP_KERNEL);

@@ -198,10 +201,16 @@ struct dc_state *dc_state_create(struct dc *dc)

	init_state(dc, state);
	dc_state_construct(dc, state);
	state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC;

#ifdef CONFIG_DRM_AMD_DC_FP
	if (dc->debug.using_dml2)
		dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2);
	if (dc->debug.using_dml2) {
		dml2_opt.use_clock_dc_limits = false;
		dml2_create(dc, &dml2_opt, &state->bw_ctx.dml2);

		dml2_opt.use_clock_dc_limits = true;
		dml2_create(dc, &dml2_opt, &state->bw_ctx.dml2_dc_power_source);
	}
#endif

	kref_init(&state->refcount);
@@ -214,6 +223,7 @@ void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
	struct kref refcount = dst_state->refcount;
#ifdef CONFIG_DRM_AMD_DC_FP
	struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2;
	struct dml2_context *dst_dml2_dc_power_source = dst_state->bw_ctx.dml2_dc_power_source;
#endif

	dc_state_copy_internal(dst_state, src_state);
@@ -222,6 +232,10 @@ void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
	dst_state->bw_ctx.dml2 = dst_dml2;
	if (src_state->bw_ctx.dml2)
		dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2);

	dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source;
	if (src_state->bw_ctx.dml2_dc_power_source)
		dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
#endif

	/* context refcount should not be overridden */
@@ -245,6 +259,12 @@ struct dc_state *dc_state_create_copy(struct dc_state *src_state)
		dc_state_release(new_state);
		return NULL;
	}

	if (src_state->bw_ctx.dml2_dc_power_source &&
			!dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
		dc_state_release(new_state);
		return NULL;
	}
#endif

	kref_init(&new_state->refcount);
@@ -326,6 +346,9 @@ static void dc_state_free(struct kref *kref)
#ifdef CONFIG_DRM_AMD_DC_FP
	dml2_destroy(state->bw_ctx.dml2);
	state->bw_ctx.dml2 = 0;

	dml2_destroy(state->bw_ctx.dml2_dc_power_source);
	state->bw_ctx.dml2_dc_power_source = 0;
#endif

	kvfree(state);
+9 −4
Original line number Diff line number Diff line
@@ -1504,10 +1504,15 @@ bool dc_acquire_release_mpc_3dlut(
bool dc_resource_is_dsc_encoding_supported(const struct dc *dc);
void get_audio_check(struct audio_info *aud_modes,
	struct audio_check *aud_chk);

enum dc_status dc_commit_streams(struct dc *dc,
				 struct dc_stream_state *streams[],
				 uint8_t stream_count);
/*
 * Set up streams and links associated to drive sinks
 * The streams parameter is an absolute set of all active streams.
 *
 * After this call:
 *   Phy, Encoder, Timing Generator are programmed and enabled.
 *   New streams are enabled with blank stream; no memory read.
 */
enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params *params);


struct dc_plane_state *dc_get_surface_for_mpcc(struct dc *dc,
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@
#include "dc.h"
#include "inc/core_status.h"

struct dc_state *dc_state_create(struct dc *dc);
struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params);
void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state);
struct dc_state *dc_state_create_copy(struct dc_state *src_state);
void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state);
Loading