dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 4.15 0/4] Backport DC commits to fix display corruption
@ 2018-01-03 17:11 Carlo Caione
       [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Carlo Caione @ 2018-01-03 17:11 UTC (permalink / raw)
  To: alexander.deucher-5C7GfCeVMHo, christian.koenig-5C7GfCeVMHo,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Yuehin.Lau-5C7GfCeVMHo, mikita.lipski-5C7GfCeVMHo,
	Tony.Cheng-5C7GfCeVMHo, harry.wentland-5C7GfCeVMHo,
	linux-6IF/jdPJHihWk0Htik3J/w, drake-6IF/jdPJHihWk0Htik3J/w
  Cc: Carlo Caione

From: Carlo Caione <carlo@endlessm.com>

Hi,
on several laptops [0] we are seeing display corruption when using multiple /
external displays. We already opened an issue upstream [1].
The following 4 patches are taken from agd5f/amd-staging-drm-next and they seem
able to solve the issue.
Can those be included in 4.15?

Thank you,

[0] Acer Aspire E5-553G (AMD FX-9800P RADEON R7)
    Acer Aspire E5-523G (AMD E2-9010 RADEON R2)
    Acer Aspire A315-21 (AMD A4-9120 RADEON R3)
    Acer Aspire A515-41G (AMD A10-9620 RADEON R5)

[1] https://bugs.freedesktop.org/show_bug.cgi?id=104319

Harry Wentland (1):
  drm/amd/display: Both timing_sync and multisync need stream_count > 1

Leo (Sunpeng) Li (1):
  drm/amd/display: Change frontend/backend programming sequence

Mikita Lipski (2):
  drm/amd/display: Adding DCN1 registers
  drm/amd/display: Multi display synchronization logic

 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c  |  54 ++++-
 drivers/gpu/drm/amd/display/dc/core/dc.c           |  60 ++++-
 drivers/gpu/drm/amd/display/dc/dc.h                |   3 +
 drivers/gpu/drm/amd/display/dc/dc_hw_types.h       |  16 ++
 .../amd/display/dc/dce110/dce110_hw_sequencer.c    |  46 +++-
 .../display/dc/dce110/dce110_timing_generator.c    | 265 +++++++++++++++++----
 .../display/dc/dce110/dce110_timing_generator.h    |   6 +
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  29 ++-
 .../amd/display/dc/dcn10/dcn10_timing_generator.c  |  66 ++++-
 .../amd/display/dc/dcn10/dcn10_timing_generator.h  |  33 ++-
 .../drm/amd/display/dc/inc/hw/timing_generator.h   |   6 +-
 drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h  |   5 +
 12 files changed, 511 insertions(+), 78 deletions(-)

-- 
2.14.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 4.15 1/4] drm/amd/display: Adding DCN1 registers
       [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
@ 2018-01-03 17:11   ` Carlo Caione
  2018-01-03 17:11   ` [PATCH 4.15 2/4] drm/amd/display: Multi display synchronization logic Carlo Caione
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Carlo Caione @ 2018-01-03 17:11 UTC (permalink / raw)
  To: alexander.deucher-5C7GfCeVMHo, christian.koenig-5C7GfCeVMHo,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Yuehin.Lau-5C7GfCeVMHo, mikita.lipski-5C7GfCeVMHo,
	Tony.Cheng-5C7GfCeVMHo, harry.wentland-5C7GfCeVMHo,
	linux-6IF/jdPJHihWk0Htik3J/w, drake-6IF/jdPJHihWk0Htik3J/w

From: Mikita Lipski <mikita.lipski@amd.com>

Registers added to definition list that are required
for multi display synchronization

Signed-off-by: Mikita Lipski <mikita.lipski@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 .../amd/display/dc/dcn10/dcn10_timing_generator.h  | 33 ++++++++++++++++++++--
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h
index 7d4818d7aa31..395820606013 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h
@@ -72,7 +72,10 @@
 	SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\
 	SRI(OPPBUF_CONTROL, OPPBUF, inst),\
 	SRI(OPPBUF_3D_PARAMETERS_0, OPPBUF, inst),\
-	SRI(CONTROL, VTG, inst)
+	SRI(CONTROL, VTG, inst),\
+	SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\
+	SRI(OTG_MASTER_UPDATE_MODE, OTG, inst),\
+	SRI(OTG_GSL_CONTROL, OTG, inst)
 
 #define TG_COMMON_REG_LIST_DCN1_0(inst) \
 	TG_COMMON_REG_LIST_DCN(inst),\
@@ -82,6 +85,9 @@
 
 
 struct dcn_tg_registers {
+	uint32_t OTG_VERT_SYNC_CONTROL;
+	uint32_t OTG_MASTER_UPDATE_MODE;
+	uint32_t OTG_GSL_CONTROL;
 	uint32_t OTG_VSTARTUP_PARAM;
 	uint32_t OTG_VUPDATE_PARAM;
 	uint32_t OTG_VREADY_PARAM;
@@ -208,7 +214,18 @@ struct dcn_tg_registers {
 	SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, mask_sh),\
 	SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\
 	SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\
-	SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh)
+	SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\
+	SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\
+	SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\
+	SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\
+	SF(OTG0_OTG_MASTER_UPDATE_MODE, MASTER_UPDATE_INTERLACED_MODE, mask_sh),\
+	SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\
+	SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\
+	SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\
+	SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\
+	SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\
+	SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh)
+
 
 #define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\
 	TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\
