summary refs log tree commit diff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-11-16 12:39:40 +1000
committerDave Airlie <airlied@redhat.com>2017-11-16 12:39:40 +1000
commit49e37ba07a3ae697086c0a1a32c113a1f177d138 (patch)
tree492fc0db4fc5d7b417cb9e6a39580bce0ccbc33a
parent4479ed411cf41b42b1c548f73099287fff2330ff (diff)
parent00f713c6dc657397ba37b42d7f6887f526c730c6 (diff)
downloadlinux-49e37ba07a3ae697086c0a1a32c113a1f177d138.tar.gz
Merge branch 'drm-next-4.15-dc' of git://people.freedesktop.org/~agd5f/linux into drm-next
Various fixes for DC for 4.15.

* 'drm-next-4.15-dc' of git://people.freedesktop.org/~agd5f/linux:
  drm/amd/display: fix MST link training fail division by 0
  drm/amd/display: Fix formatting for null pointer dereference fix
  drm/amd/display: Remove dangling planes on dc commit state
  drm/amd/display: add flip_immediate to commit update for stream
  drm/amd/display: Miss register MST encoder cbs
  drm/amd/display: Fix warnings on S3 resume
  drm/amd/display: use num_timing_generator instead of pipe_count
  drm/amd/display: use configurable FBC option in dm
  drm/amd/display: fix AZ clock not enabled before program AZ endpoint
  amdgpu/dm: Don't use DRM_ERROR in amdgpu_dm_atomic_check
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c44
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c12
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c42
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_audio.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c2
8 files changed, 122 insertions, 21 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 8ed6767b4616..889ed24084e8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -344,7 +344,7 @@ static void hotplug_notify_work_func(struct work_struct *work)
 	drm_kms_helper_hotplug_event(dev);
 }
 
-#ifdef ENABLE_FBC
+#if defined(CONFIG_DRM_AMD_DC_FBC)
 #include "dal_asic_id.h"
 /* Allocate memory for FBC compressed data  */
 /* TODO: Dynamic allocation */
@@ -422,7 +422,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 	else
 		init_data.log_mask = DC_MIN_LOG_MASK;
 
-#ifdef ENABLE_FBC
+#if defined(CONFIG_DRM_AMD_DC_FBC)
 	if (adev->family == FAMILY_CZ)
 		amdgpu_dm_initialize_fbc(adev);
 	init_data.fbc_gpu_addr = adev->dm.compressor.gpu_addr;
@@ -643,6 +643,11 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)
 	struct drm_connector *connector;
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *new_crtc_state;
+	struct dm_crtc_state *dm_new_crtc_state;
+	struct drm_plane *plane;
+	struct drm_plane_state *new_plane_state;
+	struct dm_plane_state *dm_new_plane_state;
+
 	int ret = 0;
 	int i;
 
@@ -681,6 +686,29 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)
 	for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i)
 		new_crtc_state->active_changed = true;
 
+	/*
+	 * atomic_check is expected to create the dc states. We need to release
+	 * them here, since they were duplicated as part of the suspend
+	 * procedure.
+	 */
+	for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i) {
+		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+		if (dm_new_crtc_state->stream) {
+			WARN_ON(kref_read(&dm_new_crtc_state->stream->refcount) > 1);
+			dc_stream_release(dm_new_crtc_state->stream);
+			dm_new_crtc_state->stream = NULL;
+		}
+	}
+
+	for_each_new_plane_in_state(adev->dm.cached_state, plane, new_plane_state, i) {
+		dm_new_plane_state = to_dm_plane_state(new_plane_state);
+		if (dm_new_plane_state->dc_state) {
+			WARN_ON(kref_read(&dm_new_plane_state->dc_state->refcount) > 1);
+			dc_plane_state_release(dm_new_plane_state->dc_state);
+			dm_new_plane_state->dc_state = NULL;
+		}
+	}
+
 	ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state);
 
 	drm_atomic_state_put(adev->dm.cached_state);
@@ -4662,10 +4690,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 	bool lock_and_validation_needed = false;
 
 	ret = drm_atomic_helper_check_modeset(dev, state);
-	if (ret) {
-		DRM_ERROR("Atomic state validation failed with error :%d !\n", ret);
-		return ret;
-	}
+	if (ret)
+		goto fail;
 
 	/*
 	 * legacy_cursor_update should be made false for SoC's having
@@ -4782,11 +4808,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 
 fail:
 	if (ret == -EDEADLK)
-		DRM_DEBUG_DRIVER("Atomic check stopped due to to deadlock.\n");
+		DRM_DEBUG_DRIVER("Atomic check stopped to avoid deadlock.\n");
 	else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
-		DRM_DEBUG_DRIVER("Atomic check stopped due to to signal.\n");
+		DRM_DEBUG_DRIVER("Atomic check stopped due to signal.\n");
 	else
-		DRM_ERROR("Atomic check failed with err: %d \n", ret);
+		DRM_DEBUG_DRIVER("Atomic check failed with err: %d \n", ret);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index f42f8357b676..117521c6a6ed 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -72,7 +72,7 @@ struct irq_list_head {
 	struct work_struct work;
 };
 
-#ifdef ENABLE_FBC
+#if defined(CONFIG_DRM_AMD_DC_FBC)
 struct dm_comressor_info {
 	void *cpu_addr;
 	struct amdgpu_bo *bo_ptr;
@@ -142,7 +142,7 @@ struct amdgpu_display_manager {
 	 * Caches device atomic state for suspend/resume
 	 */
 	struct drm_atomic_state *cached_state;
-#ifdef ENABLE_FBC
+#if defined(CONFIG_DRM_AMD_DC_FBC)
 	struct dm_comressor_info compressor;
 #endif
 };
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 3b05da7a90e8..f8efb98b1fa7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -245,6 +245,16 @@ static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs
 	.best_encoder = dm_mst_best_encoder,
 };
 
+static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+	kfree(encoder);
+}
+
+static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
+	.destroy = amdgpu_dm_encoder_destroy,
+};
+
 static struct amdgpu_encoder *
 dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector)
 {
@@ -268,7 +278,7 @@ dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector)
 	drm_encoder_init(
 		dev,
 		&amdgpu_encoder->base,
-		NULL,
+		&amdgpu_dm_encoder_funcs,
 		DRM_MODE_ENCODER_DPMST,
 		NULL);
 
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index ce3c57b38bc0..fe63f5894d43 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -619,6 +619,39 @@ fail:
 	return false;
 }
 
+static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
+{
+	int i, j;
+	struct dc_state *dangling_context = dc_create_state();
+	struct dc_state *current_ctx;
+
+	if (dangling_context == NULL)
+		return;
+
+	dc_resource_state_copy_construct(dc->current_state, dangling_context);
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		struct dc_stream_state *old_stream =
+				dc->current_state->res_ctx.pipe_ctx[i].stream;
+		bool should_disable = true;
+
+		for (j = 0; j < context->stream_count; j++) {
+			if (old_stream == context->streams[j]) {
+				should_disable = false;
+				break;
+			}
+		}
+		if (should_disable && old_stream) {
+			dc_rem_all_planes_for_stream(dc, old_stream, dangling_context);
+			dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context);
+		}
+	}
+
+	current_ctx = dc->current_state;
+	dc->current_state = dangling_context;
+	dc_release_state(current_ctx);
+}
+
 /*******************************************************************************
  * Public functions
  ******************************************************************************/
@@ -801,6 +834,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 	int i, j, k, l;
 	struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
 
+	disable_dangling_plane(dc, context);
+
 	for (i = 0; i < context->stream_count; i++)
 		dc_streams[i] =  context->streams[i];
 
@@ -830,8 +865,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 			}
 		}
 
-
-
 		CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
 				context->streams[i]->timing.h_addressable,
 				context->streams[i]->timing.v_addressable,
@@ -1414,8 +1447,11 @@ void dc_commit_updates_for_stream(struct dc *dc,
 		/* TODO: On flip we don't build the state, so it still has the
 		 * old address. Which is why we are updating the address here
 		 */
-		if (srf_updates[i].flip_addr)
+		if (srf_updates[i].flip_addr) {
 			surface->address = srf_updates[i].flip_addr->address;
+			surface->flip_immediate = srf_updates[i].flip_addr->flip_immediate;
+
+		}
 
 		if (update_type >= UPDATE_TYPE_MED) {
 			for (j = 0; j < dc->res_pool->pipe_count; j++) {
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index e70612eaf257..0602610489d7 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -2318,9 +2318,11 @@ void core_link_enable_stream(
 
 			/* Abort stream enable *unless* the failure was due to
 			 * DP link training - some DP monitors will recover and
-			 * show the stream anyway.
+			 * show the stream anyway. But MST displays can't proceed
+			 * without link training.
 			 */
-			if (status != DC_FAIL_DP_LINK_TRAINING) {
+			if (status != DC_FAIL_DP_LINK_TRAINING ||
+					pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
 				BREAK_TO_DEBUGGER();
 				return;
 			}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index de04b95e103a..b00a6040a697 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -288,7 +288,7 @@ bool dc_stream_set_cursor_position(
 			pos_cpy.enable = false;
 
 
-		if (ipp !=NULL && ipp->funcs->ipp_cursor_set_position != NULL)
+		if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL)
 			ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
 
 		if (mi != NULL && mi->funcs->set_cursor_position != NULL)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c
index d882adf746a5..81c40f8864db 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c
@@ -348,29 +348,44 @@ static void set_audio_latency(
 
 void dce_aud_az_enable(struct audio *audio)
 {
+	struct dce_audio *aud = DCE_AUD(audio);
 	uint32_t value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
 
-	if (get_reg_field_value(value,
+	set_reg_field_value(value, 1,
 			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
-			AUDIO_ENABLED) != 1)
+			CLOCK_GATING_DISABLE);
 		set_reg_field_value(value, 1,
 			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
 			AUDIO_ENABLED);
 
 	AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
+	value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
+
+	dm_logger_write(CTX->logger, LOG_HW_AUDIO,
+			"\n\t========= AUDIO:dce_aud_az_enable: index: %u  data: 0x%x\n",
+			audio->inst, value);
 }
 
 void dce_aud_az_disable(struct audio *audio)
 {
 	uint32_t value;
+	struct dce_audio *aud = DCE_AUD(audio);
 
 	value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
 
 	set_reg_field_value(value, 0,
 		AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
 		AUDIO_ENABLED);
+	AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
 
+	set_reg_field_value(value, 0,
+			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+			CLOCK_GATING_DISABLE);
 	AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
+	value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
+	dm_logger_write(CTX->logger, LOG_HW_AUDIO,
+			"\n\t========= AUDIO:dce_aud_az_disable: index: %u  data: 0x%x\n",
+			audio->inst, value);
 }
 
 void dce_aud_az_configure(
@@ -390,6 +405,11 @@ void dce_aud_az_configure(
 	bool is_ac3_supported = false;
 	union audio_sample_rates sample_rate;
 	uint32_t strlen = 0;
+	value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
+	set_reg_field_value(value, 1,
+			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+			CLOCK_GATING_DISABLE);
+	AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
 
 	/* Speaker Allocation */
 	/*
@@ -852,6 +872,7 @@ static bool dce_aud_endpoint_valid(struct audio *audio)
 void dce_aud_hw_init(
 		struct audio *audio)
 {
+	uint32_t value;
 	struct dce_audio *aud = DCE_AUD(audio);
 
 	/* we only need to program the following registers once, so we only do
@@ -863,6 +884,12 @@ void dce_aud_hw_init(
 	 * Suport R6 - 44.1khz
 	 * Suport R7 - 48khz
 	 */
+	/*disable clock gating before write to endpoint register*/
+	value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
+	set_reg_field_value(value, 1,
+			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+			CLOCK_GATING_DISABLE);
+	AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
 	REG_UPDATE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
 			AUDIO_RATE_CAPABILITIES, 0x70);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 63c2f5266142..961ad5c3b454 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -202,7 +202,7 @@ static void dcn10_log_hw_state(struct dc *dc)
 	DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t "
 			"h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n");
 
-	for (i = 0; i < pool->pipe_count; i++) {
+	for (i = 0; i < pool->res_cap->num_timing_generator; i++) {
 		struct timing_generator *tg = pool->timing_generators[i];
 		struct dcn_otg_state s = {0};