AMD-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
@ 2026-05-04 18:36 sunpeng.li
  2026-05-04 20:54 ` Timur Kristóf
  2026-05-10  6:06 ` Shengyu Qu
  0 siblings, 2 replies; 9+ messages in thread
From: sunpeng.li @ 2026-05-04 18:36 UTC (permalink / raw)
  To: amd-gfx
  Cc: Harry.Wentland, Aurabindo.Pillai, mario.limonciello, wiagn233,
	sysdadmin, Leo Li

From: Leo Li <sunpeng.li@amd.com>

[Why]

VStartup is an OTG event that fires when the pixel pipeline prepares for
pixel scanout of the next frame. It was previously used to deliver
vblank events for commits that do not trigger a fb address update, and
hence a pflip interrupt (hw cursor updates, for example).

The issue with vstartup is that HW can mask the interrupt in cases where
idle optimizations are enabled or when a HW lock is active. This could
the explain the range of flip_done timeouts frequently seen in the wild.

DCN hardware provides 3 generic OTG interrupts that can be programmed to
fire on a specific line. Vline 0 and 1 are currently reserved, with
vline2 available to use for event delivery. These interrupts cannot
be masked, as long as the OTG is active.

[How]

Switch to vline2 for vblank handling. Today, DC will program the
vline2 position to at vupdate -- the point at which HW latches to
double-buffered registers.

Since all the vline interrupt types share the same interrupt src_id,
refactor the existing vline0 infrastructure to allow for all the vline0,
1, and 2 types.

Since this is intended to replace vstartup for DCN, use the same handler
logic, but be careful to leave DCE on vstartup.

Signed-off-by: Leo Li <sunpeng.li@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   2 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 165 ++++++++++++------
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   9 +
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |  20 ++-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c |  99 +++++++++--
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h |   7 +
 .../display/dc/irq/dcn10/irq_service_dcn10.c  |  44 +++--
 .../display/dc/irq/dcn20/irq_service_dcn20.c  |  43 +++--
 .../dc/irq/dcn201/irq_service_dcn201.c        |  24 ++-
 .../display/dc/irq/dcn21/irq_service_dcn21.c  |  44 +++--
 .../display/dc/irq/dcn30/irq_service_dcn30.c  |  44 +++--
 .../dc/irq/dcn302/irq_service_dcn302.c        |  43 +++--
 .../dc/irq/dcn303/irq_service_dcn303.c        |  24 ++-
 .../display/dc/irq/dcn31/irq_service_dcn31.c  |  44 +++--
 .../dc/irq/dcn314/irq_service_dcn314.c        |  44 +++--
 .../dc/irq/dcn315/irq_service_dcn315.c        |  44 +++--
 .../display/dc/irq/dcn32/irq_service_dcn32.c  |  26 +--
 .../display/dc/irq/dcn35/irq_service_dcn35.c  |  41 +++--
 .../dc/irq/dcn351/irq_service_dcn351.c        |  43 +++--
 .../display/dc/irq/dcn36/irq_service_dcn36.c  |  41 +++--
 .../dc/irq/dcn401/irq_service_dcn401.c        |  25 +--
 .../display/dc/irq/dcn42/irq_service_dcn42.c  |  26 +--
 .../gpu/drm/amd/display/dc/irq/irq_service.h  |  23 +++
 23 files changed, 673 insertions(+), 252 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 39894e38fee45..0d84293705107 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -947,7 +947,7 @@ struct amdgpu_device {
 	/* For pre-DCE11. DCE11 and later are in "struct amdgpu_device->dm" */
 	struct delayed_work         hotplug_work;
 	struct amdgpu_irq_src		crtc_irq;
-	struct amdgpu_irq_src		vline0_irq;
+	struct amdgpu_irq_src		vline_irq;
 	struct amdgpu_irq_src		vupdate_irq;
 	struct amdgpu_irq_src		pageflip_irq;
 	struct amdgpu_irq_src		hpd_irq;
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 3fa4dbda4517c..429f8df17c5d1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -646,7 +646,8 @@ static void dm_vupdate_high_irq(void *interrupt_params)
  * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK
  * event handler.
  */
-static void dm_crtc_high_irq(void *interrupt_params)
+static void __dm_crtc_high_irq(void *interrupt_params,
+			     int otg_inst)
 {
 	struct common_irq_params *irq_params = interrupt_params;
 	struct amdgpu_device *adev = irq_params->adev;
@@ -655,7 +656,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
 	unsigned long flags;
 	int vrr_active;
 
-	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
+	acrtc = get_crtc_by_otg_inst(adev, otg_inst);
 	if (!acrtc)
 		return;
 
@@ -755,6 +756,13 @@ static void dm_crtc_high_irq(void *interrupt_params)
 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
 }
 
+static void dm_crtc_high_irq(void *interrupt_params)
+{
+	struct common_irq_params *irq_params = interrupt_params;
+	__dm_crtc_high_irq(interrupt_params,
+			   irq_params->irq_src - DC_IRQ_SOURCE_VBLANK1);
+}
+
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
 /**
  * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
@@ -778,6 +786,17 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
 }
 #endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
 
+
+/**
+ * Same as dm_crtc_high_irq, but driven by the vline2 interrupt instead.
+ */
+static void dm_dcn_vertical_interrupt2_high_irq(void *interrupt_params)
+{
+	struct common_irq_params *irq_params = interrupt_params;
+	__dm_crtc_high_irq(interrupt_params,
+			   irq_params->irq_src - DC_IRQ_SOURCE_DC1_VLINE2);
+}
+
 /**
  * dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
  * @adev: amdgpu_device pointer
@@ -4752,15 +4771,13 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev)
 	return r;
 }
 
-/* Register IRQ sources and initialize IRQ callbacks */
-static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
+
+static int dcn10_register_vline_irq_handlers(struct amdgpu_device *adev)
 {
 	struct dc *dc = adev->dm.dc;
 	struct common_irq_params *c_irq_params;
 	struct dc_interrupt_params int_params = {0};
-	int r;
-	int i;
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+	int r, i;
 	static const unsigned int vrtl_int_srcid[] = {
 		DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
 		DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
@@ -4769,89 +4786,127 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
 		DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
 		DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL
 	};
+#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+	static const unsigned int vrtl0_int_ctxid[] = {
+		DCN_1_0__CTXID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
+		DCN_1_0__CTXID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
+		DCN_1_0__CTXID__OTG3_VERTICAL_INTERRUPT0_CONTROL,
+		DCN_1_0__CTXID__OTG4_VERTICAL_INTERRUPT0_CONTROL,
+		DCN_1_0__CTXID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
+		DCN_1_0__CTXID__OTG6_VERTICAL_INTERRUPT0_CONTROL
+	};
 #endif
+	static const unsigned int vrtl2_int_ctxid[] = {
+		DCN_1_0__CTXID__OTG1_VERTICAL_INTERRUPT2_CONTROL,
+		DCN_1_0__CTXID__OTG2_VERTICAL_INTERRUPT2_CONTROL,
+		DCN_1_0__CTXID__OTG3_VERTICAL_INTERRUPT2_CONTROL,
+		DCN_1_0__CTXID__OTG4_VERTICAL_INTERRUPT2_CONTROL,
+		DCN_1_0__CTXID__OTG5_VERTICAL_INTERRUPT2_CONTROL,
+		DCN_1_0__CTXID__OTG6_VERTICAL_INTERRUPT2_CONTROL
+	};
 
 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
 
-	/*
-	 * Actions of amdgpu_irq_add_id():
-	 * 1. Register a set() function with base driver.
-	 *    Base driver will call set() function to enable/disable an
-	 *    interrupt in DC hardware.
-	 * 2. Register amdgpu_dm_irq_handler().
-	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
-	 *    coming from DC hardware.
-	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
-	 *    for acknowledging and handling.
-	 */
-
-	/* Use VSTARTUP interrupt */
-	for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP;
-			i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1;
-			i++) {
-		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq);
+	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
+		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
+				vrtl_int_srcid[i], &adev->vline_irq);
 
 		if (r) {
-			drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n");
+			drm_err(adev_to_drm(adev),
+				"Failed to add vline0/1/2 irq id!\n");
 			return r;
 		}
 
+#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+		/* Register vline0 */
 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
 		int_params.irq_source =
-			dc_interrupt_to_irq_source(dc, i, 0);
+			dc_interrupt_to_irq_source(dc,
+						   vrtl_int_srcid[i],
+						   vrtl0_int_ctxid[i]);
 
 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
-			int_params.irq_source  < DC_IRQ_SOURCE_VBLANK1 ||
-			int_params.irq_source  > DC_IRQ_SOURCE_VBLANK6) {
-			drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n");
+			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 ||
+			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) {
+			drm_err(adev_to_drm(adev),
+				"Failed to register vline0 irq!\n");
 			return -EINVAL;
 		}
 
-		c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
+		c_irq_params = &adev->dm.vline0_params[int_params.irq_source
+					- DC_IRQ_SOURCE_DC1_VLINE0];
 
 		c_irq_params->adev = adev;
 		c_irq_params->irq_src = int_params.irq_source;
 
 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
-			dm_crtc_high_irq, c_irq_params))
+			dm_dcn_vertical_interrupt0_high_irq,
+			c_irq_params))
 			return -ENOMEM;
-	}
-
-	/* Use otg vertical line interrupt */
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
-		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
-				vrtl_int_srcid[i], &adev->vline0_irq);
-
-		if (r) {
-			drm_err(adev_to_drm(adev), "Failed to add vline0 irq id!\n");
-			return r;
-		}
-
+#endif
+		/*
+		 * vline2 shares the same srcids as vline0, but different ctxid.
+		 */
 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
 		int_params.irq_source =
-			dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0);
+			dc_interrupt_to_irq_source(dc,
+						   vrtl_int_srcid[i],
+						   vrtl2_int_ctxid[i]);
 
 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
-			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 ||
-			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) {
-			drm_err(adev_to_drm(adev), "Failed to register vline0 irq!\n");
+			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE2 ||
+			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE2) {
+			drm_err(adev_to_drm(adev),
+				"Failed to register vline2 irq!\n");
 			return -EINVAL;
 		}
 
-		c_irq_params = &adev->dm.vline0_params[int_params.irq_source
-					- DC_IRQ_SOURCE_DC1_VLINE0];
+		c_irq_params = &adev->dm.vline2_params[int_params.irq_source
+					- DC_IRQ_SOURCE_DC1_VLINE2];
 
 		c_irq_params->adev = adev;
 		c_irq_params->irq_src = int_params.irq_source;
 
 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
-			dm_dcn_vertical_interrupt0_high_irq,
+			dm_dcn_vertical_interrupt2_high_irq,
 			c_irq_params))
 			return -ENOMEM;
 	}
-#endif
+
+	return 0;
+}
+
+/* Register IRQ sources and initialize IRQ callbacks */
+static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
+{
+	struct dc *dc = adev->dm.dc;
+	struct common_irq_params *c_irq_params;
+	struct dc_interrupt_params int_params = {0};
+	int r;
+	int i;
+
+	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
+	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
+
+	/*
+	 * Actions of amdgpu_irq_add_id():
+	 * 1. Register a set() function with base driver.
+	 *    Base driver will call set() function to enable/disable an
+	 *    interrupt in DC hardware.
+	 * 2. Register amdgpu_dm_irq_handler().
+	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
+	 *    coming from DC hardware.
+	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
+	 *    for acknowledging and handling.
+	 */
+
+	r = dcn10_register_vline_irq_handlers(adev);
+	if (r) {
+		drm_err(adev_to_drm(adev),
+			"Failed to register vline interrupts\n");
+		return r;
+	}
 
 	/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to
 	 * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx
@@ -9541,7 +9596,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
 			if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type))
 				drm_err(dev, "DM_IRQ: Cannot get pageflip irq!\n");
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-			if (amdgpu_irq_get(adev, &adev->vline0_irq, irq_type))
+			if (amdgpu_irq_get(adev, &adev->vline_irq,
+					   DM_VLINE_IRQ(adev, 0, irq_type)))
 				drm_err(dev, "DM_IRQ: Cannot get vline0 irq!\n");
 #endif
 		}
@@ -9554,7 +9610,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
 		case IP_VERSION(3, 0, 3):
 		case IP_VERSION(3, 2, 0):
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-			if (amdgpu_irq_put(adev, &adev->vline0_irq, irq_type))
+			if (amdgpu_irq_put(adev, &adev->vline_irq,
+					   DM_VLINE_IRQ(adev, 0, irq_type)))
 				drm_err(dev, "DM_IRQ: Cannot put vline0 irq!\n");
 #endif
 			if (amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type))
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 1e0ccf58cdb8d..b4e785784a882 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -543,6 +543,15 @@ struct amdgpu_display_manager {
 	struct common_irq_params
 	vline0_params[DC_IRQ_SOURCE_DC6_VLINE0 - DC_IRQ_SOURCE_DC1_VLINE0 + 1];
 
+	/**
+	 * @vline2_params:
+	 *
+	 * OTG vertical interrupt0 IRQ parameters, passed to registered
+	 * handlers when triggered.
+	 */
+	struct common_irq_params
+	vline2_params[DC_IRQ_SOURCE_DC6_VLINE2 - DC_IRQ_SOURCE_DC1_VLINE2 + 1];
+
 	/**
 	 * @vupdate_params:
 	 *
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index efb19f675b0c2..0821b0996a85f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -28,6 +28,7 @@
 
 #include "dc.h"
 #include "amdgpu.h"
+#include "amdgpu_dm_irq.h"
 #include "amdgpu_dm_psr.h"
 #include "amdgpu_dm_replay.h"
 #include "amdgpu_dm_crtc.h"
@@ -290,10 +291,19 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
 
 	/* crtc vblank or vstartup interrupt */
 	if (enable) {
-		rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
+		/* vline only available on DCN+ */
+		if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0)
+			rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
+		else
+			rc = amdgpu_irq_get(adev, &adev->vline_irq,
+					    DM_VLINE_IRQ(adev, 2, irq_type));
 		drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc);
 	} else {
-		rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
+		if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0)
+			rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
+		else
+			rc = amdgpu_irq_put(adev, &adev->vline_irq,
+					    DM_VLINE_IRQ(adev, 2, irq_type));
 		drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc);
 	}
 
@@ -323,10 +333,12 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
 	/* crtc vline0 interrupt, only available on DCN+ */
 	if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
 		if (enable) {
-			rc = amdgpu_irq_get(adev, &adev->vline0_irq, irq_type);
+			rc = amdgpu_irq_get(adev, &adev->vline_irq,
+					    DM_VLINE_IRQ(adev, 0, irq_type));
 			drm_dbg_vbl(crtc->dev, "Get vline0_irq ret=%d\n", rc);
 		} else {
-			rc = amdgpu_irq_put(adev, &adev->vline0_irq, irq_type);
+			rc = amdgpu_irq_put(adev, &adev->vline_irq,
+					    DM_VLINE_IRQ(adev, 0, irq_type));
 			drm_dbg_vbl(crtc->dev, "Put vline0_irq ret=%d\n", rc);
 		}
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index 5948e2a6219e3..757529af72ceb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -769,18 +769,86 @@ static int amdgpu_dm_set_crtc_irq_state(struct amdgpu_device *adev,
 		__func__);
 }
 
-static int amdgpu_dm_set_vline0_irq_state(struct amdgpu_device *adev,
-					struct amdgpu_irq_src *source,
-					unsigned int crtc_id,
-					enum amdgpu_interrupt_state state)
+/**
+ * amdgpu_dm_set_vline_irq_state: Set interrupt state for vline
+ *
+ * Map base driver amdgpu_irq_update() -- called per interrupt src ID -- to
+ * their corresponding dc_irq_source, then set then to the requested state.
+ *
+ * Since all the vline0/1/2 interrupts have the same src_id, the standard
+ * amdgpu_irq_src.num_types mapping to the number of OTGs won't work. For vline,
+ * num_types will have to cover (number of different vline interrupt types) *
+ * (number of OTGs) types. For example, if there are 6 OTGS, then num_types =
+ * 3*6 = 18.
+ *
+ * This is only needed for the amdgpu_irq_src_funcs.set_irq implementation; the
+ * .process implementation is provided the interrupt vector, which contains both
+ * the src_id and ctx_id to uniquely map to the dc_irq_source.
+ *
+ * The vline_otg_id mapping is first by vline num, then by OTG num:
+ *
+ * | vline_otg_id | vline num | otg num |
+ * |--------------|-----------|---------|
+ * | 0            | 0         | 0       |
+ * | 1            | 0         | 1       |
+ * | ...          | ...       | ...     |
+ * | 5            | 0         | 5       |
+ * | 6            | 1         | 0       |
+ * | ...          | ...       | ...     |
+ * | 11           | 1         | 5       |
+ * | 12           | 2         | 0       |
+ * | ...          | ...       | ...     |
+ * | 17           | 2         | 5       |
+ */
+static int amdgpu_dm_set_vline_irq_state(struct amdgpu_device *adev,
+					 struct amdgpu_irq_src *source,
+					 unsigned int vline_otg_id,
+					 enum amdgpu_interrupt_state state)
 {
-	return dm_irq_state(
-		adev,
-		source,
-		crtc_id,
-		state,
-		IRQ_TYPE_VLINE0,
-		__func__);
+	bool st;
+	unsigned int vline_num, otg_num;
+	enum dc_irq_source irq_source;
+	struct dc *dc = adev->dm.dc;
+	struct amdgpu_crtc *acrtc;
+
+	if (vline_otg_id >= 3 * adev->mode_info.num_crtc) {
+		drm_err(adev_to_drm(adev),
+			"Invalid vline map_id :%d\n", vline_otg_id);
+		return -EINVAL;
+	}
+
+	vline_num = vline_otg_id / adev->mode_info.num_crtc;
+	otg_num = vline_otg_id % adev->mode_info.num_crtc;
+	acrtc = adev->mode_info.crtcs[otg_num];
+
+	if (!acrtc) {
+		drm_err(adev_to_drm(adev),
+			"crtc is NULL at id : %d\n", otg_num);
+		return 0;
+	}
+
+	if (acrtc->otg_inst == -1)
+		return 0;
+
+	if (vline_num == 0)
+		irq_source = IRQ_TYPE_VLINE0 + otg_num;
+	else if (vline_num == 1)
+		irq_source = IRQ_TYPE_VLINE1 + otg_num;
+	else if (vline_num == 2)
+		irq_source = IRQ_TYPE_VLINE2 + otg_num;
+	else {
+		drm_err(adev_to_drm(adev),
+			"Invalid vline num :%d\n", vline_num);
+		return -EINVAL;
+	}
+
+	st = (state == AMDGPU_IRQ_STATE_ENABLE);
+
+	if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
+		dc_allow_idle_optimizations(dc, false);
+
+	dc_interrupt_set(adev->dm.dc, irq_source, st);
+	return 0;
 }
 
 static int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *adev,