@@ -317,7 +334,17 @@ struct dcn_tg_registers {
 	type OPPBUF_3D_VACT_SPACE1_SIZE;\
 	type VTG0_ENABLE;\
 	type VTG0_FP2;\
-	type VTG0_VCOUNT_INIT;
+	type VTG0_VCOUNT_INIT;\
+	type OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED;\
+	type OTG_FORCE_VSYNC_NEXT_LINE_CLEAR;\
+	type OTG_AUTO_FORCE_VSYNC_MODE;\
+	type MASTER_UPDATE_INTERLACED_MODE;\
+	type OTG_GSL0_EN;\
+	type OTG_GSL1_EN;\
+	type OTG_GSL2_EN;\
+	type OTG_GSL_MASTER_EN;\
+	type OTG_GSL_FORCE_DELAY;\
+	type OTG_GSL_CHECK_ALL_FIELDS;
 
 struct dcn_tg_shift {
 	TG_REG_FIELD_LIST(uint8_t)
-- 
2.14.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4.15 2/4] drm/amd/display: Multi display synchronization logic
       [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
  2018-01-03 17:11   ` [PATCH 4.15 1/4] drm/amd/display: Adding DCN1 registers Carlo Caione
@ 2018-01-03 17:11   ` Carlo Caione
  2018-01-03 17:11   ` [PATCH 4.15 3/4] drm/amd/display: Both timing_sync and multisync need stream_count > 1 Carlo Caione
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Carlo Caione @ 2018-01-03 17:11 UTC (permalink / raw)
  To: alexander.deucher-5C7GfCeVMHo, christian.koenig-5C7GfCeVMHo,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Yuehin.Lau-5C7GfCeVMHo, mikita.lipski-5C7GfCeVMHo,
	Tony.Cheng-5C7GfCeVMHo, harry.wentland-5C7GfCeVMHo,
	linux-6IF/jdPJHihWk0Htik3J/w, drake-6IF/jdPJHihWk0Htik3J/w

From: Mikita Lipski <mikita.lipski@amd.com>

This feature synchronizes multiple displays with various timings
to a display with the highest refresh rate
it is enabled if edid caps flag multi_display_sync is set to one

There are limitations on refresh rates allowed
that can be synchronized. That would
prevent from underflow and other potential
corruptions.

Multi display synchronization is using the
same functions as timing_sync in order to minimize
redunduncy and decision to disable synchronization is
based on trigger parametre set in DM

Feature is developed for DCN1 and DCE11

Signed-off-by: Mikita Lipski <mikita.lipski@amd.com>
Reviewed-by: Mikita Lipski <Mikita.Lipski@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c  |  54 ++++-
 drivers/gpu/drm/amd/display/dc/core/dc.c           |  26 +-
 drivers/gpu/drm/amd/display/dc/dc.h                |   3 +
 drivers/gpu/drm/amd/display/dc/dc_hw_types.h       |  16 ++
 .../amd/display/dc/dce110/dce110_hw_sequencer.c    |  46 +++-
 .../display/dc/dce110/dce110_timing_generator.c    | 265 +++++++++++++++++----
 .../display/dc/dce110/dce110_timing_generator.h    |   6 +
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  29 ++-
 .../amd/display/dc/dcn10/dcn10_timing_generator.c  |  66 ++++-
 .../drm/amd/display/dc/inc/hw/timing_generator.h   |   6 +-
 drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h  |   5 +
 11 files changed, 456 insertions(+), 66 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 bb5fa895fb64..0fae5dfc7614 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2330,6 +2330,56 @@ static int create_fake_sink(struct amdgpu_dm_connector *aconnector)
 	return 0;
 }
 
+static void set_multisync_trigger_params(
+		struct dc_stream_state *stream)
+{
+	if (stream->triggered_crtc_reset.enabled) {
+		stream->triggered_crtc_reset.event = CRTC_EVENT_VSYNC_RISING;
+		stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_LINE;
+	}
+}
+
+static void set_master_stream(struct dc_stream_state *stream_set[],
+			      int stream_count)
+{
+	int j, highest_rfr = 0, master_stream = 0;
+
+	for (j = 0;  j < stream_count; j++) {
+		if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
+			int refresh_rate = 0;
+
+			refresh_rate = (stream_set[j]->timing.pix_clk_khz*1000)/
+				(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
+			if (refresh_rate > highest_rfr) {
+				highest_rfr = refresh_rate;
+				master_stream = j;
+			}
+		}
+	}
+	for (j = 0;  j < stream_count; j++) {
+		if (stream_set[j] && j != master_stream)
+			stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream];
+	}
+}
+
+static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
+{
+	int i = 0;
+
+	if (context->stream_count < 2)
+		return;
+	for (i = 0; i < context->stream_count ; i++) {
+		if (!context->streams[i])
+			continue;
+		/* TODO: add a function to read AMD VSDB bits and will set
+		 * crtc_sync_master.multi_sync_enabled flag
+		 * For now its set to false
+		 */
+		set_multisync_trigger_params(context->streams[i]);
+	}
+	set_master_stream(context->streams, context->stream_count);
+}
+
 static struct dc_stream_state *
 create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 		       const struct drm_display_mode *drm_mode,
@@ -4160,8 +4210,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 		}
 	}
 
-	if (dm_state->context)
+	if (dm_state->context) {
+		dm_enable_per_frame_crtc_master_sync(dm_state->context);
 		WARN_ON(!dc_commit_state(dm->dc, dm_state->context));
+	}
 
 	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 7240db2e6f09..26c0dade7982 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -712,6 +712,28 @@ void dc_destroy(struct dc **dc)
 	*dc = NULL;
 }
 
+static void enable_timing_multisync(
+		struct dc *dc,
+		struct dc_state *ctx)
+{
+	int i = 0, multisync_count = 0;
+	int pipe_count = dc->res_pool->pipe_count;
+	struct pipe_ctx *multisync_pipes[MAX_PIPES] = { NULL };
+
+	for (i = 0; i < pipe_count; i++) {
+		if (!ctx->res_ctx.pipe_ctx[i].stream ||
+				!ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.enabled)
+			continue;
+		multisync_pipes[multisync_count] = &ctx->res_ctx.pipe_ctx[i];
+		multisync_count++;
+	}
+
+	if (multisync_count > 1) {
+		dc->hwss.enable_per_frame_crtc_position_reset(
+			dc, multisync_count, multisync_pipes);
+	}
+}
+
 static void program_timing_sync(
 		struct dc *dc,
 		struct dc_state *ctx)
@@ -888,7 +910,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 	}
 	result = dc->hwss.apply_ctx_to_hw(dc, context);
 
-	program_timing_sync(dc, context);
+	if (context->stream_count > 1)
+		enable_timing_multisync(dc, context);
+		program_timing_sync(dc, context);
 
 	dc_enable_stereo(dc, context, dc_streams, context->stream_count);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 9d8f4a55c74e..7fc60f6880f2 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -617,6 +617,9 @@ struct dc_stream_state {
 
 	/* from stream struct */
 	struct kref refcount;
+
+	struct crtc_trigger_info triggered_crtc_reset;
+
 };
 
 struct dc_stream_update {
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
index 1a9f57fb0838..5356909b07c2 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -664,6 +664,22 @@ enum dc_timing_3d_format {
 	TIMING_3D_FORMAT_MAX,
 };
 
+enum trigger_delay {
+	TRIGGER_DELAY_NEXT_PIXEL = 0,
+	TRIGGER_DELAY_NEXT_LINE,
+};
+
+enum crtc_event {
+	CRTC_EVENT_VSYNC_RISING = 0,
+	CRTC_EVENT_VSYNC_FALLING
+};
+
+struct crtc_trigger_info {
+	bool enabled;
+	struct dc_stream_state *event_source;
+	enum crtc_event event;
+	enum trigger_delay delay;
+};
 
 struct dc_crtc_timing {
 
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
index d844fadcd56f..fe444b582783 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -2458,20 +2458,16 @@ static void dce110_enable_timing_synchronization(
 
 	for (i = 1 /* skip the master */; i < group_size; i++)
 		grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger(
-					grouped_pipes[i]->stream_res.tg, gsl_params.gsl_group);
-
-
+				grouped_pipes[i]->stream_res.tg,
+				gsl_params.gsl_group);
 
 	for (i = 1 /* skip the master */; i < group_size; i++) {
 		DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
 		wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
-		/* Regardless of success of the wait above, remove the reset or
-		 * the driver will start timing out on Display requests. */
-		DC_SYNC_INFO("GSL: disabling trigger-reset.\n");
-		grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(grouped_pipes[i]->stream_res.tg);
+		grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(
+				grouped_pipes[i]->stream_res.tg);
 	}
 
-
 	/* GSL Vblank synchronization is a one time sync mechanism, assumption
 	 * is that the sync'ed displays will not drift out of sync over time*/
 	DC_SYNC_INFO("GSL: Restoring register states.\n");
@@ -2481,6 +2477,39 @@ static void dce110_enable_timing_synchronization(
 	DC_SYNC_INFO("GSL: Set-up complete.\n");
 }
 
+static void dce110_enable_per_frame_crtc_position_reset(
+		struct dc *dc,
+		int group_size,
+		struct pipe_ctx *grouped_pipes[])
+{
+	struct dc_context *dc_ctx = dc->ctx;
+	struct dcp_gsl_params gsl_params = { 0 };
+	int i;
+
+	gsl_params.gsl_group = 0;
+	gsl_params.gsl_master = grouped_pipes[0]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst;
+
+	for (i = 0; i < group_size; i++)
+		grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock(
+					grouped_pipes[i]->stream_res.tg, &gsl_params);
+
+	DC_SYNC_INFO("GSL: enabling trigger-reset\n");
+
+	for (i = 1; i < group_size; i++)
+		grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
+				grouped_pipes[i]->stream_res.tg,
+				gsl_params.gsl_master,
+				&grouped_pipes[i]->stream->triggered_crtc_reset);
+
+	DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
+	for (i = 1; i < group_size; i++)
+		wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
+
+	for (i = 0; i < group_size; i++)
+		grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg);
+
+}
+
 static void init_hw(struct dc *dc)
 {
 	int i;
@@ -2977,6 +3006,7 @@ static const struct hw_sequencer_funcs dce110_funcs = {
 	.power_down = dce110_power_down,
 	.enable_accelerated_mode = dce110_enable_accelerated_mode,
 	.enable_timing_synchronization = dce110_enable_timing_synchronization,
+	.enable_per_frame_crtc_position_reset = dce110_enable_per_frame_crtc_position_reset,
 	.update_info_frame = dce110_update_info_frame,
 	.enable_stream = dce110_enable_stream,
 	.disable_stream = dce110_disable_stream,
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c
index 4befce6cd87a..25ca72139e5f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c
@@ -1224,26 +1224,46 @@ void dce110_timing_generator_setup_global_swap_lock(
 
 	/* This pipe will belong to GSL Group zero. */
 	set_reg_field_value(value,
-			1,
-			DCP_GSL_CONTROL,
-			DCP_GSL0_EN);
+			    1,
+			    DCP_GSL_CONTROL,
+			    DCP_GSL0_EN);
 
 	set_reg_field_value(value,
-			gsl_params->gsl_master == tg->inst,
-			DCP_GSL_CONTROL,
-			DCP_GSL_MASTER_EN);
+			    gsl_params->gsl_master == tg->inst,
+			    DCP_GSL_CONTROL,
+			    DCP_GSL_MASTER_EN);
 
 	set_reg_field_value(value,
-			HFLIP_READY_DELAY,
-			DCP_GSL_CONTROL,
-			DCP_GSL_HSYNC_FLIP_FORCE_DELAY);
+			    HFLIP_READY_DELAY,
+			    DCP_GSL_CONTROL,
+			    DCP_GSL_HSYNC_FLIP_FORCE_DELAY);
 
 	/* Keep signal low (pending high) during 6 lines.
 	 * Also defines minimum interval before re-checking signal. */
 	set_reg_field_value(value,
-			HFLIP_CHECK_DELAY,
-			DCP_GSL_CONTROL,
-			DCP_GSL_HSYNC_FLIP_CHECK_DELAY);
+			    HFLIP_CHECK_DELAY,
+			    DCP_GSL_CONTROL,
+			    DCP_GSL_HSYNC_FLIP_CHECK_DELAY);
+
+	dm_write_reg(tg->ctx, CRTC_REG(mmDCP_GSL_CONTROL), value);
+	value = 0;
+
+	set_reg_field_value(value,
+			    gsl_params->gsl_master,
+			    DCIO_GSL0_CNTL,
+			    DCIO_GSL0_VSYNC_SEL);
+
+	set_reg_field_value(value,
+			    0,
+			    DCIO_GSL0_CNTL,
+			    DCIO_GSL0_TIMING_SYNC_SEL);
+
+	set_reg_field_value(value,
+			    0,
+			    DCIO_GSL0_CNTL,
+			    DCIO_GSL0_GLOBAL_UNLOCK_SEL);
+
+	dm_write_reg(tg->ctx, CRTC_REG(mmDCIO_GSL0_CNTL), value);
 
 
 	{
@@ -1253,38 +1273,38 @@ void dce110_timing_generator_setup_global_swap_lock(
 				CRTC_REG(mmCRTC_V_TOTAL));
 
 		set_reg_field_value(value,
-				0,/* DCP_GSL_PURPOSE_SURFACE_FLIP */
-				DCP_GSL_CONTROL,
-				DCP_GSL_SYNC_SOURCE);
+				    0,/* DCP_GSL_PURPOSE_SURFACE_FLIP */
+				    DCP_GSL_CONTROL,
+				    DCP_GSL_SYNC_SOURCE);
 
 		/* Checkpoint relative to end of frame */
 		check_point = get_reg_field_value(value_crtc_vtotal,
-				CRTC_V_TOTAL,
-				CRTC_V_TOTAL);
+						  CRTC_V_TOTAL,
+						  CRTC_V_TOTAL);
 
 		dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_GSL_WINDOW), 0);
 	}
 
 	set_reg_field_value(value,
-			1,
-			DCP_GSL_CONTROL,
-			DCP_GSL_DELAY_SURFACE_UPDATE_PENDING);
+			    1,
+			    DCP_GSL_CONTROL,
+			    DCP_GSL_DELAY_SURFACE_UPDATE_PENDING);
 
 	dm_write_reg(tg->ctx, address, value);
 
 	/********************************************************************/
 	address = CRTC_REG(mmCRTC_GSL_CONTROL);
 
-	value = 0;
+	value = dm_read_reg(tg->ctx, address);
 	set_reg_field_value(value,
-			check_point - FLIP_READY_BACK_LOOKUP,
-			CRTC_GSL_CONTROL,
-			CRTC_GSL_CHECK_LINE_NUM);
+			    check_point - FLIP_READY_BACK_LOOKUP,
+			    CRTC_GSL_CONTROL,
+			    CRTC_GSL_CHECK_LINE_NUM);
 
 	set_reg_field_value(value,
-			VFLIP_READY_DELAY,
-			CRTC_GSL_CONTROL,
-			CRTC_GSL_FORCE_DELAY);
+			    VFLIP_READY_DELAY,
+			    CRTC_GSL_CONTROL,
+			    CRTC_GSL_FORCE_DELAY);
 
 	dm_write_reg(tg->ctx, address, value);
 }
@@ -1555,6 +1575,138 @@ void dce110_timing_generator_enable_reset_trigger(
 	dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
 }
 
+void dce110_timing_generator_enable_crtc_reset(
+		struct timing_generator *tg,
+		int source_tg_inst,
+		struct crtc_trigger_info *crtc_tp)
+{
+	uint32_t value = 0;
+	uint32_t rising_edge = 0;
+	uint32_t falling_edge = 0;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	/* Setup trigger edge */
+	switch (crtc_tp->event) {
+	case CRTC_EVENT_VSYNC_RISING:
+			rising_edge = 1;
+			break;
+
+	case CRTC_EVENT_VSYNC_FALLING:
+		falling_edge = 1;
+		break;
+	}
+
+	value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL));
+
+	set_reg_field_value(value,
+			    source_tg_inst,
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_SOURCE_SELECT);
+
+	set_reg_field_value(value,
+			    TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_POLARITY_SELECT);
+
+	set_reg_field_value(value,
+			    rising_edge,
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_RISING_EDGE_DETECT_CNTL);
+
+	set_reg_field_value(value,
+			    falling_edge,
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL);
+
+	set_reg_field_value(value,
+			    1, /* clear trigger status */
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_CLEAR);
+
+	dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value);
+
+	/**************************************************************/
+
+	switch (crtc_tp->delay) {
+	case TRIGGER_DELAY_NEXT_LINE:
+		value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
+
+		set_reg_field_value(value,
+				    0, /* force H count to H_TOTAL and V count to V_TOTAL */
+				    CRTC_FORCE_COUNT_NOW_CNTL,
+				    CRTC_FORCE_COUNT_NOW_MODE);
+
+		set_reg_field_value(value,
+				    0, /* TriggerB - we never use TriggerA */
+				    CRTC_FORCE_COUNT_NOW_CNTL,
+				    CRTC_FORCE_COUNT_NOW_TRIG_SEL);
+
+		set_reg_field_value(value,
+				    1, /* clear trigger status */
+				    CRTC_FORCE_COUNT_NOW_CNTL,
+				    CRTC_FORCE_COUNT_NOW_CLEAR);
+
+		dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
+
+		value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
+
+		set_reg_field_value(value,
+				    1,
+				    CRTC_VERT_SYNC_CONTROL,
+				    CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR);
+
+		set_reg_field_value(value,
+				    2,
+				    CRTC_VERT_SYNC_CONTROL,
+				    CRTC_AUTO_FORCE_VSYNC_MODE);
+
+		break;
+
+	case TRIGGER_DELAY_NEXT_PIXEL:
+		value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
+
+		set_reg_field_value(value,
+				    1,
+				    CRTC_VERT_SYNC_CONTROL,
+				    CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR);
+
+		set_reg_field_value(value,
+				    0,
+				    CRTC_VERT_SYNC_CONTROL,
+				    CRTC_AUTO_FORCE_VSYNC_MODE);
+
+		dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL), value);
+
+		value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
+
+		set_reg_field_value(value,
+				    2, /* force H count to H_TOTAL and V count to V_TOTAL */
+				    CRTC_FORCE_COUNT_NOW_CNTL,
+				    CRTC_FORCE_COUNT_NOW_MODE);
+
+		set_reg_field_value(value,
+				    1, /* TriggerB - we never use TriggerA */
+				    CRTC_FORCE_COUNT_NOW_CNTL,
+				    CRTC_FORCE_COUNT_NOW_TRIG_SEL);
+
+		set_reg_field_value(value,
+				    1, /* clear trigger status */
+				    CRTC_FORCE_COUNT_NOW_CNTL,
+				    CRTC_FORCE_COUNT_NOW_CLEAR);
+
+		dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
+		break;
+	}
+
+	value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE));
+
+	set_reg_field_value(value,
+			    2,
+			    CRTC_MASTER_UPDATE_MODE,
+			    MASTER_UPDATE_MODE);
+
+	dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE), value);
+}
 void dce110_timing_generator_disable_reset_trigger(
 	struct timing_generator *tg)
 {
@@ -1564,34 +1716,48 @@ void dce110_timing_generator_disable_reset_trigger(
 	value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
 
 	set_reg_field_value(value,
-			0, /* force counter now mode is disabled */
-			CRTC_FORCE_COUNT_NOW_CNTL,
-			CRTC_FORCE_COUNT_NOW_MODE);
+			    0, /* force counter now mode is disabled */
+			    CRTC_FORCE_COUNT_NOW_CNTL,
+			    CRTC_FORCE_COUNT_NOW_MODE);
 
 	set_reg_field_value(value,
-			1, /* clear trigger status */
-			CRTC_FORCE_COUNT_NOW_CNTL,
-			CRTC_FORCE_COUNT_NOW_CLEAR);
+			    1, /* clear trigger status */
+			    CRTC_FORCE_COUNT_NOW_CNTL,
+			    CRTC_FORCE_COUNT_NOW_CLEAR);
 
 	dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
 
+	value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
+
+	set_reg_field_value(value,
+			    1,
+			    CRTC_VERT_SYNC_CONTROL,
+			    CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR);
+
+	set_reg_field_value(value,
+			    0,
+			    CRTC_VERT_SYNC_CONTROL,
+			    CRTC_AUTO_FORCE_VSYNC_MODE);
+
+	dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL), value);
+
 	/********************************************************************/
 	value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL));
 
 	set_reg_field_value(value,
-			TRIGGER_SOURCE_SELECT_LOGIC_ZERO,
-			CRTC_TRIGB_CNTL,
-			CRTC_TRIGB_SOURCE_SELECT);
+			    TRIGGER_SOURCE_SELECT_LOGIC_ZERO,
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_SOURCE_SELECT);
 
 	set_reg_field_value(value,
-			TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
-			CRTC_TRIGB_CNTL,
-			CRTC_TRIGB_POLARITY_SELECT);
+			    TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_POLARITY_SELECT);
 
 	set_reg_field_value(value,
-			1, /* clear trigger status */
-			CRTC_TRIGB_CNTL,
-			CRTC_TRIGB_CLEAR);
+			    1, /* clear trigger status */
+			    CRTC_TRIGB_CNTL,
+			    CRTC_TRIGB_CLEAR);
 
 	dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value);
 }
@@ -1611,10 +1777,16 @@ bool dce110_timing_generator_did_triggered_reset_occur(
 	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
 	uint32_t value = dm_read_reg(tg->ctx,
 			CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
-
-	return get_reg_field_value(value,
-			CRTC_FORCE_COUNT_NOW_CNTL,
-			CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
+	uint32_t value1 = dm_read_reg(tg->ctx,
+			CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
+	bool force = get_reg_field_value(value,
+					 CRTC_FORCE_COUNT_NOW_CNTL,
+					 CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
+	bool vert_sync = get_reg_field_value(value1,
+					     CRTC_VERT_SYNC_CONTROL,
+					     CRTC_FORCE_VSYNC_NEXT_LINE_OCCURRED) != 0;
+
+	return (force || vert_sync);
 }
 
 /**
@@ -1928,6 +2100,7 @@ static const struct timing_generator_funcs dce110_tg_funcs = {
 		.setup_global_swap_lock =
 				dce110_timing_generator_setup_global_swap_lock,
 		.enable_reset_trigger = dce110_timing_generator_enable_reset_trigger,
+		.enable_crtc_reset = dce110_timing_generator_enable_crtc_reset,
 		.disable_reset_trigger = dce110_timing_generator_disable_reset_trigger,
 		.tear_down_global_swap_lock =
 				dce110_timing_generator_tear_down_global_swap_lock,
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h
index 82737dea6984..232747c7c60b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h
@@ -174,6 +174,12 @@ void dce110_timing_generator_setup_global_swap_lock(
 void dce110_timing_generator_tear_down_global_swap_lock(
 	struct timing_generator *tg);
 
+/* Reset crtc position on master VSync */
+void dce110_timing_generator_enable_crtc_reset(
+	struct timing_generator *tg,
+	int source,
+	struct crtc_trigger_info *crtc_tp);
+
 /* Reset slave controllers on master VSync */
 void dce110_timing_generator_enable_reset_trigger(
 	struct timing_generator *tg,
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 961ad5c3b454..502a2ffb5d6b 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
@@ -1833,14 +1833,15 @@ static void dcn10_enable_timing_synchronization(
 
 	for (i = 1; i < group_size; i++)
 		grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger(
-				grouped_pipes[i]->stream_res.tg, grouped_pipes[0]->stream_res.tg->inst);
-
+				grouped_pipes[i]->stream_res.tg,
+				grouped_pipes[0]->stream_res.tg->inst);
 
 	DC_SYNC_INFO("Waiting for trigger\n");
 
 	/* Need to get only check 1 pipe for having reset as all the others are
 	 * synchronized. Look at last pipe programmed to reset.
 	 */
+
 	wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg);
 	for (i = 1; i < group_size; i++)
 		grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(
@@ -1849,6 +1850,29 @@ static void dcn10_enable_timing_synchronization(
 	DC_SYNC_INFO("Sync complete\n");
 }
 
+static void dcn10_enable_per_frame_crtc_position_reset(
+	struct dc *dc,
+	int group_size,
+	struct pipe_ctx *grouped_pipes[])
+{
+	struct dc_context *dc_ctx = dc->ctx;
+	int i;
+
+	DC_SYNC_INFO("Setting up\n");
+	for (i = 0; i < group_size; i++)
+		grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
+				grouped_pipes[i]->stream_res.tg,
+				grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst,
+				&grouped_pipes[i]->stream->triggered_crtc_reset);
+
+	DC_SYNC_INFO("Waiting for trigger\n");
+
+	for (i = 1; i < group_size; i++)
+		wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
+
+	DC_SYNC_INFO("Multi-display sync is complete\n");
+}
+
 static void print_rq_dlg_ttu(
 		struct dc *core_dc,
 		struct pipe_ctx *pipe_ctx)
@@ -2926,6 +2950,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
 	.power_down = dce110_power_down,
 	.enable_accelerated_mode = dce110_enable_accelerated_mode,
 	.enable_timing_synchronization = dcn10_enable_timing_synchronization,
+	.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
 	.update_info_frame = dce110_update_info_frame,
 	.enable_stream = dce110_enable_stream,
 	.disable_stream = dce110_disable_stream,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c
index fced178c8c79..c178cc0bd426 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c
@@ -610,12 +610,28 @@ static bool tgn10_did_triggered_reset_occur(
 	struct timing_generator *tg)
 {
 	struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
-	uint32_t occurred;
+	uint32_t occurred_force, occurred_vsync;
 
 	REG_GET(OTG_FORCE_COUNT_NOW_CNTL,
-		OTG_FORCE_COUNT_NOW_OCCURRED, &occurred);
+		OTG_FORCE_COUNT_NOW_OCCURRED, &occurred_force);
 
-	return occurred != 0;
+	REG_GET(OTG_VERT_SYNC_CONTROL,
+		OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, &occurred_vsync);
+
+	return occurred_vsync != 0 || occurred_force != 0;
+}
+
+static void tgn10_disable_reset_trigger(struct timing_generator *tg)
+{
+	struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
+
+	REG_WRITE(OTG_TRIGA_CNTL, 0);
+
+	REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0,
+		OTG_FORCE_COUNT_NOW_CLEAR, 1);
+
+	REG_SET(OTG_VERT_SYNC_CONTROL, 0,
+		OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, 1);
 }
 
 static void tgn10_enable_reset_trigger(struct timing_generator *tg, int source_tg_inst)
@@ -652,14 +668,49 @@ static void tgn10_enable_reset_trigger(struct timing_generator *tg, int source_t
 			OTG_FORCE_COUNT_NOW_MODE, 2);
 }
 
-static void tgn10_disable_reset_trigger(struct timing_generator *tg)
+void tgn10_enable_crtc_reset(
+		struct timing_generator *tg,
+		int source_tg_inst,
+		struct crtc_trigger_info *crtc_tp)
 {
 	struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
+	uint32_t falling_edge = 0;
+	uint32_t rising_edge = 0;
 
-	REG_WRITE(OTG_TRIGA_CNTL, 0);
+	switch (crtc_tp->event) {
 
-	REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0,
-			OTG_FORCE_COUNT_NOW_CLEAR, 1);
+	case CRTC_EVENT_VSYNC_RISING:
+		rising_edge = 1;
+		break;
+
+	case CRTC_EVENT_VSYNC_FALLING:
+		falling_edge = 1;
+		break;
+	}
+
+	REG_SET_4(OTG_TRIGA_CNTL, 0,
+		 /* vsync signal from selected OTG pipe based
+		  * on OTG_TRIG_SOURCE_PIPE_SELECT setting
+		  */
+		  OTG_TRIGA_SOURCE_SELECT, 20,
+		  OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst,
+		  /* always detect falling edge */
+		  OTG_TRIGA_RISING_EDGE_DETECT_CNTL, rising_edge,
+		  OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, falling_edge);
+
+	switch (crtc_tp->delay) {
+	case TRIGGER_DELAY_NEXT_LINE:
+		REG_SET(OTG_VERT_SYNC_CONTROL, 0,
+				OTG_AUTO_FORCE_VSYNC_MODE, 1);
+		break;
+	case TRIGGER_DELAY_NEXT_PIXEL:
+		REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0,
+			/* force H count to H_TOTAL and V count to V_TOTAL in
+			 * progressive mode and V_TOTAL-1 in interlaced mode
+			 */
+			OTG_FORCE_COUNT_NOW_MODE, 2);
+		break;
+	}
 }
 
 static void tgn10_wait_for_state(struct timing_generator *tg,
@@ -1174,6 +1225,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
 		.set_blank_color = tgn10_program_blank_color,
 		.did_triggered_reset_occur = tgn10_did_triggered_reset_occur,
 		.enable_reset_trigger = tgn10_enable_reset_trigger,
+		.enable_crtc_reset = tgn10_enable_crtc_reset,
 		.disable_reset_trigger = tgn10_disable_reset_trigger,
 		.lock = tgn10_lock,
 		.unlock = tgn10_unlock,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index c6ab38c5b2be..75f7a01b9175 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -158,7 +158,11 @@ struct timing_generator_funcs {
 							const struct dcp_gsl_params *gsl_params);
 	void (*unlock)(struct timing_generator *tg);
 	void (*lock)(struct timing_generator *tg);
-	void (*enable_reset_trigger)(struct timing_generator *tg, int source_tg_inst);
+	void (*enable_reset_trigger)(struct timing_generator *tg,
+				     int source_tg_inst);
+	void (*enable_crtc_reset)(struct timing_generator *tg,
+				  int source_tg_inst,
+				  struct crtc_trigger_info *crtc_tp);
 	void (*disable_reset_trigger)(struct timing_generator *tg);
 	void (*tear_down_global_swap_lock)(struct timing_generator *tg);
 	void (*enable_advanced_request)(struct timing_generator *tg,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
index 8734689a9245..cebbba345889 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -114,6 +114,11 @@ struct hw_sequencer_funcs {
 			int group_size,
 			struct pipe_ctx *grouped_pipes[]);
 
+	void (*enable_per_frame_crtc_position_reset)(
+			struct dc *dc,
+			int group_size,
+			struct pipe_ctx *grouped_pipes[]);
+
 	void (*enable_display_pipe_clock_gating)(
 					struct dc_context *ctx,
 					bool clock_gating);
-- 
2.14.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4.15 3/4] drm/amd/display: Both timing_sync and multisync need stream_count > 1
       [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
  2018-01-03 17:11   ` [PATCH 4.15 1/4] drm/amd/display: Adding DCN1 registers Carlo Caione
  2018-01-03 17:11   ` [PATCH 4.15 2/4] drm/amd/display: Multi display synchronization logic Carlo Caione
@ 2018-01-03 17:11   ` Carlo Caione
  2018-01-03 17:11   ` [PATCH 4.15 4/4] drm/amd/display: Change frontend/backend programming sequence Carlo Caione
  2018-01-03 17:32   ` [PATCH 4.15 0/4] Backport DC commits to fix display corruption Harry Wentland
  4 siblings, 0 replies; 7+ messages in thread
From: Carlo Caione @ 2018-01-03 17:11 UTC (permalink / raw)
  To: alexander.deucher-5C7GfCeVMHo, christian.koenig-5C7GfCeVMHo,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Yuehin.Lau-5C7GfCeVMHo, mikita.lipski-5C7GfCeVMHo,
	Tony.Cheng-5C7GfCeVMHo, harry.wentland-5C7GfCeVMHo,
	linux-6IF/jdPJHihWk0Htik3J/w, drake-6IF/jdPJHihWk0Htik3J/w

From: Harry Wentland <harry.wentland@amd.com>

Previous code threw a warning about misleading indentation

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Mikita Lipski <Mikita.Lipski@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 26c0dade7982..5b3ca80d9401 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -910,9 +910,10 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 	}
 	result = dc->hwss.apply_ctx_to_hw(dc, context);
 
-	if (context->stream_count > 1)
+	if (context->stream_count > 1) {
 		enable_timing_multisync(dc, context);
 		program_timing_sync(dc, context);
+	}
 
 	dc_enable_stereo(dc, context, dc_streams, context->stream_count);
 
-- 
2.14.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4.15 4/4] drm/amd/display: Change frontend/backend programming sequence
       [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
                     ` (2 preceding siblings ...)
  2018-01-03 17:11   ` [PATCH 4.15 3/4] drm/amd/display: Both timing_sync and multisync need stream_count > 1 Carlo Caione
@ 2018-01-03 17:11   ` Carlo Caione
  2018-01-03 17:32   ` [PATCH 4.15 0/4] Backport DC commits to fix display corruption Harry Wentland
  4 siblings, 0 replies; 7+ messages in thread
From: Carlo Caione @ 2018-01-03 17:11 UTC (permalink / raw)
  To: alexander.deucher-5C7GfCeVMHo, christian.koenig-5C7GfCeVMHo,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Yuehin.Lau-5C7GfCeVMHo, mikita.lipski-5C7GfCeVMHo,
	Tony.Cheng-5C7GfCeVMHo, harry.wentland-5C7GfCeVMHo,
	linux-6IF/jdPJHihWk0Htik3J/w, drake-6IF/jdPJHihWk0Htik3J/w
  Cc: Leo (Sunpeng) Li

From: "Leo (Sunpeng) Li" <sunpeng.li@amd.com>

This is a follow-up to the following change:

Yongqiang Sun: Program front end first when set mode.

Due to pipe-splitting features, how we handle stream enabling and
disabling needs to change.

In the case of pipe split disable, two planes need to be combined back
into the same stream. This needs to be done before any stream
programming happens.

The previous patch addresses this, but breaks cross-platform
compatibility. It's not guaranteed that a dc commit will be called
separately to program planes and streams.

Therefore, we handle the combined commit case by doing plane programming
both before and after stream programming, to handle pipe split disable
and plane enable respectively.

Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc.c | 41 ++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 5b3ca80d9401..8eeda0fb5c41 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -871,6 +871,33 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 	if (!dcb->funcs->is_accelerated_mode(dcb))
 		dc->hwss.enable_accelerated_mode(dc);
 
+	/* Combine planes if required, in case of pipe split disable */
+	for (i = 0; i < dc->current_state->stream_count; i++) {
+		dc->hwss.apply_ctx_for_surface(
+			dc, dc->current_state->streams[i],
+			dc->current_state->stream_status[i].plane_count,
+			dc->current_state);
+	}
+
+	/* Program hardware */
+	dc->hwss.ready_shared_resources(dc, context);
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		pipe = &context->res_ctx.pipe_ctx[i];
+		dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
+	}
+
+	result = dc->hwss.apply_ctx_to_hw(dc, context);
+
+	if (result != DC_OK)
+		goto fail;
+
+	if (context->stream_count > 1) {
+		enable_timing_multisync(dc, context);
+		program_timing_sync(dc, context);
+	}
+
+	/* Program all planes within new context*/
 	for (i = 0; i < context->stream_count; i++) {
 		const struct dc_sink *sink = context->streams[i]->sink;
 
@@ -902,19 +929,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 				context->streams[i]->timing.pix_clk_khz);
 	}
 
-	dc->hwss.ready_shared_resources(dc, context);
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		pipe = &context->res_ctx.pipe_ctx[i];
-		dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
-	}
-	result = dc->hwss.apply_ctx_to_hw(dc, context);
-
-	if (context->stream_count > 1) {
-		enable_timing_multisync(dc, context);
-		program_timing_sync(dc, context);
-	}
-
+fail:
 	dc_enable_stereo(dc, context, dc_streams, context->stream_count);
 
 	for (i = 0; i < context->stream_count; i++) {
-- 
2.14.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 4.15 0/4] Backport DC commits to fix display corruption
       [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
                     ` (3 preceding siblings ...)
  2018-01-03 17:11   ` [PATCH 4.15 4/4] drm/amd/display: Change frontend/backend programming sequence Carlo Caione
@ 2018-01-03 17:32   ` Harry Wentland
       [not found]     ` <e9f61bee-e168-d863-1ca7-c83e57e6c806-5C7GfCeVMHo@public.gmane.org>
  4 siblings, 1 reply; 7+ messages in thread
From: Harry Wentland @ 2018-01-03 17:32 UTC (permalink / raw)
  To: Carlo Caione, alexander.deucher-5C7GfCeVMHo,
	christian.koenig-5C7GfCeVMHo,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Yuehin.Lau-5C7GfCeVMHo, mikita.lipski-5C7GfCeVMHo,
	Tony.Cheng-5C7GfCeVMHo, linux-6IF/jdPJHihWk0Htik3J/w,
	drake-6IF/jdPJHihWk0Htik3J/w
  Cc: Carlo Caione

On 2018-01-03 12:11 PM, Carlo Caione wrote:
> From: Carlo Caione <carlo@endlessm.com>
> 
> Hi,
> on several laptops [0] we are seeing display corruption when using multiple /
> external displays. We already opened an issue upstream [1].
> The following 4 patches are taken from agd5f/amd-staging-drm-next and they seem
> able to solve the issue.
> Can those be included in 4.15?
> 
> Thank you,
> 
> [0] Acer Aspire E5-553G (AMD FX-9800P RADEON R7)
>     Acer Aspire E5-523G (AMD E2-9010 RADEON R2)
>     Acer Aspire A315-21 (AMD A4-9120 RADEON R3)
>     Acer Aspire A515-41G (AMD A10-9620 RADEON R5)
> 
> [1] https://bugs.freedesktop.org/show_bug.cgi?id=104319
> 
> Harry Wentland (1):
>   drm/amd/display: Both timing_sync and multisync need stream_count > 1
> 
> Leo (Sunpeng) Li (1):
>   drm/amd/display: Change frontend/backend programming sequence
> 
> Mikita Lipski (2):
>   drm/amd/display: Adding DCN1 registers
>   drm/amd/display: Multi display synchronization logic
> 

I'm surprised Mikita and my patches are required here. Are you sure they make a difference for display corruption or did you simply add them to make pull Leo's patch more cleanly?

They're not bad changes. The "Multi display synchronization logic" patch is just very big and shouldn't have an impact expect in very unique situations.

Harry

>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c  |  54 ++++-
>  drivers/gpu/drm/amd/display/dc/core/dc.c           |  60 ++++-
>  drivers/gpu/drm/amd/display/dc/dc.h                |   3 +
>  drivers/gpu/drm/amd/display/dc/dc_hw_types.h       |  16 ++
>  .../amd/display/dc/dce110/dce110_hw_sequencer.c    |  46 +++-
>  .../display/dc/dce110/dce110_timing_generator.c    | 265 +++++++++++++++++----
>  .../display/dc/dce110/dce110_timing_generator.h    |   6 +
>  .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  29 ++-
>  .../amd/display/dc/dcn10/dcn10_timing_generator.c  |  66 ++++-
>  .../amd/display/dc/dcn10/dcn10_timing_generator.h  |  33 ++-
>  .../drm/amd/display/dc/inc/hw/timing_generator.h   |   6 +-
>  drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h  |   5 +
>  12 files changed, 511 insertions(+), 78 deletions(-)
> 
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 4.15 0/4] Backport DC commits to fix display corruption
       [not found]     ` <e9f61bee-e168-d863-1ca7-c83e57e6c806-5C7GfCeVMHo@public.gmane.org>
@ 2018-01-03 17:36       ` Carlo Caione
  0 siblings, 0 replies; 7+ messages in thread
From: Carlo Caione @ 2018-01-03 17:36 UTC (permalink / raw)
  To: Harry Wentland
  Cc: Yuehin.Lau-5C7GfCeVMHo, Linux Upstreaming Team, dri-devel,
	Daniel Drake, Deucher, Alexander,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Carlo Caione,
	mikita.lipski-5C7GfCeVMHo, Tony.Cheng-5C7GfCeVMHo,
	christian.koenig-5C7GfCeVMHo

On Wed, Jan 3, 2018 at 5:32 PM, Harry Wentland <harry.wentland@amd.com> wrote:
> On 2018-01-03 12:11 PM, Carlo Caione wrote:
>> From: Carlo Caione <carlo@endlessm.com>
>>
>> Hi,
>> on several laptops [0] we are seeing display corruption when using multiple /
>> external displays. We already opened an issue upstream [1].
>> The following 4 patches are taken from agd5f/amd-staging-drm-next and they seem
>> able to solve the issue.
>> Can those be included in 4.15?
>>
>> Thank you,
>>
>> [0] Acer Aspire E5-553G (AMD FX-9800P RADEON R7)
>>     Acer Aspire E5-523G (AMD E2-9010 RADEON R2)
>>     Acer Aspire A315-21 (AMD A4-9120 RADEON R3)
>>     Acer Aspire A515-41G (AMD A10-9620 RADEON R5)
>>
>> [1] https://bugs.freedesktop.org/show_bug.cgi?id=104319
>>
>> Harry Wentland (1):
>>   drm/amd/display: Both timing_sync and multisync need stream_count > 1
>>
>> Leo (Sunpeng) Li (1):
>>   drm/amd/display: Change frontend/backend programming sequence
>>
>> Mikita Lipski (2):
>>   drm/amd/display: Adding DCN1 registers
>>   drm/amd/display: Multi display synchronization logic
>>
>
> I'm surprised Mikita and my patches are required here. Are you sure they make a difference for display corruption or did you simply add them to make pull Leo's patch more cleanly?

Yes, the only strictly required patch is the patch by Leo. The others
are just pulled in to make that apply cleanly.

Thanks,

-- 
Carlo Caione  |  +44.7384.69.16.04  |  Endless
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-01-03 17:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-03 17:11 [PATCH 4.15 0/4] Backport DC commits to fix display corruption Carlo Caione
     [not found] ` <20180103171108.17391-1-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
2018-01-03 17:11   ` [PATCH 4.15 1/4] drm/amd/display: Adding DCN1 registers Carlo Caione
2018-01-03 17:11   ` [PATCH 4.15 2/4] drm/amd/display: Multi display synchronization logic Carlo Caione
2018-01-03 17:11   ` [PATCH 4.15 3/4] drm/amd/display: Both timing_sync and multisync need stream_count > 1 Carlo Caione
2018-01-03 17:11   ` [PATCH 4.15 4/4] drm/amd/display: Change frontend/backend programming sequence Carlo Caione
2018-01-03 17:32   ` [PATCH 4.15 0/4] Backport DC commits to fix display corruption Harry Wentland
     [not found]     ` <e9f61bee-e168-d863-1ca7-c83e57e6c806-5C7GfCeVMHo@public.gmane.org>
2018-01-03 17:36       ` Carlo Caione

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).