@@ -826,8 +894,8 @@ static const struct amdgpu_irq_src_funcs dm_crtc_irq_funcs = {
 	.process = amdgpu_dm_irq_handler,
 };
 
-static const struct amdgpu_irq_src_funcs dm_vline0_irq_funcs = {
-	.set = amdgpu_dm_set_vline0_irq_state,
+static const struct amdgpu_irq_src_funcs dm_vline_irq_funcs = {
+	.set = amdgpu_dm_set_vline_irq_state,
 	.process = amdgpu_dm_irq_handler,
 };
 
@@ -861,8 +929,9 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
 	adev->crtc_irq.num_types = adev->mode_info.num_crtc;
 	adev->crtc_irq.funcs = &dm_crtc_irq_funcs;
 
-	adev->vline0_irq.num_types = adev->mode_info.num_crtc;
-	adev->vline0_irq.funcs = &dm_vline0_irq_funcs;
+	/* Number of vline types * num OTGs */
+	adev->vline_irq.num_types = 3 * adev->mode_info.num_crtc;
+	adev->vline_irq.funcs = &dm_vline_irq_funcs;
 
 	adev->dmub_outbox_irq.num_types = 1;
 	adev->dmub_outbox_irq.funcs = &dm_dmub_outbox_irq_funcs;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
index 4f6b58f4f90d7..a672b58b0f760 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
@@ -27,6 +27,13 @@
 
 #include "irq_types.h" /* DAL irq definitions */
 
+/*
+ * Get OTG vline irq id from vline num and otg num. See also
+ * amdgpu_dm_set_vline_irq_state()
+ */
+#define DM_VLINE_IRQ(adev, vline_num, otg_num) \
+	adev->mode_info.num_crtc * vline_num + otg_num
+
 /*
  * Display Manager IRQ-related interfaces (for use by DAL).
  */
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
index 7dff8731f414e..a72fefb531e99 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
@@ -58,18 +58,6 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct irq_service *irq_servic
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE1;
 	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
@@ -95,6 +83,19 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct irq_service *irq_servic
 	case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP6;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -157,6 +158,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
 	.set = NULL,
 	.ack = NULL
@@ -239,6 +245,14 @@ static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dummy_irq_entry() \
 	{\
 		.funcs = &dummy_irq_info_funcs\
@@ -353,6 +367,12 @@ irq_source_info_dcn10[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	vline0_int_entry(4),
 	vline0_int_entry(5),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
+	vline2_int_entry(4),
+	vline2_int_entry(5),
 };
 
 static const struct irq_service_funcs irq_service_funcs_dcn10 = {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
index 34f9e8a9f488f..cbf65367cba5c 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
@@ -59,18 +59,6 @@ static enum dc_irq_source to_dal_irq_source_dcn20(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -96,6 +84,19 @@ static enum dc_irq_source to_dal_irq_source_dcn20(
 	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE6;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -163,6 +164,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -244,6 +250,13 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
 #define dummy_irq_entry() \
 	{\
 		.funcs = &dummy_irq_info_funcs\
@@ -358,6 +371,12 @@ irq_source_info_dcn20[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	vline0_int_entry(4),
 	vline0_int_entry(5),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
+	vline2_int_entry(4),
+	vline2_int_entry(5),
 };
 
 static const struct irq_service_funcs irq_service_funcs_dcn20 = {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
index 6417011d22463..7ab8317961734 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
@@ -47,10 +47,6 @@ static enum dc_irq_source to_dal_irq_source_dcn201(
 		return DC_IRQ_SOURCE_VBLANK1;
 	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK2;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -59,6 +55,12 @@ static enum dc_irq_source to_dal_irq_source_dcn201(
 		return DC_IRQ_SOURCE_VUPDATE1;
 	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE2;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -104,6 +106,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.set = NULL,
 	.ack = NULL
 };
+
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
 static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
 	.set = NULL,
 	.ack = NULL
@@ -195,6 +202,13 @@ static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
 #define dummy_irq_entry() \
 	{\
 		.funcs = &dummy_irq_info_funcs\
@@ -309,6 +323,8 @@ irq_source_info_dcn201[DAL_IRQ_SOURCES_NUMBER] = {
 	dummy_irq_entry(),
 	dummy_irq_entry(),
 	dummy_irq_entry(),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
 };
 
 static const struct irq_service_funcs irq_service_funcs_dcn201 = {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
index 05f7877d2d6c8..da1ebb9467c9d 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
@@ -60,18 +60,6 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct irq_service *irq_servic
 		return DC_IRQ_SOURCE_VBLANK6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -97,6 +85,19 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct irq_service *irq_servic
 	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE6;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -170,6 +171,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
 
@@ -266,6 +272,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dmub_outbox_int_entry()\
 	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
 		IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
@@ -385,6 +399,12 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	vline0_int_entry(4),
 	vline0_int_entry(5),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
+	vline2_int_entry(4),
+	vline2_int_entry(5),
 	dmub_outbox_int_entry(),
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
index 3a7f76364000e..d4af3555d14ef 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
@@ -68,18 +68,6 @@ static enum dc_irq_source to_dal_irq_source_dcn30(
 		return DC_IRQ_SOURCE_VBLANK6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -105,6 +93,19 @@ static enum dc_irq_source to_dal_irq_source_dcn30(
 	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE6;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -177,6 +178,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -280,6 +286,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dummy_irq_entry() \
 	{\
 		.funcs = &dummy_irq_info_funcs\
@@ -394,6 +408,12 @@ irq_source_info_dcn30[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	vline0_int_entry(4),
 	vline0_int_entry(5),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
+	vline2_int_entry(4),
+	vline2_int_entry(5),
 	dmub_trace_int_entry(),
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
index f4dfc96310c73..14631b78715a0 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
@@ -55,18 +55,6 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct irq_service *irq_servi
 		return DC_IRQ_SOURCE_VBLANK6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -92,6 +80,19 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct irq_service *irq_servi
 	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE6;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -164,6 +165,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -262,6 +268,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
 
 #define i2c_int_entry(reg_num) \
@@ -363,6 +377,11 @@ static const struct irq_source_info irq_source_info_dcn302[DAL_IRQ_SOURCES_NUMBE
 		vline0_int_entry(2),
 		vline0_int_entry(3),
 		vline0_int_entry(4),
+		vline2_int_entry(0),
+		vline2_int_entry(1),
+		vline2_int_entry(2),
+		vline2_int_entry(3),
+		vline2_int_entry(4),
 		dmub_trace_int_entry(),
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
index fdc7624461ac2..bd4768afafe43 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
@@ -46,10 +46,6 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_servi
 		return DC_IRQ_SOURCE_VBLANK1;
 	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK2;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -59,6 +55,11 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_servi
 	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 		return DC_IRQ_SOURCE_VUPDATE2;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -110,6 +111,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -186,6 +192,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
 
 #define i2c_int_entry(reg_num) \
@@ -260,6 +274,8 @@ static const struct irq_source_info irq_source_info_dcn303[DAL_IRQ_SOURCES_NUMBE
 		vblank_int_entry(1),
 		vline0_int_entry(0),
 		vline0_int_entry(1),
+		vline2_int_entry(0),
+		vline2_int_entry(1),
 };
 
 static const struct irq_service_funcs irq_service_funcs_dcn303 = {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
index 5fecd03f94999..9704f90cd0407 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
@@ -56,18 +56,6 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct irq_service *irq_servic
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -94,6 +82,20 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct irq_service *irq_servic
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -166,6 +168,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -260,6 +267,15 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
 		.funcs = &vline0_irq_info_funcs\
 	}
+
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dmub_outbox_int_entry()\
 	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
 		IRQ_REG_ENTRY_DMUB(\
@@ -376,6 +392,10 @@ irq_source_info_dcn31[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
 	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
 	dmub_outbox_int_entry(),
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
index a214f13c5a978..afa4a17ce2f0e 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
@@ -58,18 +58,6 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct irq_service *irq_servi
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -96,6 +84,20 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct irq_service *irq_servi
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -168,6 +170,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -262,6 +269,15 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
 		.funcs = &vline0_irq_info_funcs\
 	}
+
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dmub_outbox_int_entry()\
 	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
 		IRQ_REG_ENTRY_DMUB(\
@@ -378,6 +394,10 @@ irq_source_info_dcn314[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
 	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
 	dmub_outbox_int_entry(),
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
index dc2dced7db85d..b64fada140fb0 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
@@ -63,18 +63,6 @@ static enum dc_irq_source to_dal_irq_source_dcn315(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -101,6 +89,20 @@ static enum dc_irq_source to_dal_irq_source_dcn315(
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -173,6 +175,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -267,6 +274,15 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
 		.funcs = &vline0_irq_info_funcs\
 	}
+
+#define vline2_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		.funcs = &vline2_irq_info_funcs\
+	}
+
 #define dmub_outbox_int_entry()\
 	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
 		IRQ_REG_ENTRY_DMUB(\
@@ -383,6 +399,10 @@ irq_source_info_dcn315[DAL_IRQ_SOURCES_NUMBER] = {
 	vline0_int_entry(3),
 	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
 	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
+	vline2_int_entry(0),
+	vline2_int_entry(1),
+	vline2_int_entry(2),
+	vline2_int_entry(3),
 	dmub_outbox_int_entry(),
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
index 3090ceb664332..f347e2ab7ced3 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
@@ -57,18 +57,6 @@ static enum dc_irq_source to_dal_irq_source_dcn32(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -95,6 +83,20 @@ static enum dc_irq_source to_dal_irq_source_dcn32(
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
index 27289279b21ca..d70754f6ac0b6 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
@@ -55,18 +55,6 @@ static enum dc_irq_source to_dal_irq_source_dcn35(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -93,6 +81,20 @@ static enum dc_irq_source to_dal_irq_source_dcn35(
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -165,6 +167,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
 
@@ -249,6 +256,12 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
 		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
 
+#define vline2_int_entry(reg_num)\
+		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs = &vline2_irq_info_funcs\
+
 #define dmub_outbox_int_entry()\
 		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
 			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
@@ -362,6 +375,10 @@ static struct irq_source_info_funcs dummy_irq_info_funcs = {
 	vline0_int_entry(3); \
 	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
 	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
+	vline2_int_entry(0); \
+	vline2_int_entry(1); \
+	vline2_int_entry(2); \
+	vline2_int_entry(3); \
 	dmub_outbox_int_entry()
 
 #define dcn35_irq_init() \
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
index 7404b572a4e96..8948cbb03011e 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
@@ -4,8 +4,6 @@
 #include "dm_services.h"
 #include "include/logger_interface.h"
 #include "../dce110/irq_service_dce110.h"
-
-
 #include "dcn/dcn_3_5_1_offset.h"
 #include "dcn/dcn_3_5_1_sh_mask.h"
 
@@ -34,18 +32,6 @@ static enum dc_irq_source to_dal_irq_source_dcn351(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -72,6 +58,20 @@ static enum dc_irq_source to_dal_irq_source_dcn351(
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -144,6 +144,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
 
@@ -228,6 +233,12 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
 		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
 
+#define vline2_int_entry(reg_num)\
+		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs = &vline2_irq_info_funcs\
+
 #define dmub_outbox_int_entry()\
 		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
 			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
@@ -342,6 +353,10 @@ static struct irq_source_info_funcs dummy_irq_info_funcs = {
 	vline0_int_entry(3); \
 	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
 	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
+	vline2_int_entry(0); \
+	vline2_int_entry(1); \
+	vline2_int_entry(2); \
+	vline2_int_entry(3); \
 	dmub_outbox_int_entry(); \
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
index 3dd47a99f568d..5525a69d0ffd2 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
@@ -33,18 +33,6 @@ static enum dc_irq_source to_dal_irq_source_dcn36(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -71,6 +59,20 @@ static enum dc_irq_source to_dal_irq_source_dcn36(
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
@@ -143,6 +145,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 	.ack = NULL
 };
 
+static struct irq_source_info_funcs vline2_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
 
@@ -227,6 +234,12 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
 			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
 		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
 
+#define vline2_int_entry(reg_num)\
+		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
+		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs = &vline2_irq_info_funcs\
+
 #define dmub_outbox_int_entry()\
 		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
 			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
@@ -339,6 +352,10 @@ static struct irq_source_info_funcs dummy_irq_info_funcs = {
 	vline0_int_entry(1); \
 	vline0_int_entry(2); \
 	vline0_int_entry(3); \
+	vline2_int_entry(0); \
+	vline2_int_entry(1); \
+	vline2_int_entry(2); \
+	vline2_int_entry(3); \
 	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
 	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
 	dmub_outbox_int_entry(); \
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
index 42d9d42ba0b99..ce264333e3cf4 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
@@ -36,18 +36,6 @@ static enum dc_irq_source to_dal_irq_source_dcn401(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -75,6 +63,19 @@ static enum dc_irq_source to_dal_irq_source_dcn401(
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
 
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
index f4d1ce9079ded..f9113d9f3c3ee 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
@@ -35,18 +35,6 @@ static enum dc_irq_source to_dal_irq_source_dcn42(
 		return DC_IRQ_SOURCE_VBLANK5;
 	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK6;
-	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC1_VLINE0;
-	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC2_VLINE0;
-	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC3_VLINE0;
-	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC4_VLINE0;
-	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC5_VLINE0;
-	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
-		return DC_IRQ_SOURCE_DC6_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -73,6 +61,20 @@ static enum dc_irq_source to_dal_irq_source_dcn42(
 		return DC_IRQ_SOURCE_VUPDATE6;
 	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+
+	case DCN_VINT_SRCID(1, 0):
+		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
+	case DCN_VINT_SRCID(2, 0):
+		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
+	case DCN_VINT_SRCID(3, 0):
+		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
+	case DCN_VINT_SRCID(4, 0):
+		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
+	case DCN_VINT_SRCID(5, 0):
+		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
+	case DCN_VINT_SRCID(6, 0):
+		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
+
 	case DCN_1_0__SRCID__DC_HPD1_INT:
 		/* generic src_id for all HPD and HPDRX interrupts */
 		switch (ext_id) {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
index bbcef3d2fe334..ba2bca88e4ccb 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
+++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
@@ -30,6 +30,29 @@
 
 #include "irq_types.h"
 
+/*
+ * Helper to get vertical interrupt src/ctx id by OTG instance and vint number
+ */
+#define DCN_VINT_SRCID(otg_inst, vint_num) \
+	DCN_1_0__SRCID__OTG ## otg_inst ## _VERTICAL_INTERRUPT ## vint_num ## _CONTROL
+#define DCN_VINT_CTXID(otg_inst, vint_num) \
+	DCN_1_0__CTXID__OTG ## otg_inst ## _VERTICAL_INTERRUPT ## vint_num ## _CONTROL
+#define DC_VINT_IRQSRC(otg_inst, vint_num) \
+	DC_IRQ_SOURCE_DC ## otg_inst ## _VLINE ## vint_num
+
+/* Helper to map vertical interrupt src/ctx id to DC irq source enum */
+#define DCN_VINT_TO_DC_IRQSRC(otg_inst, ext_id) \
+	switch (ext_id) { \
+	case DCN_VINT_CTXID(otg_inst, 0): \
+		return DC_VINT_IRQSRC(otg_inst, 0); \
+	case DCN_VINT_CTXID(otg_inst, 1): \
+		return DC_VINT_IRQSRC(otg_inst, 1); \
+	case DCN_VINT_CTXID(otg_inst, 2): \
+		return DC_VINT_IRQSRC(otg_inst, 2); \
+	default: \
+		return DC_IRQ_SOURCE_INVALID; \
+	}
+
 struct irq_service;
 struct irq_source_info;
 
-- 
2.53.0


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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-04 18:36 [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup sunpeng.li
@ 2026-05-04 20:54 ` Timur Kristóf
  2026-05-06 20:00   ` Leo Li
  2026-05-10  6:06 ` Shengyu Qu
  1 sibling, 1 reply; 9+ messages in thread
From: Timur Kristóf @ 2026-05-04 20:54 UTC (permalink / raw)
  To: amd-gfx
  Cc: Harry.Wentland, Aurabindo.Pillai, mario.limonciello, wiagn233,
	sysdadmin, Leo Li, sunpeng.li

On Monday, May 4, 2026 8:36:49 PM Central European Summer Time 
sunpeng.li@amd.com wrote:
> From: Leo Li <sunpeng.li@amd.com>
> 
> [Why]
> 
> VStartup is an OTG event that fires when the pixel pipeline prepares for
> pixel scanout of the next frame. It was previously used to deliver
> vblank events for commits that do not trigger a fb address update, and
> hence a pflip interrupt (hw cursor updates, for example).
> 
> The issue with vstartup is that HW can mask the interrupt in cases where
> idle optimizations are enabled or when a HW lock is active. This could
> the explain the range of flip_done timeouts frequently seen in the wild.

Can you help me understand how that could happen with vstartup?
Specifically, what is a "HW lock" and when is it active?

Many users have experienced flip_done timeouts while playing games.
In that scenario, would any idle optimization be enabled or is there a "HW 
lock"?

> DCN hardware provides 3 generic OTG interrupts that can be programmed to
> fire on a specific line. Vline 0 and 1 are currently reserved, with
> vline2 available to use for event delivery. These interrupts cannot
> be masked, as long as the OTG is active.
> 
> [How]
> 
> Switch to vline2 for vblank handling. Today, DC will program the
> vline2 position to at vupdate -- the point at which HW latches to
> double-buffered registers.
> 
> Since all the vline interrupt types share the same interrupt src_id,
> refactor the existing vline0 infrastructure to allow for all the vline0,
> 1, and 2 types.
> 
> Since this is intended to replace vstartup for DCN, use the same handler
> logic, but be careful to leave DCE on vstartup.

Why not also switch DCE?
Does DCE not have the vline interrupts or does it not have the same issue with 
the vstartup interrupt?

> 
> Signed-off-by: Leo Li <sunpeng.li@amd.com>

I think this patch should have a "Fixes:" tag or another way to indicate that 
it should be backported to stable kernels.

Thanks,
Timur

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   2 +-
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 165 ++++++++++++------
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   9 +
>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |  20 ++-
>  .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c |  99 +++++++++--
>  .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h |   7 +
>  .../display/dc/irq/dcn10/irq_service_dcn10.c  |  44 +++--
>  .../display/dc/irq/dcn20/irq_service_dcn20.c  |  43 +++--
>  .../dc/irq/dcn201/irq_service_dcn201.c        |  24 ++-
>  .../display/dc/irq/dcn21/irq_service_dcn21.c  |  44 +++--
>  .../display/dc/irq/dcn30/irq_service_dcn30.c  |  44 +++--
>  .../dc/irq/dcn302/irq_service_dcn302.c        |  43 +++--
>  .../dc/irq/dcn303/irq_service_dcn303.c        |  24 ++-
>  .../display/dc/irq/dcn31/irq_service_dcn31.c  |  44 +++--
>  .../dc/irq/dcn314/irq_service_dcn314.c        |  44 +++--
>  .../dc/irq/dcn315/irq_service_dcn315.c        |  44 +++--
>  .../display/dc/irq/dcn32/irq_service_dcn32.c  |  26 +--
>  .../display/dc/irq/dcn35/irq_service_dcn35.c  |  41 +++--
>  .../dc/irq/dcn351/irq_service_dcn351.c        |  43 +++--
>  .../display/dc/irq/dcn36/irq_service_dcn36.c  |  41 +++--
>  .../dc/irq/dcn401/irq_service_dcn401.c        |  25 +--
>  .../display/dc/irq/dcn42/irq_service_dcn42.c  |  26 +--
>  .../gpu/drm/amd/display/dc/irq/irq_service.h  |  23 +++
>  23 files changed, 673 insertions(+), 252 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 39894e38fee45..0d84293705107
> 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -947,7 +947,7 @@ struct amdgpu_device {
>  	/* For pre-DCE11. DCE11 and later are in "struct amdgpu_device-
>dm" */
>  	struct delayed_work         hotplug_work;
>  	struct amdgpu_irq_src		crtc_irq;
> -	struct amdgpu_irq_src		vline0_irq;
> +	struct amdgpu_irq_src		vline_irq;
>  	struct amdgpu_irq_src		vupdate_irq;
>  	struct amdgpu_irq_src		pageflip_irq;
>  	struct amdgpu_irq_src		hpd_irq;
> 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
> 3fa4dbda4517c..429f8df17c5d1 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -646,7 +646,8 @@ static void dm_vupdate_high_irq(void *interrupt_params)
>   * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK
>   * event handler.
>   */
> -static void dm_crtc_high_irq(void *interrupt_params)
> +static void __dm_crtc_high_irq(void *interrupt_params,
> +			     int otg_inst)
>  {
>  	struct common_irq_params *irq_params = interrupt_params;
>  	struct amdgpu_device *adev = irq_params->adev;
> @@ -655,7 +656,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
>  	unsigned long flags;
>  	int vrr_active;
> 
> -	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - 
IRQ_TYPE_VBLANK);
> +	acrtc = get_crtc_by_otg_inst(adev, otg_inst);
>  	if (!acrtc)
>  		return;
> 
> @@ -755,6 +756,13 @@ static void dm_crtc_high_irq(void *interrupt_params)
>  	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
>  }
> 
> +static void dm_crtc_high_irq(void *interrupt_params)
> +{
> +	struct common_irq_params *irq_params = interrupt_params;
> +	__dm_crtc_high_irq(interrupt_params,
> +			   irq_params->irq_src - 
DC_IRQ_SOURCE_VBLANK1);
> +}
> +
>  #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
>  /**
>   * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0
> for @@ -778,6 +786,17 @@ static void
> dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params) }
>  #endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
> 
> +
> +/**
> + * Same as dm_crtc_high_irq, but driven by the vline2 interrupt instead.
> + */
> +static void dm_dcn_vertical_interrupt2_high_irq(void *interrupt_params)
> +{
> +	struct common_irq_params *irq_params = interrupt_params;
> +	__dm_crtc_high_irq(interrupt_params,
> +			   irq_params->irq_src - 
DC_IRQ_SOURCE_DC1_VLINE2);
> +}
> +
>  /**
>   * dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
>   * @adev: amdgpu_device pointer
> @@ -4752,15 +4771,13 @@ static int dce110_register_irq_handlers(struct
> amdgpu_device *adev) return r;
>  }
> 
> -/* Register IRQ sources and initialize IRQ callbacks */
> -static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
> +
> +static int dcn10_register_vline_irq_handlers(struct amdgpu_device *adev)
>  {
>  	struct dc *dc = adev->dm.dc;
>  	struct common_irq_params *c_irq_params;
>  	struct dc_interrupt_params int_params = {0};
> -	int r;
> -	int i;
> -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> +	int r, i;
>  	static const unsigned int vrtl_int_srcid[] = {
>  		DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
>  		DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
> @@ -4769,89 +4786,127 @@ static int dcn10_register_irq_handlers(struct
> amdgpu_device *adev) DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
>  		DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL
>  	};
> +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> +	static const unsigned int vrtl0_int_ctxid[] = {
> +		DCN_1_0__CTXID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG3_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG4_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG6_VERTICAL_INTERRUPT0_CONTROL
> +	};
>  #endif
> +	static const unsigned int vrtl2_int_ctxid[] = {
> +		DCN_1_0__CTXID__OTG1_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG2_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG3_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG4_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG5_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG6_VERTICAL_INTERRUPT2_CONTROL
> +	};
> 
>  	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
>  	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
> 
> -	/*
> -	 * Actions of amdgpu_irq_add_id():
> -	 * 1. Register a set() function with base driver.
> -	 *    Base driver will call set() function to enable/disable an
> -	 *    interrupt in DC hardware.
> -	 * 2. Register amdgpu_dm_irq_handler().
> -	 *    Base driver will call amdgpu_dm_irq_handler() for ALL 
interrupts
> -	 *    coming from DC hardware.
> -	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
> -	 *    for acknowledging and handling.
> -	 */
> -
> -	/* Use VSTARTUP interrupt */
> -	for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP;
> -			i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + 
adev->mode_info.num_crtc - 1;
> -			i++) {
> -		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, 
&adev->crtc_irq);
> +	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
> +		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
> +				vrtl_int_srcid[i], &adev-
>vline_irq);
> 
>  		if (r) {
> -			drm_err(adev_to_drm(adev), "Failed to add 
crtc irq id!\n");
> +			drm_err(adev_to_drm(adev),
> +				"Failed to add vline0/1/2 irq id!
\n");
>  			return r;
>  		}
> 
> +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> +		/* Register vline0 */
>  		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
>  		int_params.irq_source =
> -			dc_interrupt_to_irq_source(dc, i, 0);
> +			dc_interrupt_to_irq_source(dc,
> +						   
vrtl_int_srcid[i],
> +						   
vrtl0_int_ctxid[i]);
> 
>  		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
> -			int_params.irq_source  < 
DC_IRQ_SOURCE_VBLANK1 ||
> -			int_params.irq_source  > 
DC_IRQ_SOURCE_VBLANK6) {
> -			drm_err(adev_to_drm(adev), "Failed to 
register vblank irq!\n");
> +			int_params.irq_source < 
DC_IRQ_SOURCE_DC1_VLINE0 ||
> +			int_params.irq_source > 
DC_IRQ_SOURCE_DC6_VLINE0) {
> +			drm_err(adev_to_drm(adev),
> +				"Failed to register vline0 irq!
\n");
>  			return -EINVAL;
>  		}
> 
> -		c_irq_params = &adev-
>dm.vblank_params[int_params.irq_source -
> DC_IRQ_SOURCE_VBLANK1]; +		c_irq_params =
> &adev->dm.vline0_params[int_params.irq_source
> +					- 
DC_IRQ_SOURCE_DC1_VLINE0];
> 
>  		c_irq_params->adev = adev;
>  		c_irq_params->irq_src = int_params.irq_source;
> 
>  		if (!amdgpu_dm_irq_register_interrupt(adev, 
&int_params,
> -			dm_crtc_high_irq, c_irq_params))
> +			dm_dcn_vertical_interrupt0_high_irq,
> +			c_irq_params))
>  			return -ENOMEM;
> -	}
> -
> -	/* Use otg vertical line interrupt */
> -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> -	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
> -		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
> -				vrtl_int_srcid[i], &adev-
>vline0_irq);
> -
> -		if (r) {
> -			drm_err(adev_to_drm(adev), "Failed to add 
vline0 irq id!\n");
> -			return r;
> -		}
> -
> +#endif
> +		/*
> +		 * vline2 shares the same srcids as vline0, but different 
ctxid.
> +		 */
>  		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
>  		int_params.irq_source =
> -			dc_interrupt_to_irq_source(dc, 
vrtl_int_srcid[i], 0);
> +			dc_interrupt_to_irq_source(dc,
> +						   
vrtl_int_srcid[i],
> +						   
vrtl2_int_ctxid[i]);
> 
>  		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
> -			int_params.irq_source < 
DC_IRQ_SOURCE_DC1_VLINE0 ||
> -			int_params.irq_source > 
DC_IRQ_SOURCE_DC6_VLINE0) {
> -			drm_err(adev_to_drm(adev), "Failed to 
register vline0 irq!\n");
> +			int_params.irq_source < 
DC_IRQ_SOURCE_DC1_VLINE2 ||
> +			int_params.irq_source > 
DC_IRQ_SOURCE_DC6_VLINE2) {
> +			drm_err(adev_to_drm(adev),
> +				"Failed to register vline2 irq!
\n");
>  			return -EINVAL;
>  		}
> 
> -		c_irq_params = &adev-
>dm.vline0_params[int_params.irq_source
> -					- 
DC_IRQ_SOURCE_DC1_VLINE0];
> +		c_irq_params = &adev-
>dm.vline2_params[int_params.irq_source
> +					- 
DC_IRQ_SOURCE_DC1_VLINE2];
> 
>  		c_irq_params->adev = adev;
>  		c_irq_params->irq_src = int_params.irq_source;
> 
>  		if (!amdgpu_dm_irq_register_interrupt(adev, 
&int_params,
> -			dm_dcn_vertical_interrupt0_high_irq,
> +			dm_dcn_vertical_interrupt2_high_irq,
>  			c_irq_params))
>  			return -ENOMEM;
>  	}
> -#endif
> +
> +	return 0;
> +}
> +
> +/* Register IRQ sources and initialize IRQ callbacks */
> +static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
> +{
> +	struct dc *dc = adev->dm.dc;
> +	struct common_irq_params *c_irq_params;
> +	struct dc_interrupt_params int_params = {0};
> +	int r;
> +	int i;
> +
> +	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
> +	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
> +
> +	/*
> +	 * Actions of amdgpu_irq_add_id():
> +	 * 1. Register a set() function with base driver.
> +	 *    Base driver will call set() function to enable/disable an
> +	 *    interrupt in DC hardware.
> +	 * 2. Register amdgpu_dm_irq_handler().
> +	 *    Base driver will call amdgpu_dm_irq_handler() for ALL 
interrupts
> +	 *    coming from DC hardware.
> +	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
> +	 *    for acknowledging and handling.
> +	 */
> +
> +	r = dcn10_register_vline_irq_handlers(adev);
> +	if (r) {
> +		drm_err(adev_to_drm(adev),
> +			"Failed to register vline interrupts\n");
> +		return r;
> +	}
> 
>  	/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond 
to
>  	 * the regular VUPDATE interrupt on DCE. We want 
DC_IRQ_SOURCE_VUPDATEx
> @@ -9541,7 +9596,8 @@ static void manage_dm_interrupts(struct amdgpu_device
> *adev, if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type))
>  				drm_err(dev, "DM_IRQ: Cannot get 
pageflip irq!\n");
>  #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> -			if (amdgpu_irq_get(adev, &adev->vline0_irq, 
irq_type))
> +			if (amdgpu_irq_get(adev, &adev->vline_irq,
> +					   DM_VLINE_IRQ(adev, 
0, irq_type)))
>  				drm_err(dev, "DM_IRQ: Cannot get 
vline0 irq!\n");
>  #endif
>  		}
> @@ -9554,7 +9610,8 @@ static void manage_dm_interrupts(struct amdgpu_device
> *adev, case IP_VERSION(3, 0, 3):
>  		case IP_VERSION(3, 2, 0):
>  #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> -			if (amdgpu_irq_put(adev, &adev->vline0_irq, 
irq_type))
> +			if (amdgpu_irq_put(adev, &adev->vline_irq,
> +					   DM_VLINE_IRQ(adev, 
0, irq_type)))
>  				drm_err(dev, "DM_IRQ: Cannot put 
vline0 irq!\n");
>  #endif
>  			if (amdgpu_irq_put(adev, &adev->pageflip_irq, 
irq_type))
> 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
> 1e0ccf58cdb8d..b4e785784a882 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -543,6 +543,15 @@ struct amdgpu_display_manager {
>  	struct common_irq_params
>  	vline0_params[DC_IRQ_SOURCE_DC6_VLINE0 - DC_IRQ_SOURCE_DC1_VLINE0 
+ 1];
> 
> +	/**
> +	 * @vline2_params:
> +	 *
> +	 * OTG vertical interrupt0 IRQ parameters, passed to registered
> +	 * handlers when triggered.
> +	 */
> +	struct common_irq_params
> +	vline2_params[DC_IRQ_SOURCE_DC6_VLINE2 - DC_IRQ_SOURCE_DC1_VLINE2 + 
1];
> +
>  	/**
>  	 * @vupdate_params:
>  	 *
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index
> efb19f675b0c2..0821b0996a85f 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> @@ -28,6 +28,7 @@
> 
>  #include "dc.h"
>  #include "amdgpu.h"
> +#include "amdgpu_dm_irq.h"
>  #include "amdgpu_dm_psr.h"
>  #include "amdgpu_dm_replay.h"
>  #include "amdgpu_dm_crtc.h"
> @@ -290,10 +291,19 @@ static inline int amdgpu_dm_crtc_set_vblank(struct
> drm_crtc *crtc, bool enable)
> 
>  	/* crtc vblank or vstartup interrupt */
>  	if (enable) {
> -		rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
> +		/* vline only available on DCN+ */
> +		if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0)
> +			rc = amdgpu_irq_get(adev, &adev->crtc_irq, 
irq_type);
> +		else
> +			rc = amdgpu_irq_get(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 
2, irq_type));
>  		drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc);
>  	} else {
> -		rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
> +		if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0)
> +			rc = amdgpu_irq_put(adev, &adev->crtc_irq, 
irq_type);
> +		else
> +			rc = amdgpu_irq_put(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 
2, irq_type));
>  		drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc);
>  	}
> 
> @@ -323,10 +333,12 @@ static inline int amdgpu_dm_crtc_set_vblank(struct
> drm_crtc *crtc, bool enable) /* crtc vline0 interrupt, only available on
> DCN+ */
>  	if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
>  		if (enable) {
> -			rc = amdgpu_irq_get(adev, &adev->vline0_irq, 
irq_type);
> +			rc = amdgpu_irq_get(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 
0, irq_type));
>  			drm_dbg_vbl(crtc->dev, "Get vline0_irq 
ret=%d\n", rc);
>  		} else {
> -			rc = amdgpu_irq_put(adev, &adev->vline0_irq, 
irq_type);
> +			rc = amdgpu_irq_put(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 
0, irq_type));
>  			drm_dbg_vbl(crtc->dev, "Put vline0_irq 
ret=%d\n", rc);
>  		}
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index
> 5948e2a6219e3..757529af72ceb 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> @@ -769,18 +769,86 @@ static int amdgpu_dm_set_crtc_irq_state(struct
> amdgpu_device *adev, __func__);
>  }
> 
> -static int amdgpu_dm_set_vline0_irq_state(struct amdgpu_device *adev,
> -					struct amdgpu_irq_src 
*source,
> -					unsigned int crtc_id,
> -					enum 
amdgpu_interrupt_state state)
> +/**
> + * amdgpu_dm_set_vline_irq_state: Set interrupt state for vline
> + *
> + * Map base driver amdgpu_irq_update() -- called per interrupt src ID -- to
> + * their corresponding dc_irq_source, then set then to the requested
> state. + *
> + * Since all the vline0/1/2 interrupts have the same src_id, the standard
> + * amdgpu_irq_src.num_types mapping to the number of OTGs won't work. For
> vline, + * num_types will have to cover (number of different vline
> interrupt types) * + * (number of OTGs) types. For example, if there are 6
> OTGS, then num_types = + * 3*6 = 18.
> + *
> + * This is only needed for the amdgpu_irq_src_funcs.set_irq implementation;
> the + * .process implementation is provided the interrupt vector, which
> contains both + * the src_id and ctx_id to uniquely map to the
> dc_irq_source.
> + *
> + * The vline_otg_id mapping is first by vline num, then by OTG num:
> + *
> + * | vline_otg_id | vline num | otg num |
> + * |--------------|-----------|---------|
> + * | 0            | 0         | 0       |
> + * | 1            | 0         | 1       |
> + * | ...          | ...       | ...     |
> + * | 5            | 0         | 5       |
> + * | 6            | 1         | 0       |
> + * | ...          | ...       | ...     |
> + * | 11           | 1         | 5       |
> + * | 12           | 2         | 0       |
> + * | ...          | ...       | ...     |
> + * | 17           | 2         | 5       |
> + */
> +static int amdgpu_dm_set_vline_irq_state(struct amdgpu_device *adev,
> +					 struct amdgpu_irq_src 
*source,
> +					 unsigned int 
vline_otg_id,
> +					 enum 
amdgpu_interrupt_state state)
>  {
> -	return dm_irq_state(
> -		adev,
> -		source,
> -		crtc_id,
> -		state,
> -		IRQ_TYPE_VLINE0,
> -		__func__);
> +	bool st;
> +	unsigned int vline_num, otg_num;
> +	enum dc_irq_source irq_source;
> +	struct dc *dc = adev->dm.dc;
> +	struct amdgpu_crtc *acrtc;
> +
> +	if (vline_otg_id >= 3 * adev->mode_info.num_crtc) {
> +		drm_err(adev_to_drm(adev),
> +			"Invalid vline map_id :%d\n", vline_otg_id);
> +		return -EINVAL;
> +	}
> +
> +	vline_num = vline_otg_id / adev->mode_info.num_crtc;
> +	otg_num = vline_otg_id % adev->mode_info.num_crtc;
> +	acrtc = adev->mode_info.crtcs[otg_num];
> +
> +	if (!acrtc) {
> +		drm_err(adev_to_drm(adev),
> +			"crtc is NULL at id : %d\n", otg_num);
> +		return 0;
> +	}
> +
> +	if (acrtc->otg_inst == -1)
> +		return 0;
> +
> +	if (vline_num == 0)
> +		irq_source = IRQ_TYPE_VLINE0 + otg_num;
> +	else if (vline_num == 1)
> +		irq_source = IRQ_TYPE_VLINE1 + otg_num;
> +	else if (vline_num == 2)
> +		irq_source = IRQ_TYPE_VLINE2 + otg_num;
> +	else {
> +		drm_err(adev_to_drm(adev),
> +			"Invalid vline num :%d\n", vline_num);
> +		return -EINVAL;
> +	}
> +
> +	st = (state == AMDGPU_IRQ_STATE_ENABLE);
> +
> +	if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
> +		dc_allow_idle_optimizations(dc, false);
> +
> +	dc_interrupt_set(adev->dm.dc, irq_source, st);
> +	return 0;
>  }
> 
>  static int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *adev,
> @@ -826,8 +894,8 @@ static const struct amdgpu_irq_src_funcs
> dm_crtc_irq_funcs = { .process = amdgpu_dm_irq_handler,
>  };
> 
> -static const struct amdgpu_irq_src_funcs dm_vline0_irq_funcs = {
> -	.set = amdgpu_dm_set_vline0_irq_state,
> +static const struct amdgpu_irq_src_funcs dm_vline_irq_funcs = {
> +	.set = amdgpu_dm_set_vline_irq_state,
>  	.process = amdgpu_dm_irq_handler,
>  };
> 
> @@ -861,8 +929,9 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
> adev->crtc_irq.num_types = adev->mode_info.num_crtc;
>  	adev->crtc_irq.funcs = &dm_crtc_irq_funcs;
> 
> -	adev->vline0_irq.num_types = adev->mode_info.num_crtc;
> -	adev->vline0_irq.funcs = &dm_vline0_irq_funcs;
> +	/* Number of vline types * num OTGs */
> +	adev->vline_irq.num_types = 3 * adev->mode_info.num_crtc;
> +	adev->vline_irq.funcs = &dm_vline_irq_funcs;
> 
>  	adev->dmub_outbox_irq.num_types = 1;
>  	adev->dmub_outbox_irq.funcs = &dm_dmub_outbox_irq_funcs;
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h index
> 4f6b58f4f90d7..a672b58b0f760 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> @@ -27,6 +27,13 @@
> 
>  #include "irq_types.h" /* DAL irq definitions */
> 
> +/*
> + * Get OTG vline irq id from vline num and otg num. See also
> + * amdgpu_dm_set_vline_irq_state()
> + */
> +#define DM_VLINE_IRQ(adev, vline_num, otg_num) \
> +	adev->mode_info.num_crtc * vline_num + otg_num
> +
>  /*
>   * Display Manager IRQ-related interfaces (for use by DAL).
>   */
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c index
> 7dff8731f414e..a72fefb531e99 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
> @@ -58,18 +58,6 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct
> irq_service *irq_servic return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE1;
>  	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
> @@ -95,6 +83,19 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct
> irq_service *irq_servic case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP6;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -157,6 +158,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
>  	.set = NULL,
>  	.ack = NULL
> @@ -239,6 +245,14 @@ static struct irq_source_info_funcs
> vupdate_no_lock_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dummy_irq_entry() \
>  	{\
>  		.funcs = &dummy_irq_info_funcs\
> @@ -353,6 +367,12 @@ irq_source_info_dcn10[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	vline0_int_entry(4),
>  	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>  };
> 
>  static const struct irq_service_funcs irq_service_funcs_dcn10 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c index
> 34f9e8a9f488f..cbf65367cba5c 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
> @@ -59,18 +59,6 @@ static enum dc_irq_source to_dal_irq_source_dcn20(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -96,6 +84,19 @@ static enum dc_irq_source to_dal_irq_source_dcn20(
>  	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE6;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -163,6 +164,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -244,6 +250,13 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
>  #define dummy_irq_entry() \
>  	{\
>  		.funcs = &dummy_irq_info_funcs\
> @@ -358,6 +371,12 @@ irq_source_info_dcn20[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	vline0_int_entry(4),
>  	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>  };
> 
>  static const struct irq_service_funcs irq_service_funcs_dcn20 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c index
> 6417011d22463..7ab8317961734 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
> @@ -47,10 +47,6 @@ static enum dc_irq_source to_dal_irq_source_dcn201(
>  		return DC_IRQ_SOURCE_VBLANK1;
>  	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK2;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -59,6 +55,12 @@ static enum dc_irq_source to_dal_irq_source_dcn201(
>  		return DC_IRQ_SOURCE_VUPDATE1;
>  	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE2;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -104,6 +106,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .set = NULL,
>  	.ack = NULL
>  };
> +
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
>  static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
>  	.set = NULL,
>  	.ack = NULL
> @@ -195,6 +202,13 @@ static struct irq_source_info_funcs
> vupdate_no_lock_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
>  #define dummy_irq_entry() \
>  	{\
>  		.funcs = &dummy_irq_info_funcs\
> @@ -309,6 +323,8 @@ irq_source_info_dcn201[DAL_IRQ_SOURCES_NUMBER] = {
>  	dummy_irq_entry(),
>  	dummy_irq_entry(),
>  	dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
>  };
> 
>  static const struct irq_service_funcs irq_service_funcs_dcn201 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c index
> 05f7877d2d6c8..da1ebb9467c9d 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
> @@ -60,18 +60,6 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct
> irq_service *irq_servic return DC_IRQ_SOURCE_VBLANK6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -97,6 +85,19 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct
> irq_service *irq_servic case
> DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE6;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -170,6 +171,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
> 
> @@ -266,6 +272,14 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dmub_outbox_int_entry()\
>  	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>  		IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, 
DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -385,6 +399,12 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	vline0_int_entry(4),
>  	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>  	dmub_outbox_int_entry(),
>  };
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c index
> 3a7f76364000e..d4af3555d14ef 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
> @@ -68,18 +68,6 @@ static enum dc_irq_source to_dal_irq_source_dcn30(
>  		return DC_IRQ_SOURCE_VBLANK6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -105,6 +93,19 @@ static enum dc_irq_source to_dal_irq_source_dcn30(
>  	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE6;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -177,6 +178,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -280,6 +286,14 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dummy_irq_entry() \
>  	{\
>  		.funcs = &dummy_irq_info_funcs\
> @@ -394,6 +408,12 @@ irq_source_info_dcn30[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	vline0_int_entry(4),
>  	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>  	dmub_trace_int_entry(),
>  };
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c index
> f4dfc96310c73..14631b78715a0 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
> @@ -55,18 +55,6 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct
> irq_service *irq_servi return DC_IRQ_SOURCE_VBLANK6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -92,6 +80,19 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct
> irq_service *irq_servi case
> DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE6;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -164,6 +165,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -262,6 +268,14 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
> 
>  #define i2c_int_entry(reg_num) \
> @@ -363,6 +377,11 @@ static const struct irq_source_info
> irq_source_info_dcn302[DAL_IRQ_SOURCES_NUMBE vline0_int_entry(2),
>  		vline0_int_entry(3),
>  		vline0_int_entry(4),
> +		vline2_int_entry(0),
> +		vline2_int_entry(1),
> +		vline2_int_entry(2),
> +		vline2_int_entry(3),
> +		vline2_int_entry(4),
>  		dmub_trace_int_entry(),
>  };
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c index
> fdc7624461ac2..bd4768afafe43 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
> @@ -46,10 +46,6 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct
> irq_service *irq_servi return DC_IRQ_SOURCE_VBLANK1;
>  	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK2;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -59,6 +55,11 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct
> irq_service *irq_servi case
> DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>  		return DC_IRQ_SOURCE_VUPDATE2;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -110,6 +111,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -186,6 +192,14 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .funcs = &vline0_irq_info_funcs\
>  	}
> 
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
> 
>  #define i2c_int_entry(reg_num) \
> @@ -260,6 +274,8 @@ static const struct irq_source_info
> irq_source_info_dcn303[DAL_IRQ_SOURCES_NUMBE vblank_int_entry(1),
>  		vline0_int_entry(0),
>  		vline0_int_entry(1),
> +		vline2_int_entry(0),
> +		vline2_int_entry(1),
>  };
> 
>  static const struct irq_service_funcs irq_service_funcs_dcn303 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c index
> 5fecd03f94999..9704f90cd0407 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
> @@ -56,18 +56,6 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct
> irq_service *irq_servic return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -94,6 +82,20 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct
> irq_service *irq_servic return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -166,6 +168,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -260,6 +267,15 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { OTG_VERTICAL_INTERRUPT0_CONTROL,
> OTG_VERTICAL_INTERRUPT0_CLEAR),\ .funcs = &vline0_irq_info_funcs\
>  	}
> +
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dmub_outbox_int_entry()\
>  	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>  		IRQ_REG_ENTRY_DMUB(\
> @@ -376,6 +392,10 @@ irq_source_info_dcn31[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
>  	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
>  	dmub_outbox_int_entry(),
>  };
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c index
> a214f13c5a978..afa4a17ce2f0e 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
> @@ -58,18 +58,6 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct
> irq_service *irq_servi return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -96,6 +84,20 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct
> irq_service *irq_servi return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -168,6 +170,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -262,6 +269,15 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { OTG_VERTICAL_INTERRUPT0_CONTROL,
> OTG_VERTICAL_INTERRUPT0_CLEAR),\ .funcs = &vline0_irq_info_funcs\
>  	}
> +
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dmub_outbox_int_entry()\
>  	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>  		IRQ_REG_ENTRY_DMUB(\
> @@ -378,6 +394,10 @@ irq_source_info_dcn314[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
>  	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
>  	dmub_outbox_int_entry(),
>  };
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c index
> dc2dced7db85d..b64fada140fb0 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
> @@ -63,18 +63,6 @@ static enum dc_irq_source to_dal_irq_source_dcn315(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -101,6 +89,20 @@ static enum dc_irq_source to_dal_irq_source_dcn315(
>  		return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -173,6 +175,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
> 
> @@ -267,6 +274,15 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { OTG_VERTICAL_INTERRUPT0_CONTROL,
> OTG_VERTICAL_INTERRUPT0_CLEAR),\ .funcs = &vline0_irq_info_funcs\
>  	}
> +
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>  #define dmub_outbox_int_entry()\
>  	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>  		IRQ_REG_ENTRY_DMUB(\
> @@ -383,6 +399,10 @@ irq_source_info_dcn315[DAL_IRQ_SOURCES_NUMBER] = {
>  	vline0_int_entry(3),
>  	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
>  	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
>  	dmub_outbox_int_entry(),
>  };
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c index
> 3090ceb664332..f347e2ab7ced3 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
> @@ -57,18 +57,6 @@ static enum dc_irq_source to_dal_irq_source_dcn32(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -95,6 +83,20 @@ static enum dc_irq_source to_dal_irq_source_dcn32(
>  		return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c index
> 27289279b21ca..d70754f6ac0b6 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
> @@ -55,18 +55,6 @@ static enum dc_irq_source to_dal_irq_source_dcn35(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -93,6 +81,20 @@ static enum dc_irq_source to_dal_irq_source_dcn35(
>  		return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -165,6 +167,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
> 
> @@ -249,6 +256,12 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { OTG_VERTICAL_INTERRUPT0_CONTROL,
> OTG_VERTICAL_INTERRUPT0_CLEAR),\ REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 +
> reg_num].funcs = &vline0_irq_info_funcs\
> 
> +#define vline2_int_entry(reg_num)\
> +		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs =
> &vline2_irq_info_funcs\ +
>  #define dmub_outbox_int_entry()\
>  		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
>  			DMCUB_INTERRUPT_ENABLE, 
DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -362,6 +375,10 @@ static struct irq_source_info_funcs
> dummy_irq_info_funcs = { vline0_int_entry(3); \
>  	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
>  	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
> +	vline2_int_entry(0); \
> +	vline2_int_entry(1); \
> +	vline2_int_entry(2); \
> +	vline2_int_entry(3); \
>  	dmub_outbox_int_entry()
> 
>  #define dcn35_irq_init() \
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c index
> 7404b572a4e96..8948cbb03011e 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
> @@ -4,8 +4,6 @@
>  #include "dm_services.h"
>  #include "include/logger_interface.h"
>  #include "../dce110/irq_service_dce110.h"
> -
> -
>  #include "dcn/dcn_3_5_1_offset.h"
>  #include "dcn/dcn_3_5_1_sh_mask.h"
> 
> @@ -34,18 +32,6 @@ static enum dc_irq_source to_dal_irq_source_dcn351(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -72,6 +58,20 @@ static enum dc_irq_source to_dal_irq_source_dcn351(
>  		return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -144,6 +144,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
> 
> @@ -228,6 +233,12 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { OTG_VERTICAL_INTERRUPT0_CONTROL,
> OTG_VERTICAL_INTERRUPT0_CLEAR),\ REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 +
> reg_num].funcs = &vline0_irq_info_funcs\
> 
> +#define vline2_int_entry(reg_num)\
> +		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs =
> &vline2_irq_info_funcs\ +
>  #define dmub_outbox_int_entry()\
>  		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
>  			DMCUB_INTERRUPT_ENABLE, 
DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -342,6 +353,10 @@ static struct irq_source_info_funcs
> dummy_irq_info_funcs = { vline0_int_entry(3); \
>  	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
>  	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
> +	vline2_int_entry(0); \
> +	vline2_int_entry(1); \
> +	vline2_int_entry(2); \
> +	vline2_int_entry(3); \
>  	dmub_outbox_int_entry(); \
>  }
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c index
> 3dd47a99f568d..5525a69d0ffd2 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
> @@ -33,18 +33,6 @@ static enum dc_irq_source to_dal_irq_source_dcn36(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -71,6 +59,20 @@ static enum dc_irq_source to_dal_irq_source_dcn36(
>  		return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> @@ -143,6 +145,11 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { .ack = NULL
>  };
> 
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>  #undef BASE_INNER
>  #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
> 
> @@ -227,6 +234,12 @@ static struct irq_source_info_funcs
> vline0_irq_info_funcs = { OTG_VERTICAL_INTERRUPT0_CONTROL,
> OTG_VERTICAL_INTERRUPT0_CLEAR),\ REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 +
> reg_num].funcs = &vline0_irq_info_funcs\
> 
> +#define vline2_int_entry(reg_num)\
> +		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, 
OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs =
> &vline2_irq_info_funcs\ +
>  #define dmub_outbox_int_entry()\
>  		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
>  			DMCUB_INTERRUPT_ENABLE, 
DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -339,6 +352,10 @@ static struct irq_source_info_funcs
> dummy_irq_info_funcs = { vline0_int_entry(1); \
>  	vline0_int_entry(2); \
>  	vline0_int_entry(3); \
> +	vline2_int_entry(0); \
> +	vline2_int_entry(1); \
> +	vline2_int_entry(2); \
> +	vline2_int_entry(3); \
>  	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
>  	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
>  	dmub_outbox_int_entry(); \
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c index
> 42d9d42ba0b99..ce264333e3cf4 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
> @@ -36,18 +36,6 @@ static enum dc_irq_source to_dal_irq_source_dcn401(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -75,6 +63,19 @@ static enum dc_irq_source to_dal_irq_source_dcn401(
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> 
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
> b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c index
> f4d1ce9079ded..f9113d9f3c3ee 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
> @@ -35,18 +35,6 @@ static enum dc_irq_source to_dal_irq_source_dcn42(
>  		return DC_IRQ_SOURCE_VBLANK5;
>  	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>  		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>  	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>  		return DC_IRQ_SOURCE_PFLIP1;
>  	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -73,6 +61,20 @@ static enum dc_irq_source to_dal_irq_source_dcn42(
>  		return DC_IRQ_SOURCE_VUPDATE6;
>  	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>  		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>  	case DCN_1_0__SRCID__DC_HPD1_INT:
>  		/* generic src_id for all HPD and HPDRX interrupts */
>  		switch (ext_id) {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
> b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h index
> bbcef3d2fe334..ba2bca88e4ccb 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
> +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
> @@ -30,6 +30,29 @@
> 
>  #include "irq_types.h"
> 
> +/*
> + * Helper to get vertical interrupt src/ctx id by OTG instance and vint
> number + */
> +#define DCN_VINT_SRCID(otg_inst, vint_num) \
> +	DCN_1_0__SRCID__OTG ## otg_inst ## _VERTICAL_INTERRUPT ## vint_num 
##
> _CONTROL +#define DCN_VINT_CTXID(otg_inst, vint_num) \
> +	DCN_1_0__CTXID__OTG ## otg_inst ## _VERTICAL_INTERRUPT ## vint_num 
##
> _CONTROL +#define DC_VINT_IRQSRC(otg_inst, vint_num) \
> +	DC_IRQ_SOURCE_DC ## otg_inst ## _VLINE ## vint_num
> +
> +/* Helper to map vertical interrupt src/ctx id to DC irq source enum */
> +#define DCN_VINT_TO_DC_IRQSRC(otg_inst, ext_id) \
> +	switch (ext_id) { \
> +	case DCN_VINT_CTXID(otg_inst, 0): \
> +		return DC_VINT_IRQSRC(otg_inst, 0); \
> +	case DCN_VINT_CTXID(otg_inst, 1): \
> +		return DC_VINT_IRQSRC(otg_inst, 1); \
> +	case DCN_VINT_CTXID(otg_inst, 2): \
> +		return DC_VINT_IRQSRC(otg_inst, 2); \
> +	default: \
> +		return DC_IRQ_SOURCE_INVALID; \
> +	}
> +
>  struct irq_service;
>  struct irq_source_info;





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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-04 20:54 ` Timur Kristóf
@ 2026-05-06 20:00   ` Leo Li
  2026-05-06 20:32     ` Harry Wentland
  2026-05-06 22:03     ` Timur Kristóf
  0 siblings, 2 replies; 9+ messages in thread
From: Leo Li @ 2026-05-06 20:00 UTC (permalink / raw)
  To: Timur Kristóf, amd-gfx
  Cc: Harry.Wentland, Aurabindo.Pillai, mario.limonciello, wiagn233,
	sysdadmin



On 2026-05-04 16:54, Timur Kristóf wrote:
> On Monday, May 4, 2026 8:36:49 PM Central European Summer Time 
> sunpeng.li@amd.com wrote:
>> From: Leo Li <sunpeng.li@amd.com>
>>
>> [Why]
>>
>> VStartup is an OTG event that fires when the pixel pipeline prepares for
>> pixel scanout of the next frame. It was previously used to deliver
>> vblank events for commits that do not trigger a fb address update, and
>> hence a pflip interrupt (hw cursor updates, for example).
>>
>> The issue with vstartup is that HW can mask the interrupt in cases where
>> idle optimizations are enabled or when a HW lock is active. This could
>> the explain the range of flip_done timeouts frequently seen in the wild.
> Can you help me understand how that could happen with vstartup?
> Specifically, what is a "HW lock" and when is it active?

Hi Timur,

I should've prefaced this patch to say that this is a theoretical fix. I haven't
been able to reproduce the timeout issues myself, and this patch came out of
internal discussions with folks more familiar with the HW. I don't think this
will fix *all* cases of flip_done timeouts, but it may address some of them.

(But timeouts aside, we *should* transition to vline since it's more reliable
than vstartup.)

To answer your questions: depending on the DCN generation, there can be a few
things that affects vstartup firing:

* DPG - DCN can Dynamically Power Gate parts of the display pipe when a
  self-refresh capable eDP is connected. DPG is engaged when there's enough
  static frames (detected thru drm_vblank_off) Once gated, even though the OTG
  (output timing generator) is still enabled, vstartup is masked. vline is
  unaffected.

* GSL - Driver can use the Global Sync Lock to block HW from latching onto
  double-buffered registers during programming, to prevent HW from latching onto
  a partially programmed state. This will mask vstartup, but vline is
  unaffected. See dcn20_pipe_control_lock()

* MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can store fb
  data to allow for longer DRAM sleep. When scanning out from MALL, vstartup is
  masked, vline is unaffected.

> 
> Many users have experienced flip_done timeouts while playing games.
> In that scenario, would any idle optimization be enabled or is there a "HW 
> lock"?

If the game stops submitting frames for ~15 refresh cycles, it's possible that
PSR kicks in. Though I know there are plenty of reporters running on external
without PSR support. If it's DGPUs, it's very likely due to MALL. A reporter I
was debugging with said disabling MALL showed good results[1]. If it's an APU
with an external monitor, then that's less clear.

A lot of the reporters seem to be running Phoenix (DCN314), with a common
symptom of DMUB timing out[2]. If a self-refresh panel is involved, then I'm
curious if this vline2 patch would help. Hamza's recent patch[3] that enables
various levels of reset may help to mitigate, but it doesn't fix the root-cause.
I'm planning a branch with this patch and [3], along with debug dumps on
flip_done timeouts for reporters to try.

[1]https://lore.kernel.org/amd-gfx/e415c38b-4102-40e4-a195-0256caf34802@m1k.cloud/
[2]https://gitlab.freedesktop.org/drm/amd/-/work_items/4831
[3]https://lore.kernel.org/lkml/20260505182105.420525-2-someguy@effective-light.com/

> 
>> DCN hardware provides 3 generic OTG interrupts that can be programmed to>> fire on a specific line. Vline 0 and 1 are currently reserved, with
>> vline2 available to use for event delivery. These interrupts cannot
>> be masked, as long as the OTG is active.
>>
>> [How]
>>
>> Switch to vline2 for vblank handling. Today, DC will program the
>> vline2 position to at vupdate -- the point at which HW latches to
>> double-buffered registers.
>>
>> Since all the vline interrupt types share the same interrupt src_id,
>> refactor the existing vline0 infrastructure to allow for all the vline0,
>> 1, and 2 types.
>>
>> Since this is intended to replace vstartup for DCN, use the same handler
>> logic, but be careful to leave DCE on vstartup.
> Why not also switch DCE?
> Does DCE not have the vline interrupts or does it not have the same issue with 
> the vstartup interrupt?

I didn't want to touch DCE since I don't have information on how these
interrupts behave on them, and I didn't want to regress anything. Would need to
do some digging to find out.

- Leo

> 
>> Signed-off-by: Leo Li <sunpeng.li@amd.com>
> I think this patch should have a "Fixes:" tag or another way to indicate that 
> it should be backported to stable kernels.
> 
> Thanks,
> Timur


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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-06 20:00   ` Leo Li
@ 2026-05-06 20:32     ` Harry Wentland
  2026-05-06 21:57       ` Timur Kristóf
  2026-05-06 22:03     ` Timur Kristóf
  1 sibling, 1 reply; 9+ messages in thread
From: Harry Wentland @ 2026-05-06 20:32 UTC (permalink / raw)
  To: Leo Li, Timur Kristóf, amd-gfx
  Cc: Aurabindo.Pillai, mario.limonciello, wiagn233, sysdadmin



On 2026-05-06 16:00, Leo Li wrote:
> 
> 
> On 2026-05-04 16:54, Timur Kristóf wrote:
>> On Monday, May 4, 2026 8:36:49 PM Central European Summer Time 
>> sunpeng.li@amd.com wrote:
>>> From: Leo Li <sunpeng.li@amd.com>
>>>
>>> [Why]
>>>
>>> VStartup is an OTG event that fires when the pixel pipeline prepares for
>>> pixel scanout of the next frame. It was previously used to deliver
>>> vblank events for commits that do not trigger a fb address update, and
>>> hence a pflip interrupt (hw cursor updates, for example).
>>>
>>> The issue with vstartup is that HW can mask the interrupt in cases where
>>> idle optimizations are enabled or when a HW lock is active. This could
>>> the explain the range of flip_done timeouts frequently seen in the wild.
>> Can you help me understand how that could happen with vstartup?
>> Specifically, what is a "HW lock" and when is it active?
> 
> Hi Timur,
> 
> I should've prefaced this patch to say that this is a theoretical fix. I haven't
> been able to reproduce the timeout issues myself, and this patch came out of
> internal discussions with folks more familiar with the HW. I don't think this
> will fix *all* cases of flip_done timeouts, but it may address some of them.
> 
> (But timeouts aside, we *should* transition to vline since it's more reliable
> than vstartup.)
> 
> To answer your questions: depending on the DCN generation, there can be a few
> things that affects vstartup firing:
> 
> * DPG - DCN can Dynamically Power Gate parts of the display pipe when a
>   self-refresh capable eDP is connected. DPG is engaged when there's enough
>   static frames (detected thru drm_vblank_off) Once gated, even though the OTG
>   (output timing generator) is still enabled, vstartup is masked. vline is
>   unaffected.
> 
> * GSL - Driver can use the Global Sync Lock to block HW from latching onto
>   double-buffered registers during programming, to prevent HW from latching onto
>   a partially programmed state. This will mask vstartup, but vline is
>   unaffected. See dcn20_pipe_control_lock()
> 
> * MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can store fb
>   data to allow for longer DRAM sleep. When scanning out from MALL, vstartup is
>   masked, vline is unaffected.
> 
>>
>> Many users have experienced flip_done timeouts while playing games.
>> In that scenario, would any idle optimization be enabled or is there a "HW 
>> lock"?
> 
> If the game stops submitting frames for ~15 refresh cycles, it's possible that
> PSR kicks in. Though I know there are plenty of reporters running on external
> without PSR support. If it's DGPUs, it's very likely due to MALL. A reporter I
> was debugging with said disabling MALL showed good results[1]. If it's an APU
> with an external monitor, then that's less clear.
> 
> A lot of the reporters seem to be running Phoenix (DCN314), with a common
> symptom of DMUB timing out[2]. If a self-refresh panel is involved, then I'm
> curious if this vline2 patch would help. Hamza's recent patch[3] that enables
> various levels of reset may help to mitigate, but it doesn't fix the root-cause.
> I'm planning a branch with this patch and [3], along with debug dumps on
> flip_done timeouts for reporters to try.
> 
> [1]https://lore.kernel.org/amd-gfx/e415c38b-4102-40e4-a195-0256caf34802@m1k.cloud/
> [2]https://gitlab.freedesktop.org/drm/amd/-/work_items/4831
> [3]https://lore.kernel.org/lkml/20260505182105.420525-2-someguy@effective-light.com/
> 
>>
>>> DCN hardware provides 3 generic OTG interrupts that can be programmed to>> fire on a specific line. Vline 0 and 1 are currently reserved, with
>>> vline2 available to use for event delivery. These interrupts cannot
>>> be masked, as long as the OTG is active.
>>>
>>> [How]
>>>
>>> Switch to vline2 for vblank handling. Today, DC will program the
>>> vline2 position to at vupdate -- the point at which HW latches to
>>> double-buffered registers.
>>>
>>> Since all the vline interrupt types share the same interrupt src_id,
>>> refactor the existing vline0 infrastructure to allow for all the vline0,
>>> 1, and 2 types.
>>>
>>> Since this is intended to replace vstartup for DCN, use the same handler
>>> logic, but be careful to leave DCE on vstartup.
>> Why not also switch DCE?
>> Does DCE not have the vline interrupts or does it not have the same issue with 
>> the vstartup interrupt?
> 
> I didn't want to touch DCE since I don't have information on how these
> interrupts behave on them, and I didn't want to regress anything. Would need to
> do some digging to find out.
> 

DCE's architecture is quite different in this regard. No VSTARTUP, VUPDATE
signals and interrupts on DCE.

Harry

> - Leo
> 
>>
>>> Signed-off-by: Leo Li <sunpeng.li@amd.com>
>> I think this patch should have a "Fixes:" tag or another way to indicate that 
>> it should be backported to stable kernels.
>>
>> Thanks,
>> Timur
> 


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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-06 20:32     ` Harry Wentland
@ 2026-05-06 21:57       ` Timur Kristóf
  0 siblings, 0 replies; 9+ messages in thread
From: Timur Kristóf @ 2026-05-06 21:57 UTC (permalink / raw)
  To: Leo Li, amd-gfx, Harry Wentland
  Cc: Aurabindo.Pillai, mario.limonciello, wiagn233, sysdadmin

On Wednesday, May 6, 2026 10:32:16 PM Central European Summer Time Harry 
Wentland wrote:
> On 2026-05-06 16:00, Leo Li wrote:
> > On 2026-05-04 16:54, Timur Kristóf wrote:
> >> On Monday, May 4, 2026 8:36:49 PM Central European Summer Time
> >> 
> >> sunpeng.li@amd.com wrote:
> >>> From: Leo Li <sunpeng.li@amd.com>
> >>> 
> >>> [Why]
> >>> 
> >>> VStartup is an OTG event that fires when the pixel pipeline prepares for
> >>> pixel scanout of the next frame. It was previously used to deliver
> >>> vblank events for commits that do not trigger a fb address update, and
> >>> hence a pflip interrupt (hw cursor updates, for example).
> >>> 
> >>> The issue with vstartup is that HW can mask the interrupt in cases where
> >>> idle optimizations are enabled or when a HW lock is active. This could
> >>> the explain the range of flip_done timeouts frequently seen in the wild.
> >> 
> >> Can you help me understand how that could happen with vstartup?
> >> Specifically, what is a "HW lock" and when is it active?
> > 
> > Hi Timur,
> > 
> > I should've prefaced this patch to say that this is a theoretical fix. I
> > haven't been able to reproduce the timeout issues myself, and this patch
> > came out of internal discussions with folks more familiar with the HW. I
> > don't think this will fix *all* cases of flip_done timeouts, but it may
> > address some of them.
> > 
> > (But timeouts aside, we *should* transition to vline since it's more
> > reliable than vstartup.)
> > 
> > To answer your questions: depending on the DCN generation, there can be a
> > few things that affects vstartup firing:
> > 
> > * DPG - DCN can Dynamically Power Gate parts of the display pipe when a
> > 
> >   self-refresh capable eDP is connected. DPG is engaged when there's
> >   enough
> >   static frames (detected thru drm_vblank_off) Once gated, even though the
> >   OTG (output timing generator) is still enabled, vstartup is masked.
> >   vline is unaffected.
> > 
> > * GSL - Driver can use the Global Sync Lock to block HW from latching onto
> > 
> >   double-buffered registers during programming, to prevent HW from
> >   latching onto a partially programmed state. This will mask vstartup,
> >   but vline is unaffected. See dcn20_pipe_control_lock()
> > 
> > * MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can store
> > fb> 
> >   data to allow for longer DRAM sleep. When scanning out from MALL,
> >   vstartup is masked, vline is unaffected.
> >> 
> >> Many users have experienced flip_done timeouts while playing games.
> >> In that scenario, would any idle optimization be enabled or is there a
> >> "HW
> >> lock"?
> > 
> > If the game stops submitting frames for ~15 refresh cycles, it's possible
> > that PSR kicks in. Though I know there are plenty of reporters running on
> > external without PSR support. If it's DGPUs, it's very likely due to
> > MALL. A reporter I was debugging with said disabling MALL showed good
> > results[1]. If it's an APU with an external monitor, then that's less
> > clear.
> > 
> > A lot of the reporters seem to be running Phoenix (DCN314), with a common
> > symptom of DMUB timing out[2]. If a self-refresh panel is involved, then
> > I'm curious if this vline2 patch would help. Hamza's recent patch[3] that
> > enables various levels of reset may help to mitigate, but it doesn't fix
> > the root-cause. I'm planning a branch with this patch and [3], along with
> > debug dumps on flip_done timeouts for reporters to try.
> > 
> > [1]https://lore.kernel.org/amd-gfx/e415c38b-4102-40e4-a195-0256caf34802@m1
> > k.cloud/ [2]https://gitlab.freedesktop.org/drm/amd/-/work_items/4831
> > [3]https://lore.kernel.org/lkml/20260505182105.420525-2-someguy@effective-> > light.com/> 
> >>> DCN hardware provides 3 generic OTG interrupts that can be programmed
> >>> to>> fire on a specific line. Vline 0 and 1 are currently reserved,
> >>> with vline2 available to use for event delivery. These interrupts
> >>> cannot be masked, as long as the OTG is active.
> >>> 
> >>> [How]
> >>> 
> >>> Switch to vline2 for vblank handling. Today, DC will program the
> >>> vline2 position to at vupdate -- the point at which HW latches to
> >>> double-buffered registers.
> >>> 
> >>> Since all the vline interrupt types share the same interrupt src_id,
> >>> refactor the existing vline0 infrastructure to allow for all the vline0,
> >>> 1, and 2 types.
> >>> 
> >>> Since this is intended to replace vstartup for DCN, use the same handler
> >>> logic, but be careful to leave DCE on vstartup.
> >> 
> >> Why not also switch DCE?
> >> Does DCE not have the vline interrupts or does it not have the same issue
> >> with the vstartup interrupt?
> > 
> > I didn't want to touch DCE since I don't have information on how these
> > interrupts behave on them, and I didn't want to regress anything. Would
> > need to do some digging to find out.
> 
> DCE's architecture is quite different in this regard. No VSTARTUP, VUPDATE
> signals and interrupts on DCE.
> 

Hi Harry,

I'm pretty sure DCE has VUPDATE, starting from DCE 8, it is used for VRR.
You can verify this in irq_service_dce80.c

Not sure about VSTART, I'm a bit confused about that, but Leo above says that 
DCE uses that, but I can't find it.

Timur






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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-06 20:00   ` Leo Li
  2026-05-06 20:32     ` Harry Wentland
@ 2026-05-06 22:03     ` Timur Kristóf
  2026-05-07  6:15       ` Shengyu Qu
  2026-05-07 14:08       ` Leo Li
  1 sibling, 2 replies; 9+ messages in thread
From: Timur Kristóf @ 2026-05-06 22:03 UTC (permalink / raw)
  To: amd-gfx, Leo Li
  Cc: Harry.Wentland, Aurabindo.Pillai, mario.limonciello, wiagn233,
	sysdadmin

On Wednesday, May 6, 2026 10:00:12 PM Central European Summer Time Leo Li 
wrote:
> On 2026-05-04 16:54, Timur Kristóf wrote:
> > On Monday, May 4, 2026 8:36:49 PM Central European Summer Time
> > 
> > sunpeng.li@amd.com wrote:
> >> From: Leo Li <sunpeng.li@amd.com>
> >> 
> >> [Why]
> >> 
> >> VStartup is an OTG event that fires when the pixel pipeline prepares for
> >> pixel scanout of the next frame. It was previously used to deliver
> >> vblank events for commits that do not trigger a fb address update, and
> >> hence a pflip interrupt (hw cursor updates, for example).
> >> 
> >> The issue with vstartup is that HW can mask the interrupt in cases where
> >> idle optimizations are enabled or when a HW lock is active. This could
> >> the explain the range of flip_done timeouts frequently seen in the wild.
> > 
> > Can you help me understand how that could happen with vstartup?
> > Specifically, what is a "HW lock" and when is it active?
> 
> Hi Timur,
> 
> I should've prefaced this patch to say that this is a theoretical fix. I
> haven't been able to reproduce the timeout issues myself, and this patch
> came out of internal discussions with folks more familiar with the HW. I
> don't think this will fix *all* cases of flip_done timeouts, but it may
> address some of them.

I see.
Yeah, I've only very rarely seen that issue myself. Seems that the bug avoids 
driver devs, but it's very popular among end users.

> 
> (But timeouts aside, we *should* transition to vline since it's more
> reliable than vstartup.)

I agree.

> 
> To answer your questions: depending on the DCN generation, there can be a
> few things that affects vstartup firing:
> 
> * DPG - DCN can Dynamically Power Gate parts of the display pipe when a
>   self-refresh capable eDP is connected. DPG is engaged when there's enough
>   static frames (detected thru drm_vblank_off) Once gated, even though the
> OTG (output timing generator) is still enabled, vstartup is masked. vline
> is unaffected.
> 
> * GSL - Driver can use the Global Sync Lock to block HW from latching onto
>   double-buffered registers during programming, to prevent HW from latching
> onto a partially programmed state. This will mask vstartup, but vline is
> unaffected. See dcn20_pipe_control_lock()
> 
> * MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can store fb
> data to allow for longer DRAM sleep. When scanning out from MALL, vstartup
> is masked, vline is unaffected.

Thanks for the explanation.
Just one more question: does DCN always mask the VSTARTUP interrupt under 
those conditions or is that configurable?

> 
> > Many users have experienced flip_done timeouts while playing games.
> > In that scenario, would any idle optimization be enabled or is there a "HW
> > lock"?
> 
> If the game stops submitting frames for ~15 refresh cycles, it's possible
> that PSR kicks in. Though I know there are plenty of reporters running on
> external without PSR support. If it's DGPUs, it's very likely due to MALL.
> A reporter I was debugging with said disabling MALL showed good results[1].
> If it's an APU with an external monitor, then that's less clear.
> 
> A lot of the reporters seem to be running Phoenix (DCN314), with a common
> symptom of DMUB timing out[2]. If a self-refresh panel is involved, then I'm
> curious if this vline2 patch would help. Hamza's recent patch[3] that
> enables various levels of reset may help to mitigate, but it doesn't fix
> the root-cause. I'm planning a branch with this patch and [3], along with
> debug dumps on flip_done timeouts for reporters to try.
> 

That's very nice to hear. I'm crossing my fingers that it works out.

> [1]https://lore.kernel.org/amd-gfx/e415c38b-4102-40e4-a195-0256caf34802@m1k.
> cloud/ [2]https://gitlab.freedesktop.org/drm/amd/-/work_items/4831
> [3]https://lore.kernel.org/lkml/20260505182105.420525-2-someguy@effective-li
> ght.com/
> >> DCN hardware provides 3 generic OTG interrupts that can be programmed
> >> to>> fire on a specific line. Vline 0 and 1 are currently reserved, with
> >> vline2 available to use for event delivery. These interrupts cannot be
> >> masked, as long as the OTG is active.
> >> 
> >> [How]
> >> 
> >> Switch to vline2 for vblank handling. Today, DC will program the
> >> vline2 position to at vupdate -- the point at which HW latches to
> >> double-buffered registers.
> >> 
> >> Since all the vline interrupt types share the same interrupt src_id,
> >> refactor the existing vline0 infrastructure to allow for all the vline0,
> >> 1, and 2 types.
> >> 
> >> Since this is intended to replace vstartup for DCN, use the same handler
> >> logic, but be careful to leave DCE on vstartup.
> > 
> > Why not also switch DCE?
> > Does DCE not have the vline interrupts or does it not have the same issue
> > with the vstartup interrupt?
> 
> I didn't want to touch DCE since I don't have information on how these
> interrupts behave on them, and I didn't want to regress anything. Would need
> to do some digging to find out.
> 

Do we have any reports of these page flip timeouts on DCE?
Maybe it's better to leave DCE well enough alone if the issue doesn't exist 
there. (I have never seen one, but that doesn't mean it doesn't exist.)

Best regards,
Timur






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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-06 22:03     ` Timur Kristóf
@ 2026-05-07  6:15       ` Shengyu Qu
  2026-05-07 14:08       ` Leo Li
  1 sibling, 0 replies; 9+ messages in thread
From: Shengyu Qu @ 2026-05-07  6:15 UTC (permalink / raw)
  To: Timur Kristóf, amd-gfx, Leo Li
  Cc: wiagn233, Harry.Wentland, Aurabindo.Pillai, mario.limonciello,
	sysdadmin


[-- Attachment #1.1.1: Type: text/plain, Size: 5659 bytes --]


在 2026/5/7 06:03, Timur Kristóf 写道:
> On Wednesday, May 6, 2026 10:00:12 PM Central European Summer Time Leo Li
> wrote:
>> On 2026-05-04 16:54, Timur Kristóf wrote:
>>> On Monday, May 4, 2026 8:36:49 PM Central European Summer Time
>>>
>>> sunpeng.li@amd.com wrote:
>>>> From: Leo Li<sunpeng.li@amd.com>
>>>>
>>>> [Why]
>>>>
>>>> VStartup is an OTG event that fires when the pixel pipeline prepares for
>>>> pixel scanout of the next frame. It was previously used to deliver
>>>> vblank events for commits that do not trigger a fb address update, and
>>>> hence a pflip interrupt (hw cursor updates, for example).
>>>>
>>>> The issue with vstartup is that HW can mask the interrupt in cases where
>>>> idle optimizations are enabled or when a HW lock is active. This could
>>>> the explain the range of flip_done timeouts frequently seen in the wild.
>>> Can you help me understand how that could happen with vstartup?
>>> Specifically, what is a "HW lock" and when is it active?
>> Hi Timur,
>>
>> I should've prefaced this patch to say that this is a theoretical fix. I
>> haven't been able to reproduce the timeout issues myself, and this patch
>> came out of internal discussions with folks more familiar with the HW. I
>> don't think this will fix *all* cases of flip_done timeouts, but it may
>> address some of them.
> I see.
> Yeah, I've only very rarely seen that issue myself. Seems that the bug avoids
> driver devs, but it's very popular among end users.

Btw according to Michele's test result, such issue would be hidden by

debug options due to code running slower:

https://lore.kernel.org/amd-gfx/20260217191632.1243826-1-sysdadmin@m1k.cloud/


>> (But timeouts aside, we *should* transition to vline since it's more
>> reliable than vstartup.)
> I agree.
>
>> To answer your questions: depending on the DCN generation, there can be a
>> few things that affects vstartup firing:
>>
>> * DPG - DCN can Dynamically Power Gate parts of the display pipe when a
>>    self-refresh capable eDP is connected. DPG is engaged when there's enough
>>    static frames (detected thru drm_vblank_off) Once gated, even though the
>> OTG (output timing generator) is still enabled, vstartup is masked. vline
>> is unaffected.
>>
>> * GSL - Driver can use the Global Sync Lock to block HW from latching onto
>>    double-buffered registers during programming, to prevent HW from latching
>> onto a partially programmed state. This will mask vstartup, but vline is
>> unaffected. See dcn20_pipe_control_lock()
>>
>> * MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can store fb
>> data to allow for longer DRAM sleep. When scanning out from MALL, vstartup
>> is masked, vline is unaffected.
> Thanks for the explanation.
> Just one more question: does DCN always mask the VSTARTUP interrupt under
> those conditions or is that configurable?
>
>>> Many users have experienced flip_done timeouts while playing games.
>>> In that scenario, would any idle optimization be enabled or is there a "HW
>>> lock"?
>> If the game stops submitting frames for ~15 refresh cycles, it's possible
>> that PSR kicks in. Though I know there are plenty of reporters running on
>> external without PSR support. If it's DGPUs, it's very likely due to MALL.
>> A reporter I was debugging with said disabling MALL showed good results[1].
>> If it's an APU with an external monitor, then that's less clear.
>>
>> A lot of the reporters seem to be running Phoenix (DCN314), with a common
>> symptom of DMUB timing out[2]. If a self-refresh panel is involved, then I'm
>> curious if this vline2 patch would help. Hamza's recent patch[3] that
>> enables various levels of reset may help to mitigate, but it doesn't fix
>> the root-cause. I'm planning a branch with this patch and [3], along with
>> debug dumps on flip_done timeouts for reporters to try.
>>
> That's very nice to hear. I'm crossing my fingers that it works out.
>
>> [1]https://lore.kernel.org/amd-gfx/e415c38b-4102-40e4-a195-0256caf34802@m1k.
>> cloud/ [2]https://gitlab.freedesktop.org/drm/amd/-/work_items/4831
>> [3]https://lore.kernel.org/lkml/20260505182105.420525-2-someguy@effective-li
>> ght.com/
>>>> DCN hardware provides 3 generic OTG interrupts that can be programmed
>>>> to>> fire on a specific line. Vline 0 and 1 are currently reserved, with
>>>> vline2 available to use for event delivery. These interrupts cannot be
>>>> masked, as long as the OTG is active.
>>>>
>>>> [How]
>>>>
>>>> Switch to vline2 for vblank handling. Today, DC will program the
>>>> vline2 position to at vupdate -- the point at which HW latches to
>>>> double-buffered registers.
>>>>
>>>> Since all the vline interrupt types share the same interrupt src_id,
>>>> refactor the existing vline0 infrastructure to allow for all the vline0,
>>>> 1, and 2 types.
>>>>
>>>> Since this is intended to replace vstartup for DCN, use the same handler
>>>> logic, but be careful to leave DCE on vstartup.
>>> Why not also switch DCE?
>>> Does DCE not have the vline interrupts or does it not have the same issue
>>> with the vstartup interrupt?
>> I didn't want to touch DCE since I don't have information on how these
>> interrupts behave on them, and I didn't want to regress anything. Would need
>> to do some digging to find out.
>>
> Do we have any reports of these page flip timeouts on DCE?
> Maybe it's better to leave DCE well enough alone if the issue doesn't exist
> there. (I have never seen one, but that doesn't mean it doesn't exist.)
>
> Best regards,
> Timur
>
>
>
>
>

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 11341 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-06 22:03     ` Timur Kristóf
  2026-05-07  6:15       ` Shengyu Qu
@ 2026-05-07 14:08       ` Leo Li
  1 sibling, 0 replies; 9+ messages in thread
From: Leo Li @ 2026-05-07 14:08 UTC (permalink / raw)
  To: Timur Kristóf, amd-gfx
  Cc: Harry.Wentland, Aurabindo.Pillai, mario.limonciello, wiagn233,
	sysdadmin



On 2026-05-06 18:03, Timur Kristóf wrote:
> Thanks for the explanation.
> Just one more question: does DCN always mask the VSTARTUP interrupt under 
> those conditions or is that configurable?

AFAIK, yes. The masking is part of HW operation and not something we can
toggle (short of disabling the features that cause the masking conditions)

- Leo

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

* Re: [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup
  2026-05-04 18:36 [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup sunpeng.li
  2026-05-04 20:54 ` Timur Kristóf
@ 2026-05-10  6:06 ` Shengyu Qu
  1 sibling, 0 replies; 9+ messages in thread
From: Shengyu Qu @ 2026-05-10  6:06 UTC (permalink / raw)
  To: sunpeng.li, amd-gfx
  Cc: wiagn233, Harry.Wentland, Aurabindo.Pillai, mario.limonciello,
	sysdadmin


[-- Attachment #1.1.1: Type: text/plain, Size: 72640 bytes --]

Hi Leo,

Seems this patch is working:

https://gitlab.freedesktop.org/drm/amd/-/work_items/2950#note_3465004

Best regards,

Shengyu


在 2026/5/5 02:36, sunpeng.li@amd.com 写道:
> From: Leo Li <sunpeng.li@amd.com>
>
> [Why]
>
> VStartup is an OTG event that fires when the pixel pipeline prepares for
> pixel scanout of the next frame. It was previously used to deliver
> vblank events for commits that do not trigger a fb address update, and
> hence a pflip interrupt (hw cursor updates, for example).
>
> The issue with vstartup is that HW can mask the interrupt in cases where
> idle optimizations are enabled or when a HW lock is active. This could
> the explain the range of flip_done timeouts frequently seen in the wild.
>
> DCN hardware provides 3 generic OTG interrupts that can be programmed to
> fire on a specific line. Vline 0 and 1 are currently reserved, with
> vline2 available to use for event delivery. These interrupts cannot
> be masked, as long as the OTG is active.
>
> [How]
>
> Switch to vline2 for vblank handling. Today, DC will program the
> vline2 position to at vupdate -- the point at which HW latches to
> double-buffered registers.
>
> Since all the vline interrupt types share the same interrupt src_id,
> refactor the existing vline0 infrastructure to allow for all the vline0,
> 1, and 2 types.
>
> Since this is intended to replace vstartup for DCN, use the same handler
> logic, but be careful to leave DCE on vstartup.
>
> Signed-off-by: Leo Li <sunpeng.li@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   2 +-
>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 165 ++++++++++++------
>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   9 +
>   .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |  20 ++-
>   .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c |  99 +++++++++--
>   .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h |   7 +
>   .../display/dc/irq/dcn10/irq_service_dcn10.c  |  44 +++--
>   .../display/dc/irq/dcn20/irq_service_dcn20.c  |  43 +++--
>   .../dc/irq/dcn201/irq_service_dcn201.c        |  24 ++-
>   .../display/dc/irq/dcn21/irq_service_dcn21.c  |  44 +++--
>   .../display/dc/irq/dcn30/irq_service_dcn30.c  |  44 +++--
>   .../dc/irq/dcn302/irq_service_dcn302.c        |  43 +++--
>   .../dc/irq/dcn303/irq_service_dcn303.c        |  24 ++-
>   .../display/dc/irq/dcn31/irq_service_dcn31.c  |  44 +++--
>   .../dc/irq/dcn314/irq_service_dcn314.c        |  44 +++--
>   .../dc/irq/dcn315/irq_service_dcn315.c        |  44 +++--
>   .../display/dc/irq/dcn32/irq_service_dcn32.c  |  26 +--
>   .../display/dc/irq/dcn35/irq_service_dcn35.c  |  41 +++--
>   .../dc/irq/dcn351/irq_service_dcn351.c        |  43 +++--
>   .../display/dc/irq/dcn36/irq_service_dcn36.c  |  41 +++--
>   .../dc/irq/dcn401/irq_service_dcn401.c        |  25 +--
>   .../display/dc/irq/dcn42/irq_service_dcn42.c  |  26 +--
>   .../gpu/drm/amd/display/dc/irq/irq_service.h  |  23 +++
>   23 files changed, 673 insertions(+), 252 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 39894e38fee45..0d84293705107 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -947,7 +947,7 @@ struct amdgpu_device {
>   	/* For pre-DCE11. DCE11 and later are in "struct amdgpu_device->dm" */
>   	struct delayed_work         hotplug_work;
>   	struct amdgpu_irq_src		crtc_irq;
> -	struct amdgpu_irq_src		vline0_irq;
> +	struct amdgpu_irq_src		vline_irq;
>   	struct amdgpu_irq_src		vupdate_irq;
>   	struct amdgpu_irq_src		pageflip_irq;
>   	struct amdgpu_irq_src		hpd_irq;
> 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 3fa4dbda4517c..429f8df17c5d1 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -646,7 +646,8 @@ static void dm_vupdate_high_irq(void *interrupt_params)
>    * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK
>    * event handler.
>    */
> -static void dm_crtc_high_irq(void *interrupt_params)
> +static void __dm_crtc_high_irq(void *interrupt_params,
> +			     int otg_inst)
>   {
>   	struct common_irq_params *irq_params = interrupt_params;
>   	struct amdgpu_device *adev = irq_params->adev;
> @@ -655,7 +656,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
>   	unsigned long flags;
>   	int vrr_active;
>   
> -	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
> +	acrtc = get_crtc_by_otg_inst(adev, otg_inst);
>   	if (!acrtc)
>   		return;
>   
> @@ -755,6 +756,13 @@ static void dm_crtc_high_irq(void *interrupt_params)
>   	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
>   }
>   
> +static void dm_crtc_high_irq(void *interrupt_params)
> +{
> +	struct common_irq_params *irq_params = interrupt_params;
> +	__dm_crtc_high_irq(interrupt_params,
> +			   irq_params->irq_src - DC_IRQ_SOURCE_VBLANK1);
> +}
> +
>   #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
>   /**
>    * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
> @@ -778,6 +786,17 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
>   }
>   #endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
>   
> +
> +/**
> + * Same as dm_crtc_high_irq, but driven by the vline2 interrupt instead.
> + */
> +static void dm_dcn_vertical_interrupt2_high_irq(void *interrupt_params)
> +{
> +	struct common_irq_params *irq_params = interrupt_params;
> +	__dm_crtc_high_irq(interrupt_params,
> +			   irq_params->irq_src - DC_IRQ_SOURCE_DC1_VLINE2);
> +}
> +
>   /**
>    * dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
>    * @adev: amdgpu_device pointer
> @@ -4752,15 +4771,13 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev)
>   	return r;
>   }
>   
> -/* Register IRQ sources and initialize IRQ callbacks */
> -static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
> +
> +static int dcn10_register_vline_irq_handlers(struct amdgpu_device *adev)
>   {
>   	struct dc *dc = adev->dm.dc;
>   	struct common_irq_params *c_irq_params;
>   	struct dc_interrupt_params int_params = {0};
> -	int r;
> -	int i;
> -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> +	int r, i;
>   	static const unsigned int vrtl_int_srcid[] = {
>   		DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
>   		DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
> @@ -4769,89 +4786,127 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
>   		DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
>   		DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL
>   	};
> +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> +	static const unsigned int vrtl0_int_ctxid[] = {
> +		DCN_1_0__CTXID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG3_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG4_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
> +		DCN_1_0__CTXID__OTG6_VERTICAL_INTERRUPT0_CONTROL
> +	};
>   #endif
> +	static const unsigned int vrtl2_int_ctxid[] = {
> +		DCN_1_0__CTXID__OTG1_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG2_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG3_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG4_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG5_VERTICAL_INTERRUPT2_CONTROL,
> +		DCN_1_0__CTXID__OTG6_VERTICAL_INTERRUPT2_CONTROL
> +	};
>   
>   	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
>   	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
>   
> -	/*
> -	 * Actions of amdgpu_irq_add_id():
> -	 * 1. Register a set() function with base driver.
> -	 *    Base driver will call set() function to enable/disable an
> -	 *    interrupt in DC hardware.
> -	 * 2. Register amdgpu_dm_irq_handler().
> -	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
> -	 *    coming from DC hardware.
> -	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
> -	 *    for acknowledging and handling.
> -	 */
> -
> -	/* Use VSTARTUP interrupt */
> -	for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP;
> -			i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1;
> -			i++) {
> -		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq);
> +	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
> +		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
> +				vrtl_int_srcid[i], &adev->vline_irq);
>   
>   		if (r) {
> -			drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n");
> +			drm_err(adev_to_drm(adev),
> +				"Failed to add vline0/1/2 irq id!\n");
>   			return r;
>   		}
>   
> +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> +		/* Register vline0 */
>   		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
>   		int_params.irq_source =
> -			dc_interrupt_to_irq_source(dc, i, 0);
> +			dc_interrupt_to_irq_source(dc,
> +						   vrtl_int_srcid[i],
> +						   vrtl0_int_ctxid[i]);
>   
>   		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
> -			int_params.irq_source  < DC_IRQ_SOURCE_VBLANK1 ||
> -			int_params.irq_source  > DC_IRQ_SOURCE_VBLANK6) {
> -			drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n");
> +			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 ||
> +			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) {
> +			drm_err(adev_to_drm(adev),
> +				"Failed to register vline0 irq!\n");
>   			return -EINVAL;
>   		}
>   
> -		c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
> +		c_irq_params = &adev->dm.vline0_params[int_params.irq_source
> +					- DC_IRQ_SOURCE_DC1_VLINE0];
>   
>   		c_irq_params->adev = adev;
>   		c_irq_params->irq_src = int_params.irq_source;
>   
>   		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
> -			dm_crtc_high_irq, c_irq_params))
> +			dm_dcn_vertical_interrupt0_high_irq,
> +			c_irq_params))
>   			return -ENOMEM;
> -	}
> -
> -	/* Use otg vertical line interrupt */
> -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> -	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
> -		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
> -				vrtl_int_srcid[i], &adev->vline0_irq);
> -
> -		if (r) {
> -			drm_err(adev_to_drm(adev), "Failed to add vline0 irq id!\n");
> -			return r;
> -		}
> -
> +#endif
> +		/*
> +		 * vline2 shares the same srcids as vline0, but different ctxid.
> +		 */
>   		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
>   		int_params.irq_source =
> -			dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0);
> +			dc_interrupt_to_irq_source(dc,
> +						   vrtl_int_srcid[i],
> +						   vrtl2_int_ctxid[i]);
>   
>   		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
> -			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 ||
> -			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) {
> -			drm_err(adev_to_drm(adev), "Failed to register vline0 irq!\n");
> +			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE2 ||
> +			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE2) {
> +			drm_err(adev_to_drm(adev),
> +				"Failed to register vline2 irq!\n");
>   			return -EINVAL;
>   		}
>   
> -		c_irq_params = &adev->dm.vline0_params[int_params.irq_source
> -					- DC_IRQ_SOURCE_DC1_VLINE0];
> +		c_irq_params = &adev->dm.vline2_params[int_params.irq_source
> +					- DC_IRQ_SOURCE_DC1_VLINE2];
>   
>   		c_irq_params->adev = adev;
>   		c_irq_params->irq_src = int_params.irq_source;
>   
>   		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
> -			dm_dcn_vertical_interrupt0_high_irq,
> +			dm_dcn_vertical_interrupt2_high_irq,
>   			c_irq_params))
>   			return -ENOMEM;
>   	}
> -#endif
> +
> +	return 0;
> +}
> +
> +/* Register IRQ sources and initialize IRQ callbacks */
> +static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
> +{
> +	struct dc *dc = adev->dm.dc;
> +	struct common_irq_params *c_irq_params;
> +	struct dc_interrupt_params int_params = {0};
> +	int r;
> +	int i;
> +
> +	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
> +	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
> +
> +	/*
> +	 * Actions of amdgpu_irq_add_id():
> +	 * 1. Register a set() function with base driver.
> +	 *    Base driver will call set() function to enable/disable an
> +	 *    interrupt in DC hardware.
> +	 * 2. Register amdgpu_dm_irq_handler().
> +	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
> +	 *    coming from DC hardware.
> +	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
> +	 *    for acknowledging and handling.
> +	 */
> +
> +	r = dcn10_register_vline_irq_handlers(adev);
> +	if (r) {
> +		drm_err(adev_to_drm(adev),
> +			"Failed to register vline interrupts\n");
> +		return r;
> +	}
>   
>   	/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to
>   	 * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx
> @@ -9541,7 +9596,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
>   			if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type))
>   				drm_err(dev, "DM_IRQ: Cannot get pageflip irq!\n");
>   #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> -			if (amdgpu_irq_get(adev, &adev->vline0_irq, irq_type))
> +			if (amdgpu_irq_get(adev, &adev->vline_irq,
> +					   DM_VLINE_IRQ(adev, 0, irq_type)))
>   				drm_err(dev, "DM_IRQ: Cannot get vline0 irq!\n");
>   #endif
>   		}
> @@ -9554,7 +9610,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
>   		case IP_VERSION(3, 0, 3):
>   		case IP_VERSION(3, 2, 0):
>   #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
> -			if (amdgpu_irq_put(adev, &adev->vline0_irq, irq_type))
> +			if (amdgpu_irq_put(adev, &adev->vline_irq,
> +					   DM_VLINE_IRQ(adev, 0, irq_type)))
>   				drm_err(dev, "DM_IRQ: Cannot put vline0 irq!\n");
>   #endif
>   			if (amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type))
> 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 1e0ccf58cdb8d..b4e785784a882 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -543,6 +543,15 @@ struct amdgpu_display_manager {
>   	struct common_irq_params
>   	vline0_params[DC_IRQ_SOURCE_DC6_VLINE0 - DC_IRQ_SOURCE_DC1_VLINE0 + 1];
>   
> +	/**
> +	 * @vline2_params:
> +	 *
> +	 * OTG vertical interrupt0 IRQ parameters, passed to registered
> +	 * handlers when triggered.
> +	 */
> +	struct common_irq_params
> +	vline2_params[DC_IRQ_SOURCE_DC6_VLINE2 - DC_IRQ_SOURCE_DC1_VLINE2 + 1];
> +
>   	/**
>   	 * @vupdate_params:
>   	 *
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> index efb19f675b0c2..0821b0996a85f 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> @@ -28,6 +28,7 @@
>   
>   #include "dc.h"
>   #include "amdgpu.h"
> +#include "amdgpu_dm_irq.h"
>   #include "amdgpu_dm_psr.h"
>   #include "amdgpu_dm_replay.h"
>   #include "amdgpu_dm_crtc.h"
> @@ -290,10 +291,19 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
>   
>   	/* crtc vblank or vstartup interrupt */
>   	if (enable) {
> -		rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
> +		/* vline only available on DCN+ */
> +		if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0)
> +			rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
> +		else
> +			rc = amdgpu_irq_get(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 2, irq_type));
>   		drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc);
>   	} else {
> -		rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
> +		if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0)
> +			rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
> +		else
> +			rc = amdgpu_irq_put(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 2, irq_type));
>   		drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc);
>   	}
>   
> @@ -323,10 +333,12 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
>   	/* crtc vline0 interrupt, only available on DCN+ */
>   	if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
>   		if (enable) {
> -			rc = amdgpu_irq_get(adev, &adev->vline0_irq, irq_type);
> +			rc = amdgpu_irq_get(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 0, irq_type));
>   			drm_dbg_vbl(crtc->dev, "Get vline0_irq ret=%d\n", rc);
>   		} else {
> -			rc = amdgpu_irq_put(adev, &adev->vline0_irq, irq_type);
> +			rc = amdgpu_irq_put(adev, &adev->vline_irq,
> +					    DM_VLINE_IRQ(adev, 0, irq_type));
>   			drm_dbg_vbl(crtc->dev, "Put vline0_irq ret=%d\n", rc);
>   		}
>   
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> index 5948e2a6219e3..757529af72ceb 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> @@ -769,18 +769,86 @@ static int amdgpu_dm_set_crtc_irq_state(struct amdgpu_device *adev,
>   		__func__);
>   }
>   
> -static int amdgpu_dm_set_vline0_irq_state(struct amdgpu_device *adev,
> -					struct amdgpu_irq_src *source,
> -					unsigned int crtc_id,
> -					enum amdgpu_interrupt_state state)
> +/**
> + * amdgpu_dm_set_vline_irq_state: Set interrupt state for vline
> + *
> + * Map base driver amdgpu_irq_update() -- called per interrupt src ID -- to
> + * their corresponding dc_irq_source, then set then to the requested state.
> + *
> + * Since all the vline0/1/2 interrupts have the same src_id, the standard
> + * amdgpu_irq_src.num_types mapping to the number of OTGs won't work. For vline,
> + * num_types will have to cover (number of different vline interrupt types) *
> + * (number of OTGs) types. For example, if there are 6 OTGS, then num_types =
> + * 3*6 = 18.
> + *
> + * This is only needed for the amdgpu_irq_src_funcs.set_irq implementation; the
> + * .process implementation is provided the interrupt vector, which contains both
> + * the src_id and ctx_id to uniquely map to the dc_irq_source.
> + *
> + * The vline_otg_id mapping is first by vline num, then by OTG num:
> + *
> + * | vline_otg_id | vline num | otg num |
> + * |--------------|-----------|---------|
> + * | 0            | 0         | 0       |
> + * | 1            | 0         | 1       |
> + * | ...          | ...       | ...     |
> + * | 5            | 0         | 5       |
> + * | 6            | 1         | 0       |
> + * | ...          | ...       | ...     |
> + * | 11           | 1         | 5       |
> + * | 12           | 2         | 0       |
> + * | ...          | ...       | ...     |
> + * | 17           | 2         | 5       |
> + */
> +static int amdgpu_dm_set_vline_irq_state(struct amdgpu_device *adev,
> +					 struct amdgpu_irq_src *source,
> +					 unsigned int vline_otg_id,
> +					 enum amdgpu_interrupt_state state)
>   {
> -	return dm_irq_state(
> -		adev,
> -		source,
> -		crtc_id,
> -		state,
> -		IRQ_TYPE_VLINE0,
> -		__func__);
> +	bool st;
> +	unsigned int vline_num, otg_num;
> +	enum dc_irq_source irq_source;
> +	struct dc *dc = adev->dm.dc;
> +	struct amdgpu_crtc *acrtc;
> +
> +	if (vline_otg_id >= 3 * adev->mode_info.num_crtc) {
> +		drm_err(adev_to_drm(adev),
> +			"Invalid vline map_id :%d\n", vline_otg_id);
> +		return -EINVAL;
> +	}
> +
> +	vline_num = vline_otg_id / adev->mode_info.num_crtc;
> +	otg_num = vline_otg_id % adev->mode_info.num_crtc;
> +	acrtc = adev->mode_info.crtcs[otg_num];
> +
> +	if (!acrtc) {
> +		drm_err(adev_to_drm(adev),
> +			"crtc is NULL at id : %d\n", otg_num);
> +		return 0;
> +	}
> +
> +	if (acrtc->otg_inst == -1)
> +		return 0;
> +
> +	if (vline_num == 0)
> +		irq_source = IRQ_TYPE_VLINE0 + otg_num;
> +	else if (vline_num == 1)
> +		irq_source = IRQ_TYPE_VLINE1 + otg_num;
> +	else if (vline_num == 2)
> +		irq_source = IRQ_TYPE_VLINE2 + otg_num;
> +	else {
> +		drm_err(adev_to_drm(adev),
> +			"Invalid vline num :%d\n", vline_num);
> +		return -EINVAL;
> +	}
> +
> +	st = (state == AMDGPU_IRQ_STATE_ENABLE);
> +
> +	if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
> +		dc_allow_idle_optimizations(dc, false);
> +
> +	dc_interrupt_set(adev->dm.dc, irq_source, st);
> +	return 0;
>   }
>   
>   static int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *adev,
> @@ -826,8 +894,8 @@ static const struct amdgpu_irq_src_funcs dm_crtc_irq_funcs = {
>   	.process = amdgpu_dm_irq_handler,
>   };
>   
> -static const struct amdgpu_irq_src_funcs dm_vline0_irq_funcs = {
> -	.set = amdgpu_dm_set_vline0_irq_state,
> +static const struct amdgpu_irq_src_funcs dm_vline_irq_funcs = {
> +	.set = amdgpu_dm_set_vline_irq_state,
>   	.process = amdgpu_dm_irq_handler,
>   };
>   
> @@ -861,8 +929,9 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
>   	adev->crtc_irq.num_types = adev->mode_info.num_crtc;
>   	adev->crtc_irq.funcs = &dm_crtc_irq_funcs;
>   
> -	adev->vline0_irq.num_types = adev->mode_info.num_crtc;
> -	adev->vline0_irq.funcs = &dm_vline0_irq_funcs;
> +	/* Number of vline types * num OTGs */
> +	adev->vline_irq.num_types = 3 * adev->mode_info.num_crtc;
> +	adev->vline_irq.funcs = &dm_vline_irq_funcs;
>   
>   	adev->dmub_outbox_irq.num_types = 1;
>   	adev->dmub_outbox_irq.funcs = &dm_dmub_outbox_irq_funcs;
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> index 4f6b58f4f90d7..a672b58b0f760 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> @@ -27,6 +27,13 @@
>   
>   #include "irq_types.h" /* DAL irq definitions */
>   
> +/*
> + * Get OTG vline irq id from vline num and otg num. See also
> + * amdgpu_dm_set_vline_irq_state()
> + */
> +#define DM_VLINE_IRQ(adev, vline_num, otg_num) \
> +	adev->mode_info.num_crtc * vline_num + otg_num
> +
>   /*
>    * Display Manager IRQ-related interfaces (for use by DAL).
>    */
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
> index 7dff8731f414e..a72fefb531e99 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c
> @@ -58,18 +58,6 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct irq_service *irq_servic
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE1;
>   	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
> @@ -95,6 +83,19 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct irq_service *irq_servic
>   	case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP6;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -157,6 +158,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
>   	.set = NULL,
>   	.ack = NULL
> @@ -239,6 +245,14 @@ static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dummy_irq_entry() \
>   	{\
>   		.funcs = &dummy_irq_info_funcs\
> @@ -353,6 +367,12 @@ irq_source_info_dcn10[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	vline0_int_entry(4),
>   	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>   };
>   
>   static const struct irq_service_funcs irq_service_funcs_dcn10 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
> index 34f9e8a9f488f..cbf65367cba5c 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
> @@ -59,18 +59,6 @@ static enum dc_irq_source to_dal_irq_source_dcn20(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -96,6 +84,19 @@ static enum dc_irq_source to_dal_irq_source_dcn20(
>   	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -163,6 +164,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -244,6 +250,13 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
>   #define dummy_irq_entry() \
>   	{\
>   		.funcs = &dummy_irq_info_funcs\
> @@ -358,6 +371,12 @@ irq_source_info_dcn20[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	vline0_int_entry(4),
>   	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>   };
>   
>   static const struct irq_service_funcs irq_service_funcs_dcn20 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
> index 6417011d22463..7ab8317961734 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
> @@ -47,10 +47,6 @@ static enum dc_irq_source to_dal_irq_source_dcn201(
>   		return DC_IRQ_SOURCE_VBLANK1;
>   	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK2;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -59,6 +55,12 @@ static enum dc_irq_source to_dal_irq_source_dcn201(
>   		return DC_IRQ_SOURCE_VUPDATE1;
>   	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE2;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -104,6 +106,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.set = NULL,
>   	.ack = NULL
>   };
> +
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
>   static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
>   	.set = NULL,
>   	.ack = NULL
> @@ -195,6 +202,13 @@ static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
>   #define dummy_irq_entry() \
>   	{\
>   		.funcs = &dummy_irq_info_funcs\
> @@ -309,6 +323,8 @@ irq_source_info_dcn201[DAL_IRQ_SOURCES_NUMBER] = {
>   	dummy_irq_entry(),
>   	dummy_irq_entry(),
>   	dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
>   };
>   
>   static const struct irq_service_funcs irq_service_funcs_dcn201 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
> index 05f7877d2d6c8..da1ebb9467c9d 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
> @@ -60,18 +60,6 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct irq_service *irq_servic
>   		return DC_IRQ_SOURCE_VBLANK6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -97,6 +85,19 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct irq_service *irq_servic
>   	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -170,6 +171,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
>   
> @@ -266,6 +272,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dmub_outbox_int_entry()\
>   	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>   		IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -385,6 +399,12 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	vline0_int_entry(4),
>   	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>   	dmub_outbox_int_entry(),
>   };
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
> index 3a7f76364000e..d4af3555d14ef 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
> @@ -68,18 +68,6 @@ static enum dc_irq_source to_dal_irq_source_dcn30(
>   		return DC_IRQ_SOURCE_VBLANK6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -105,6 +93,19 @@ static enum dc_irq_source to_dal_irq_source_dcn30(
>   	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -177,6 +178,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -280,6 +286,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dummy_irq_entry() \
>   	{\
>   		.funcs = &dummy_irq_info_funcs\
> @@ -394,6 +408,12 @@ irq_source_info_dcn30[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	vline0_int_entry(4),
>   	vline0_int_entry(5),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
> +	vline2_int_entry(4),
> +	vline2_int_entry(5),
>   	dmub_trace_int_entry(),
>   };
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
> index f4dfc96310c73..14631b78715a0 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c
> @@ -55,18 +55,6 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct irq_service *irq_servi
>   		return DC_IRQ_SOURCE_VBLANK6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -92,6 +80,19 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct irq_service *irq_servi
>   	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -164,6 +165,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -262,6 +268,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
>   
>   #define i2c_int_entry(reg_num) \
> @@ -363,6 +377,11 @@ static const struct irq_source_info irq_source_info_dcn302[DAL_IRQ_SOURCES_NUMBE
>   		vline0_int_entry(2),
>   		vline0_int_entry(3),
>   		vline0_int_entry(4),
> +		vline2_int_entry(0),
> +		vline2_int_entry(1),
> +		vline2_int_entry(2),
> +		vline2_int_entry(3),
> +		vline2_int_entry(4),
>   		dmub_trace_int_entry(),
>   };
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
> index fdc7624461ac2..bd4768afafe43 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
> @@ -46,10 +46,6 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_servi
>   		return DC_IRQ_SOURCE_VBLANK1;
>   	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK2;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -59,6 +55,11 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_servi
>   	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
>   		return DC_IRQ_SOURCE_VUPDATE2;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -110,6 +111,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -186,6 +192,14 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   		.funcs = &vline0_irq_info_funcs\
>   	}
>   
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
>   
>   #define i2c_int_entry(reg_num) \
> @@ -260,6 +274,8 @@ static const struct irq_source_info irq_source_info_dcn303[DAL_IRQ_SOURCES_NUMBE
>   		vblank_int_entry(1),
>   		vline0_int_entry(0),
>   		vline0_int_entry(1),
> +		vline2_int_entry(0),
> +		vline2_int_entry(1),
>   };
>   
>   static const struct irq_service_funcs irq_service_funcs_dcn303 = {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
> index 5fecd03f94999..9704f90cd0407 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c
> @@ -56,18 +56,6 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct irq_service *irq_servic
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -94,6 +82,20 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct irq_service *irq_servic
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -166,6 +168,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -260,6 +267,15 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
>   		.funcs = &vline0_irq_info_funcs\
>   	}
> +
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dmub_outbox_int_entry()\
>   	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>   		IRQ_REG_ENTRY_DMUB(\
> @@ -376,6 +392,10 @@ irq_source_info_dcn31[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
>   	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
>   	dmub_outbox_int_entry(),
>   };
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
> index a214f13c5a978..afa4a17ce2f0e 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c
> @@ -58,18 +58,6 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct irq_service *irq_servi
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -96,6 +84,20 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct irq_service *irq_servi
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -168,6 +170,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -262,6 +269,15 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
>   		.funcs = &vline0_irq_info_funcs\
>   	}
> +
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dmub_outbox_int_entry()\
>   	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>   		IRQ_REG_ENTRY_DMUB(\
> @@ -378,6 +394,10 @@ irq_source_info_dcn314[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
>   	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
>   	dmub_outbox_int_entry(),
>   };
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
> index dc2dced7db85d..b64fada140fb0 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
> @@ -63,18 +63,6 @@ static enum dc_irq_source to_dal_irq_source_dcn315(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -101,6 +89,20 @@ static enum dc_irq_source to_dal_irq_source_dcn315(
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -173,6 +175,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
>   
> @@ -267,6 +274,15 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
>   		.funcs = &vline0_irq_info_funcs\
>   	}
> +
> +#define vline2_int_entry(reg_num)\
> +	[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
> +		IRQ_REG_ENTRY(OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		.funcs = &vline2_irq_info_funcs\
> +	}
> +
>   #define dmub_outbox_int_entry()\
>   	[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
>   		IRQ_REG_ENTRY_DMUB(\
> @@ -383,6 +399,10 @@ irq_source_info_dcn315[DAL_IRQ_SOURCES_NUMBER] = {
>   	vline0_int_entry(3),
>   	[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
>   	[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
> +	vline2_int_entry(0),
> +	vline2_int_entry(1),
> +	vline2_int_entry(2),
> +	vline2_int_entry(3),
>   	dmub_outbox_int_entry(),
>   };
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
> index 3090ceb664332..f347e2ab7ced3 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c
> @@ -57,18 +57,6 @@ static enum dc_irq_source to_dal_irq_source_dcn32(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -95,6 +83,20 @@ static enum dc_irq_source to_dal_irq_source_dcn32(
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
> index 27289279b21ca..d70754f6ac0b6 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c
> @@ -55,18 +55,6 @@ static enum dc_irq_source to_dal_irq_source_dcn35(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -93,6 +81,20 @@ static enum dc_irq_source to_dal_irq_source_dcn35(
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -165,6 +167,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
>   
> @@ -249,6 +256,12 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
>   		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
>   
> +#define vline2_int_entry(reg_num)\
> +		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs = &vline2_irq_info_funcs\
> +
>   #define dmub_outbox_int_entry()\
>   		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
>   			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -362,6 +375,10 @@ static struct irq_source_info_funcs dummy_irq_info_funcs = {
>   	vline0_int_entry(3); \
>   	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
>   	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
> +	vline2_int_entry(0); \
> +	vline2_int_entry(1); \
> +	vline2_int_entry(2); \
> +	vline2_int_entry(3); \
>   	dmub_outbox_int_entry()
>   
>   #define dcn35_irq_init() \
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
> index 7404b572a4e96..8948cbb03011e 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c
> @@ -4,8 +4,6 @@
>   #include "dm_services.h"
>   #include "include/logger_interface.h"
>   #include "../dce110/irq_service_dce110.h"
> -
> -
>   #include "dcn/dcn_3_5_1_offset.h"
>   #include "dcn/dcn_3_5_1_sh_mask.h"
>   
> @@ -34,18 +32,6 @@ static enum dc_irq_source to_dal_irq_source_dcn351(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -72,6 +58,20 @@ static enum dc_irq_source to_dal_irq_source_dcn351(
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -144,6 +144,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
>   
> @@ -228,6 +233,12 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
>   		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
>   
> +#define vline2_int_entry(reg_num)\
> +		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs = &vline2_irq_info_funcs\
> +
>   #define dmub_outbox_int_entry()\
>   		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
>   			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -342,6 +353,10 @@ static struct irq_source_info_funcs dummy_irq_info_funcs = {
>   	vline0_int_entry(3); \
>   	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
>   	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
> +	vline2_int_entry(0); \
> +	vline2_int_entry(1); \
> +	vline2_int_entry(2); \
> +	vline2_int_entry(3); \
>   	dmub_outbox_int_entry(); \
>   }
>   
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
> index 3dd47a99f568d..5525a69d0ffd2 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c
> @@ -33,18 +33,6 @@ static enum dc_irq_source to_dal_irq_source_dcn36(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -71,6 +59,20 @@ static enum dc_irq_source to_dal_irq_source_dcn36(
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> @@ -143,6 +145,11 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   	.ack = NULL
>   };
>   
> +static struct irq_source_info_funcs vline2_irq_info_funcs = {
> +	.set = NULL,
> +	.ack = NULL
> +};
> +
>   #undef BASE_INNER
>   #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
>   
> @@ -227,6 +234,12 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = {
>   			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
>   		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
>   
> +#define vline2_int_entry(reg_num)\
> +		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE2, OTG, reg_num,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
> +			OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
> +		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num].funcs = &vline2_irq_info_funcs\
> +
>   #define dmub_outbox_int_entry()\
>   		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
>   			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
> @@ -339,6 +352,10 @@ static struct irq_source_info_funcs dummy_irq_info_funcs = {
>   	vline0_int_entry(1); \
>   	vline0_int_entry(2); \
>   	vline0_int_entry(3); \
> +	vline2_int_entry(0); \
> +	vline2_int_entry(1); \
> +	vline2_int_entry(2); \
> +	vline2_int_entry(3); \
>   	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
>   	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
>   	dmub_outbox_int_entry(); \
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
> index 42d9d42ba0b99..ce264333e3cf4 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c
> @@ -36,18 +36,6 @@ static enum dc_irq_source to_dal_irq_source_dcn401(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -75,6 +63,19 @@ static enum dc_irq_source to_dal_irq_source_dcn401(
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
>   
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
> index f4d1ce9079ded..f9113d9f3c3ee 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
> +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c
> @@ -35,18 +35,6 @@ static enum dc_irq_source to_dal_irq_source_dcn42(
>   		return DC_IRQ_SOURCE_VBLANK5;
>   	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
>   		return DC_IRQ_SOURCE_VBLANK6;
> -	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC1_VLINE0;
> -	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC2_VLINE0;
> -	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC3_VLINE0;
> -	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC4_VLINE0;
> -	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC5_VLINE0;
> -	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
> -		return DC_IRQ_SOURCE_DC6_VLINE0;
>   	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
>   		return DC_IRQ_SOURCE_PFLIP1;
>   	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
> @@ -73,6 +61,20 @@ static enum dc_irq_source to_dal_irq_source_dcn42(
>   		return DC_IRQ_SOURCE_VUPDATE6;
>   	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
>   		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
> +
> +	case DCN_VINT_SRCID(1, 0):
> +		DCN_VINT_TO_DC_IRQSRC(1, ext_id);
> +	case DCN_VINT_SRCID(2, 0):
> +		DCN_VINT_TO_DC_IRQSRC(2, ext_id);
> +	case DCN_VINT_SRCID(3, 0):
> +		DCN_VINT_TO_DC_IRQSRC(3, ext_id);
> +	case DCN_VINT_SRCID(4, 0):
> +		DCN_VINT_TO_DC_IRQSRC(4, ext_id);
> +	case DCN_VINT_SRCID(5, 0):
> +		DCN_VINT_TO_DC_IRQSRC(5, ext_id);
> +	case DCN_VINT_SRCID(6, 0):
> +		DCN_VINT_TO_DC_IRQSRC(6, ext_id);
> +
>   	case DCN_1_0__SRCID__DC_HPD1_INT:
>   		/* generic src_id for all HPD and HPDRX interrupts */
>   		switch (ext_id) {
> diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
> index bbcef3d2fe334..ba2bca88e4ccb 100644
> --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
> +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
> @@ -30,6 +30,29 @@
>   
>   #include "irq_types.h"
>   
> +/*
> + * Helper to get vertical interrupt src/ctx id by OTG instance and vint number
> + */
> +#define DCN_VINT_SRCID(otg_inst, vint_num) \
> +	DCN_1_0__SRCID__OTG ## otg_inst ## _VERTICAL_INTERRUPT ## vint_num ## _CONTROL
> +#define DCN_VINT_CTXID(otg_inst, vint_num) \
> +	DCN_1_0__CTXID__OTG ## otg_inst ## _VERTICAL_INTERRUPT ## vint_num ## _CONTROL
> +#define DC_VINT_IRQSRC(otg_inst, vint_num) \
> +	DC_IRQ_SOURCE_DC ## otg_inst ## _VLINE ## vint_num
> +
> +/* Helper to map vertical interrupt src/ctx id to DC irq source enum */
> +#define DCN_VINT_TO_DC_IRQSRC(otg_inst, ext_id) \
> +	switch (ext_id) { \
> +	case DCN_VINT_CTXID(otg_inst, 0): \
> +		return DC_VINT_IRQSRC(otg_inst, 0); \
> +	case DCN_VINT_CTXID(otg_inst, 1): \
> +		return DC_VINT_IRQSRC(otg_inst, 1); \
> +	case DCN_VINT_CTXID(otg_inst, 2): \
> +		return DC_VINT_IRQSRC(otg_inst, 2); \
> +	default: \
> +		return DC_IRQ_SOURCE_INVALID; \
> +	}
> +
>   struct irq_service;
>   struct irq_source_info;
>   

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 12161 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

end of thread, other threads:[~2026-05-11  7:30 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-04 18:36 [PATCH] drm/amd/display: Use vline2 interrupt on DCN instead of vstartup sunpeng.li
2026-05-04 20:54 ` Timur Kristóf
2026-05-06 20:00   ` Leo Li
2026-05-06 20:32     ` Harry Wentland
2026-05-06 21:57       ` Timur Kristóf
2026-05-06 22:03     ` Timur Kristóf
2026-05-07  6:15       ` Shengyu Qu
2026-05-07 14:08       ` Leo Li
2026-05-10  6:06 ` Shengyu Qu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox