diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index 0f4fdb2..916c532 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -682,27 +682,30 @@ void dispc_runtime_put(void)
 	WARN_ON(r < 0 && r != -ENOSYS);
 }
 
-static u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
+static const char *dispc_get_ovl_name(enum omap_plane_id plane)
 {
-	return mgr_desc[channel].vsync_irq;
-}
-
-static u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
-{
-	if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
-		return 0;
+	static const char *ovl_names[] = {
+		[OMAP_DSS_GFX]		= "GFX",
+		[OMAP_DSS_VIDEO1]	= "VID1",
+		[OMAP_DSS_VIDEO2]	= "VID2",
+		[OMAP_DSS_VIDEO3]	= "VID3",
+		[OMAP_DSS_WB]		= "WB",
+	};
 
-	return mgr_desc[channel].framedone_irq;
+	return ovl_names[plane];
 }
 
-static u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
+static const char *dispc_get_mgr_name(enum omap_channel channel)
 {
-	return mgr_desc[channel].sync_lost_irq;
+	return mgr_desc[channel].name;
 }
 
-u32 dispc_wb_get_framedone_irq(void)
+static bool dispc_mgr_has_framedone(enum omap_channel channel)
 {
-	return DISPC_IRQ_FRAMEDONEWB;
+	if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
+		return false;
+
+	return true;
 }
 
 static void dispc_mgr_enable(enum omap_channel channel, bool enable)
@@ -3588,6 +3591,120 @@ static void dispc_write_irqenable(u32 mask)
 	dispc_read_reg(DISPC_IRQENABLE);
 }
 
+static void dispc_hw_to_api_irq(u32 hw, struct dss_irq *api)
+{
+	memset(api, 0, sizeof(*api));
+
+	if (hw & DISPC_IRQ_OCP_ERR)
+		api->device |= DSS_IRQ_DEVICE_OCP_ERR;
+
+	if (hw & DISPC_IRQ_FRAMEDONE)
+		api->channel[0] |= DSS_IRQ_MGR_FRAME_DONE;
+	if (hw & DISPC_IRQ_VSYNC)
+		api->channel[0] |= DSS_IRQ_MGR_VSYNC_EVEN;
+	if (hw & DISPC_IRQ_SYNC_LOST)
+		api->channel[0] |= DSS_IRQ_MGR_SYNC_LOST;
+
+	if (hw & DISPC_IRQ_EVSYNC_EVEN)
+		api->channel[1] |= DSS_IRQ_MGR_VSYNC_EVEN;
+	if (hw & DISPC_IRQ_EVSYNC_ODD)
+		api->channel[1] |= DSS_IRQ_MGR_VSYNC_ODD;
+	if (hw & DISPC_IRQ_SYNC_LOST_DIGIT)
+		api->channel[1] |= DSS_IRQ_MGR_SYNC_LOST;
+	if (hw & DISPC_IRQ_FRAMEDONETV)
+		api->channel[1] |= DSS_IRQ_MGR_FRAME_DONE;
+
+	if (hw & DISPC_IRQ_SYNC_LOST2)
+		api->channel[2] |= DSS_IRQ_MGR_SYNC_LOST;
+	if (hw & DISPC_IRQ_VSYNC2)
+		api->channel[2] |= DSS_IRQ_MGR_VSYNC_EVEN;
+	if (hw & DISPC_IRQ_FRAMEDONE2)
+		api->channel[2] |= DSS_IRQ_MGR_FRAME_DONE;
+
+	if (hw & DISPC_IRQ_SYNC_LOST3)
+		api->channel[3] |= DSS_IRQ_MGR_SYNC_LOST;
+	if (hw & DISPC_IRQ_VSYNC3)
+		api->channel[3] |= DSS_IRQ_MGR_VSYNC_EVEN;
+	if (hw & DISPC_IRQ_FRAMEDONE3)
+		api->channel[3] |= DSS_IRQ_MGR_FRAME_DONE;
+
+	if (hw & DISPC_IRQ_GFX_FIFO_UNDERFLOW)
+		api->ovl[0] |= DSS_IRQ_OVL_FIFO_UNDERFLOW;
+	if (hw & DISPC_IRQ_VID1_FIFO_UNDERFLOW)
+		api->ovl[1] |= DSS_IRQ_OVL_FIFO_UNDERFLOW;
+	if (hw & DISPC_IRQ_VID2_FIFO_UNDERFLOW)
+		api->ovl[2] |= DSS_IRQ_OVL_FIFO_UNDERFLOW;
+	if (hw & DISPC_IRQ_VID3_FIFO_UNDERFLOW)
+		api->ovl[3] |= DSS_IRQ_OVL_FIFO_UNDERFLOW;
+}
+
+static u32 dispc_api_to_hw_irq(const struct dss_irq *api)
+{
+	u32 hw = 0;
+
+	if (api->device & DSS_IRQ_DEVICE_OCP_ERR)
+		hw |= DISPC_IRQ_OCP_ERR;
+
+	if (api->channel[0] & DSS_IRQ_MGR_FRAME_DONE)
+		hw |= DISPC_IRQ_FRAMEDONE;
+	if (api->channel[0] & DSS_IRQ_MGR_VSYNC_EVEN)
+		hw |= DISPC_IRQ_VSYNC;
+	if (api->channel[0] & DSS_IRQ_MGR_SYNC_LOST)
+		hw |= DISPC_IRQ_SYNC_LOST;
+
+	if (api->channel[1] & DSS_IRQ_MGR_VSYNC_EVEN)
+		hw |= DISPC_IRQ_EVSYNC_EVEN;
+	if (api->channel[1] & DSS_IRQ_MGR_VSYNC_ODD)
+		hw |= DISPC_IRQ_EVSYNC_ODD;
+	if (api->channel[1] & DSS_IRQ_MGR_SYNC_LOST)
+		hw |= DISPC_IRQ_SYNC_LOST_DIGIT;
+	if (api->channel[1] & DSS_IRQ_MGR_FRAME_DONE)
+		hw |= DISPC_IRQ_FRAMEDONETV;
+
+	if (api->channel[2] & DSS_IRQ_MGR_SYNC_LOST)
+		hw |= DISPC_IRQ_SYNC_LOST2;
+	if (api->channel[2] & DSS_IRQ_MGR_VSYNC_EVEN)
+		hw |= DISPC_IRQ_VSYNC2;
+	if (api->channel[2] & DSS_IRQ_MGR_FRAME_DONE)
+		hw |= DISPC_IRQ_FRAMEDONE2;
+
+	if (api->channel[3] & DSS_IRQ_MGR_SYNC_LOST)
+		hw |= DISPC_IRQ_SYNC_LOST3;
+	if (api->channel[3] & DSS_IRQ_MGR_VSYNC_EVEN)
+		hw |= DISPC_IRQ_VSYNC3;
+	if (api->channel[3] & DSS_IRQ_MGR_FRAME_DONE)
+		hw |= DISPC_IRQ_FRAMEDONE3;
+
+	if (api->ovl[0] & DSS_IRQ_OVL_FIFO_UNDERFLOW)
+		hw |= DISPC_IRQ_GFX_FIFO_UNDERFLOW;
+	if (api->ovl[1] & DSS_IRQ_OVL_FIFO_UNDERFLOW)
+		hw |= DISPC_IRQ_VID1_FIFO_UNDERFLOW;
+	if (api->ovl[2] & DSS_IRQ_OVL_FIFO_UNDERFLOW)
+		hw |= DISPC_IRQ_VID2_FIFO_UNDERFLOW;
+	if (api->ovl[3] & DSS_IRQ_OVL_FIFO_UNDERFLOW)
+		hw |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
+
+	return hw;
+}
+
+static void dispc_api_read_irqstatus(struct dss_irq *status,
+				     const struct dss_irq *clearmask)
+{
+	u32 hw_clearmask = dispc_api_to_hw_irq(clearmask);
+	u32 hw_status = dispc_read_irqstatus();
+
+	dispc_clear_irqstatus(hw_clearmask & hw_status);
+
+	dispc_hw_to_api_irq(hw_status, status);
+}
+
+static void dispc_api_write_irqenable(const struct dss_irq *enable)
+{
+	u32 hw_enable = dispc_api_to_hw_irq(enable);
+
+	dispc_write_irqenable(hw_enable);
+}
+
 void dispc_enable_sidle(void)
 {
 	REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3);	/* SIDLEMODE: smart idle */
@@ -4426,7 +4543,7 @@ static void dispc_errata_i734_wa_fini(void)
 
 static void dispc_errata_i734_wa(void)
 {
-	u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD);
+	u32 framedone_irq = DISPC_IRQ_FRAMEDONE;
 	struct omap_overlay_info ovli;
 	struct dss_lcd_mgr_config lcd_conf;
 	u32 gatestate;
@@ -4484,9 +4601,8 @@ static void dispc_errata_i734_wa(void)
 }
 
 static const struct dispc_ops dispc_ops = {
-	.read_irqstatus = dispc_read_irqstatus,
-	.clear_irqstatus = dispc_clear_irqstatus,
-	.write_irqenable = dispc_write_irqenable,
+	.read_irqstatus = dispc_api_read_irqstatus,
+	.write_irqenable = dispc_api_write_irqenable,
 
 	.request_irq = dispc_request_irq,
 	.free_irq = dispc_free_irq,
@@ -4497,11 +4613,13 @@ static void dispc_errata_i734_wa(void)
 	.get_num_ovls = dispc_get_num_ovls,
 	.get_num_mgrs = dispc_get_num_mgrs,
 
+	.get_ovl_name = dispc_get_ovl_name,
+	.get_mgr_name = dispc_get_mgr_name,
+
+	.mgr_has_framedone = dispc_mgr_has_framedone,
+
 	.mgr_enable = dispc_mgr_enable,
 	.mgr_is_enabled = dispc_mgr_is_enabled,
-	.mgr_get_vsync_irq = dispc_mgr_get_vsync_irq,
-	.mgr_get_framedone_irq = dispc_mgr_get_framedone_irq,
-	.mgr_get_sync_lost_irq = dispc_mgr_get_sync_lost_irq,
 	.mgr_go_busy = dispc_mgr_go_busy,
 	.mgr_go = dispc_mgr_go,
 	.mgr_set_lcd_config = dispc_mgr_set_lcd_config,
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h
index 003adce..0835486 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.h
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.h
@@ -21,6 +21,39 @@
 #ifndef __OMAP2_DISPC_REG_H
 #define __OMAP2_DISPC_REG_H
 
+/* DISPC IRQ bits */
+#define DISPC_IRQ_FRAMEDONE		(1 << 0)
+#define DISPC_IRQ_VSYNC			(1 << 1)
+#define DISPC_IRQ_EVSYNC_EVEN		(1 << 2)
+#define DISPC_IRQ_EVSYNC_ODD		(1 << 3)
+#define DISPC_IRQ_ACBIAS_COUNT_STAT	(1 << 4)
+#define DISPC_IRQ_PROG_LINE_NUM		(1 << 5)
+#define DISPC_IRQ_GFX_FIFO_UNDERFLOW	(1 << 6)
+#define DISPC_IRQ_GFX_END_WIN		(1 << 7)
+#define DISPC_IRQ_PAL_GAMMA_MASK	(1 << 8)
+#define DISPC_IRQ_OCP_ERR		(1 << 9)
+#define DISPC_IRQ_VID1_FIFO_UNDERFLOW	(1 << 10)
+#define DISPC_IRQ_VID1_END_WIN		(1 << 11)
+#define DISPC_IRQ_VID2_FIFO_UNDERFLOW	(1 << 12)
+#define DISPC_IRQ_VID2_END_WIN		(1 << 13)
+#define DISPC_IRQ_SYNC_LOST		(1 << 14)
+#define DISPC_IRQ_SYNC_LOST_DIGIT	(1 << 15)
+#define DISPC_IRQ_WAKEUP		(1 << 16)
+#define DISPC_IRQ_SYNC_LOST2		(1 << 17)
+#define DISPC_IRQ_VSYNC2		(1 << 18)
+#define DISPC_IRQ_VID3_END_WIN		(1 << 19)
+#define DISPC_IRQ_VID3_FIFO_UNDERFLOW	(1 << 20)
+#define DISPC_IRQ_ACBIAS_COUNT_STAT2	(1 << 21)
+#define DISPC_IRQ_FRAMEDONE2		(1 << 22)
+#define DISPC_IRQ_FRAMEDONEWB		(1 << 23)
+#define DISPC_IRQ_FRAMEDONETV		(1 << 24)
+#define DISPC_IRQ_WBBUFFEROVERFLOW	(1 << 25)
+#define DISPC_IRQ_WBUNCOMPLETEERROR	(1 << 26)
+#define DISPC_IRQ_SYNC_LOST3		(1 << 27)
+#define DISPC_IRQ_VSYNC3		(1 << 28)
+#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 29)
+#define DISPC_IRQ_FRAMEDONE3		(1 << 30)
+
 /* DISPC common registers */
 #define DISPC_REVISION			0x0000
 #define DISPC_SYSCONFIG			0x0010
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 47a3316..dbbb71b 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -27,37 +27,29 @@
 #include <uapi/drm/drm_mode.h>
 #include <drm/drm_crtc.h>
 
-#define DISPC_IRQ_FRAMEDONE		(1 << 0)
-#define DISPC_IRQ_VSYNC			(1 << 1)
-#define DISPC_IRQ_EVSYNC_EVEN		(1 << 2)
-#define DISPC_IRQ_EVSYNC_ODD		(1 << 3)
-#define DISPC_IRQ_ACBIAS_COUNT_STAT	(1 << 4)
-#define DISPC_IRQ_PROG_LINE_NUM		(1 << 5)
-#define DISPC_IRQ_GFX_FIFO_UNDERFLOW	(1 << 6)
-#define DISPC_IRQ_GFX_END_WIN		(1 << 7)
-#define DISPC_IRQ_PAL_GAMMA_MASK	(1 << 8)
-#define DISPC_IRQ_OCP_ERR		(1 << 9)
-#define DISPC_IRQ_VID1_FIFO_UNDERFLOW	(1 << 10)
-#define DISPC_IRQ_VID1_END_WIN		(1 << 11)
-#define DISPC_IRQ_VID2_FIFO_UNDERFLOW	(1 << 12)
-#define DISPC_IRQ_VID2_END_WIN		(1 << 13)
-#define DISPC_IRQ_SYNC_LOST		(1 << 14)
-#define DISPC_IRQ_SYNC_LOST_DIGIT	(1 << 15)
-#define DISPC_IRQ_WAKEUP		(1 << 16)
-#define DISPC_IRQ_SYNC_LOST2		(1 << 17)
-#define DISPC_IRQ_VSYNC2		(1 << 18)
-#define DISPC_IRQ_VID3_END_WIN		(1 << 19)
-#define DISPC_IRQ_VID3_FIFO_UNDERFLOW	(1 << 20)
-#define DISPC_IRQ_ACBIAS_COUNT_STAT2	(1 << 21)
-#define DISPC_IRQ_FRAMEDONE2		(1 << 22)
-#define DISPC_IRQ_FRAMEDONEWB		(1 << 23)
-#define DISPC_IRQ_FRAMEDONETV		(1 << 24)
-#define DISPC_IRQ_WBBUFFEROVERFLOW	(1 << 25)
-#define DISPC_IRQ_WBUNCOMPLETEERROR	(1 << 26)
-#define DISPC_IRQ_SYNC_LOST3		(1 << 27)
-#define DISPC_IRQ_VSYNC3		(1 << 28)
-#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 29)
-#define DISPC_IRQ_FRAMEDONE3		(1 << 30)
+enum dss_irq_device {
+	DSS_IRQ_DEVICE_OCP_ERR = BIT(0),
+};
+
+enum dss_irq_channel {
+	DSS_IRQ_MGR_FRAME_DONE = BIT(0),
+	DSS_IRQ_MGR_VSYNC_EVEN = BIT(1),
+	DSS_IRQ_MGR_VSYNC_ODD = BIT(2),
+	DSS_IRQ_MGR_SYNC_LOST = BIT(3),
+};
+
+enum dss_irq_ovl {
+	DSS_IRQ_OVL_FIFO_UNDERFLOW = BIT(0),
+};
+
+#define DSS_MAX_CHANNELS 4
+#define DSS_MAX_OVLS 4
+struct dss_irq {
+	u8 device;
+	u8 channel[DSS_MAX_CHANNELS];
+	u8 ovl[DSS_MAX_OVLS];
+};
+
 
 struct omap_dss_device;
 struct dss_lcd_mgr_config;
@@ -681,9 +673,9 @@ void dss_mgr_unregister_framedone_handler(enum omap_channel channel,
 /* dispc ops */
 
 struct dispc_ops {
-	u32 (*read_irqstatus)(void);
-	void (*clear_irqstatus)(u32 mask);
-	void (*write_irqenable)(u32 mask);
+	void (*read_irqstatus)(struct dss_irq *status,
+			       const struct dss_irq *clearmask);
+	void (*write_irqenable)(const struct dss_irq *enable);
 
 	int (*request_irq)(irq_handler_t handler, void *dev_id);
 	void (*free_irq)(void *dev_id);
@@ -694,11 +686,13 @@ struct dispc_ops {
 	int (*get_num_ovls)(void);
 	int (*get_num_mgrs)(void);
 
+	const char *(*get_ovl_name)(enum omap_plane_id plane);
+	const char *(*get_mgr_name)(enum omap_channel channel);
+
+	bool (*mgr_has_framedone)(enum omap_channel channel);
+
 	void (*mgr_enable)(enum omap_channel channel, bool enable);
 	bool (*mgr_is_enabled)(enum omap_channel channel);
-	u32 (*mgr_get_vsync_irq)(enum omap_channel channel);
-	u32 (*mgr_get_framedone_irq)(enum omap_channel channel);
-	u32 (*mgr_get_sync_lost_irq)(enum omap_channel channel);
 	bool (*mgr_go_busy)(enum omap_channel channel);
 	void (*mgr_go)(enum omap_channel channel);
 	void (*mgr_set_lcd_config)(enum omap_channel channel,
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index cc85c16..a1f8ccf 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -150,7 +150,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	enum omap_channel channel = omap_crtc->channel;
 	struct omap_irq_wait *wait;
-	u32 framedone_irq, vsync_irq;
+	struct dss_irq vsync_irq, framedone_irq;
 	int ret;
 
 	if (WARN_ON(omap_crtc->enabled == enable))
@@ -170,11 +170,15 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 		omap_crtc->ignore_digit_sync_lost = true;
 	}
 
-	framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel);
-	vsync_irq = priv->dispc_ops->mgr_get_vsync_irq(channel);
+
+	memset(&vsync_irq, 0, sizeof(vsync_irq));
+	vsync_irq.channel[channel] = (DSS_IRQ_MGR_VSYNC_EVEN |
+				      DSS_IRQ_MGR_VSYNC_ODD);
+	memset(&framedone_irq, 0, sizeof(framedone_irq));
+	framedone_irq.channel[channel] = DSS_IRQ_MGR_FRAME_DONE;
 
 	if (enable) {
-		wait = omap_irq_wait_init(dev, vsync_irq, 1);
+		wait = omap_irq_wait_init(dev, &vsync_irq, 1);
 	} else {
 		/*
 		 * When we disable the digit output, we need to wait for
@@ -185,10 +189,10 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 		 * even and odd frames.
 		 */
 
-		if (framedone_irq)
-			wait = omap_irq_wait_init(dev, framedone_irq, 1);
+		if (priv->dispc_ops->mgr_has_framedone(channel))
+			wait = omap_irq_wait_init(dev, &framedone_irq, 1);
 		else
-			wait = omap_irq_wait_init(dev, vsync_irq, 2);
+			wait = omap_irq_wait_init(dev, &vsync_irq, 2);
 	}
 
 	priv->dispc_ops->mgr_enable(channel, enable);
@@ -273,17 +277,17 @@ static void omap_crtc_dss_unregister_framedone(
  * Setup, Flush and Page Flip
  */
 
-void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus)
+void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t mgr_irqstatus)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
 	if (omap_crtc->ignore_digit_sync_lost) {
-		irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
-		if (!irqstatus)
+		mgr_irqstatus &= ~DSS_IRQ_MGR_SYNC_LOST;
+		if (!mgr_irqstatus)
 			return;
 	}
 
-	DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+	DRM_ERROR_RATELIMITED("%s: errors: %02x\n", omap_crtc->name, mgr_irqstatus);
 }
 
 void omap_crtc_vblank_irq(struct drm_crtc *crtc)
@@ -627,13 +631,6 @@ static void omap_crtc_reset(struct drm_crtc *crtc)
  * Init and Cleanup
  */
 
-static const char *channel_names[] = {
-	[OMAP_DSS_CHANNEL_LCD] = "lcd",
-	[OMAP_DSS_CHANNEL_DIGIT] = "tv",
-	[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
-	[OMAP_DSS_CHANNEL_LCD3] = "lcd3",
-};
-
 void omap_crtc_pre_init(void)
 {
 	memset(omap_crtcs, 0, sizeof(omap_crtcs));
@@ -661,7 +658,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 	channel = out->dispc_channel;
 	omap_dss_put_device(out);
 
-	DBG("%s", channel_names[channel]);
+	DBG("%s", priv->dispc_ops->get_mgr_name(channel));
 
 	/* Multiple displays on same channel is not allowed */
 	if (WARN_ON(omap_crtcs[channel] != NULL))
@@ -676,7 +673,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 	init_waitqueue_head(&omap_crtc->pending_wait);
 
 	omap_crtc->channel = channel;
-	omap_crtc->name = channel_names[channel];
+	omap_crtc->name = priv->dispc_ops->get_mgr_name(channel);
 
 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
 					&omap_crtc_funcs, NULL);
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 4bd1e90..ffc84b0 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -42,7 +42,7 @@
  */
 struct omap_irq_wait;
 struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
-		uint32_t irqmask, int count);
+		struct dss_irq *irqmask, int count);
 int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
 		unsigned long timeout);
 
@@ -82,7 +82,7 @@ struct omap_drm_private {
 	/* irq handling: */
 	spinlock_t wait_lock;		/* protects the wait_list */
 	struct list_head wait_list;	/* list of omap_irq_wait */
-	uint32_t irq_mask;		/* enabled irqs in addition to wait_list */
+	struct dss_irq irq_mask;		/* enabled irqs in addition to wait_list */
 };
 
 
@@ -130,6 +130,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 		u32 possible_crtcs);
 void omap_plane_install_properties(struct drm_plane *plane,
 		struct drm_mode_object *obj);
+enum omap_plane_id omap_plane_get_id(struct drm_plane *plane);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 		struct omap_dss_device *dssdev);
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c
index 013b0bb..7dafa2c 100644
--- a/drivers/gpu/drm/omapdrm/omap_irq.c
+++ b/drivers/gpu/drm/omapdrm/omap_irq.c
@@ -22,25 +22,69 @@
 struct omap_irq_wait {
 	struct list_head node;
 	wait_queue_head_t wq;
-	uint32_t irqmask;
+	struct dss_irq irqmask;
 	int count;
 };
 
+static void dss_irq_or(struct omap_drm_private *priv,
+		       struct dss_irq *res, const struct dss_irq *arg1,
+		       const struct dss_irq *arg2)
+{
+	int i;
+
+	for (i = 0; i < priv->dispc_ops->get_num_mgrs(); i++)
+		res->channel[i] = arg1->channel[i] | arg2->channel[i];
+
+	for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++)
+		res->ovl[i] = arg1->ovl[i] | arg2->ovl[i];
+}
+
+static void dss_irq_and(struct omap_drm_private *priv,
+			struct dss_irq *res, const struct dss_irq *arg1,
+			const struct dss_irq *arg2)
+{
+	int i;
+
+	for (i = 0; i < priv->dispc_ops->get_num_mgrs(); i++)
+		res->channel[i] = arg1->channel[i] & arg2->channel[i];
+
+	for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++)
+		res->ovl[i] = arg1->ovl[i] & arg2->ovl[i];
+}
+
+static bool dss_irq_nonzero(struct omap_drm_private *priv,
+			    struct dss_irq *status)
+{
+	int i;
+
+	for (i = 0; i < priv->dispc_ops->get_num_mgrs(); i++)
+		if (status->channel[i])
+			return true;
+
+	for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++)
+		if (status->ovl[i])
+			return true;
+
+	return false;
+}
+
 /* call with wait_lock and dispc runtime held */
-static void omap_irq_update(struct drm_device *dev)
+static void omap_irq_full_mask(struct drm_device *dev, struct dss_irq *irqmask)
 {
 	struct omap_drm_private *priv = dev->dev_private;
 	struct omap_irq_wait *wait;
-	uint32_t irqmask = priv->irq_mask;
 
 	assert_spin_locked(&priv->wait_lock);
 
-	list_for_each_entry(wait, &priv->wait_list, node)
-		irqmask |= wait->irqmask;
+	*irqmask = priv->irq_mask;
 
-	DBG("irqmask=%08x", irqmask);
+	list_for_each_entry(wait, &priv->wait_list, node)
+		dss_irq_or(priv, irqmask, irqmask, &wait->irqmask);
 
-	priv->dispc_ops->write_irqenable(irqmask);
+	DBG("irqmask ch %02x %02x %02x %02x ovl %02x %02x %02x %02x",
+	    irqmask->channel[0], irqmask->channel[1],
+	    irqmask->channel[2], irqmask->channel[3],
+	    irqmask->ovl[0], irqmask->ovl[1], irqmask->ovl[2], irqmask->ovl[3]);
 }
 
 static void omap_irq_wait_handler(struct omap_irq_wait *wait)
@@ -50,19 +94,21 @@ static void omap_irq_wait_handler(struct omap_irq_wait *wait)
 }
 
 struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
-		uint32_t irqmask, int count)
+		struct dss_irq *waitmask, int count)
 {
 	struct omap_drm_private *priv = dev->dev_private;
 	struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+	struct dss_irq irqmask;
 	unsigned long flags;
 
 	init_waitqueue_head(&wait->wq);
-	wait->irqmask = irqmask;
+	wait->irqmask = *waitmask;
 	wait->count = count;
 
 	spin_lock_irqsave(&priv->wait_lock, flags);
 	list_add(&wait->node, &priv->wait_list);
-	omap_irq_update(dev);
+	omap_irq_full_mask(dev, &irqmask);
+	priv->dispc_ops->write_irqenable(&irqmask);
 	spin_unlock_irqrestore(&priv->wait_lock, flags);
 
 	return wait;
@@ -72,6 +118,7 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
 		unsigned long timeout)
 {
 	struct omap_drm_private *priv = dev->dev_private;
+	struct dss_irq irqmask;
 	unsigned long flags;
 	int ret;
 
@@ -79,7 +126,8 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
 
 	spin_lock_irqsave(&priv->wait_lock, flags);
 	list_del(&wait->node);
-	omap_irq_update(dev);
+	omap_irq_full_mask(dev, &irqmask);
+	priv->dispc_ops->write_irqenable(&irqmask);
 	spin_unlock_irqrestore(&priv->wait_lock, flags);
 
 	kfree(wait);
@@ -106,12 +154,15 @@ int omap_irq_enable_vblank(struct drm_crtc *crtc)
 	struct omap_drm_private *priv = dev->dev_private;
 	unsigned long flags;
 	enum omap_channel channel = omap_crtc_channel(crtc);
+	struct dss_irq irqmask;
 
 	DBG("dev=%p, crtc=%u", dev, channel);
 
 	spin_lock_irqsave(&priv->wait_lock, flags);
-	priv->irq_mask |= priv->dispc_ops->mgr_get_vsync_irq(channel);
-	omap_irq_update(dev);
+	priv->irq_mask.channel[channel] |=
+		DSS_IRQ_MGR_VSYNC_EVEN | DSS_IRQ_MGR_VSYNC_ODD;
+	omap_irq_full_mask(dev, &irqmask);
+	priv->dispc_ops->write_irqenable(&irqmask);
 	spin_unlock_irqrestore(&priv->wait_lock, flags);
 
 	return 0;
@@ -132,41 +183,35 @@ void omap_irq_disable_vblank(struct drm_crtc *crtc)
 	struct omap_drm_private *priv = dev->dev_private;
 	unsigned long flags;
 	enum omap_channel channel = omap_crtc_channel(crtc);
+	struct dss_irq irqmask;
 
 	DBG("dev=%p, crtc=%u", dev, channel);
 
 	spin_lock_irqsave(&priv->wait_lock, flags);
-	priv->irq_mask &= ~priv->dispc_ops->mgr_get_vsync_irq(channel);
-	omap_irq_update(dev);
+	priv->irq_mask.channel[channel] &=
+		~(DSS_IRQ_MGR_VSYNC_EVEN | DSS_IRQ_MGR_VSYNC_ODD);
+	omap_irq_full_mask(dev, &irqmask);
+	priv->dispc_ops->write_irqenable(&irqmask);
 	spin_unlock_irqrestore(&priv->wait_lock, flags);
 }
 
 static void omap_irq_fifo_underflow(struct omap_drm_private *priv,
-				    u32 irqstatus)
+				    struct dss_irq *irqstatus)
 {
 	static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
 				      DEFAULT_RATELIMIT_BURST);
-	static const struct {
-		const char *name;
-		u32 mask;
-	} sources[] = {
-		{ "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW },
-		{ "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW },
-		{ "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW },
-		{ "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW },
-	};
-
-	const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW
-		       | DISPC_IRQ_VID1_FIFO_UNDERFLOW
-		       | DISPC_IRQ_VID2_FIFO_UNDERFLOW
-		       | DISPC_IRQ_VID3_FIFO_UNDERFLOW;
+	bool ovl_undeflow[DSS_MAX_OVLS] = { false };
+	bool underflow = false;
 	unsigned int i;
 
 	spin_lock(&priv->wait_lock);
-	irqstatus &= priv->irq_mask & mask;
+	for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++)
+		if (irqstatus->ovl[i] & priv->irq_mask.ovl[i] &
+		    DSS_IRQ_OVL_FIFO_UNDERFLOW)
+			underflow = ovl_undeflow[i] = true;
 	spin_unlock(&priv->wait_lock);
 
-	if (!irqstatus)
+	if (!underflow)
 		return;
 
 	if (!__ratelimit(&_rs))
@@ -174,18 +219,18 @@ static void omap_irq_fifo_underflow(struct omap_drm_private *priv,
 
 	DRM_ERROR("FIFO underflow on ");
 
-	for (i = 0; i < ARRAY_SIZE(sources); ++i) {
-		if (sources[i].mask & irqstatus)
-			pr_cont("%s ", sources[i].name);
+	for (i = 0; i < DSS_MAX_OVLS; ++i) {
+		if (ovl_undeflow[i])
+			pr_cont("%u:%s ", i, priv->dispc_ops->get_ovl_name(i));
 	}
 
-	pr_cont("(0x%08x)\n", irqstatus);
+	pr_cont("\n");
 }
 
 static void omap_irq_ocp_error_handler(struct drm_device *dev,
-	u32 irqstatus)
+				       struct dss_irq *irqstatus)
 {
-	if (!(irqstatus & DISPC_IRQ_OCP_ERR))
+	if (!(irqstatus->device & DSS_IRQ_DEVICE_OCP_ERR))
 		return;
 
 	dev_err_ratelimited(dev->dev, "OCP error\n");
@@ -198,47 +243,48 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
 	struct omap_irq_wait *wait, *n;
 	unsigned long flags;
 	unsigned int id;
-	u32 irqstatus;
+	struct dss_irq irqstatus, clearmask;
 
-	irqstatus = priv->dispc_ops->read_irqstatus();
-	priv->dispc_ops->clear_irqstatus(irqstatus);
-	priv->dispc_ops->read_irqstatus();        /* flush posted write */
+	spin_lock_irqsave(&priv->wait_lock, flags);
+	omap_irq_full_mask(dev, &clearmask);
+	priv->dispc_ops->read_irqstatus(&irqstatus, &clearmask);
+
+	list_for_each_entry_safe(wait, n, &priv->wait_list, node) {
+		struct dss_irq waitstatus;
+
+		dss_irq_and(priv, &waitstatus, &irqstatus, &wait->irqmask);
+		if (dss_irq_nonzero(priv, &waitstatus))
+			omap_irq_wait_handler(wait);
+	}
+	spin_unlock_irqrestore(&priv->wait_lock, flags);
+
+	VERB("irqs: ch 0x%02x 0x%02x 0x%02x 0x%02x ovl 0x%02x 0x%02x 0x%02x 0x%02x\n",
+	       irqstatus.channel[0], irqstatus.channel[1],
+	       irqstatus.channel[2], irqstatus.channel[3],
+	       irqstatus.ovl[0], irqstatus.ovl[1],
+	       irqstatus.ovl[2], irqstatus.ovl[3]);
 
-	VERB("irqs: %08x", irqstatus);
 
 	for (id = 0; id < priv->num_crtcs; id++) {
 		struct drm_crtc *crtc = priv->crtcs[id];
 		enum omap_channel channel = omap_crtc_channel(crtc);
 
-		if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(channel)) {
+		if (irqstatus.channel[channel] & 
+		    (DSS_IRQ_MGR_VSYNC_EVEN | DSS_IRQ_MGR_VSYNC_ODD)) {
 			drm_handle_vblank(dev, id);
 			omap_crtc_vblank_irq(crtc);
 		}
 
-		if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel))
-			omap_crtc_error_irq(crtc, irqstatus);
+		if (irqstatus.channel[channel] & DSS_IRQ_MGR_SYNC_LOST)
+			omap_crtc_error_irq(crtc, irqstatus.channel[channel]);
 	}
 
-	omap_irq_ocp_error_handler(dev, irqstatus);
-	omap_irq_fifo_underflow(priv, irqstatus);
-
-	spin_lock_irqsave(&priv->wait_lock, flags);
-	list_for_each_entry_safe(wait, n, &priv->wait_list, node) {
-		if (wait->irqmask & irqstatus)
-			omap_irq_wait_handler(wait);
-	}
-	spin_unlock_irqrestore(&priv->wait_lock, flags);
+	omap_irq_ocp_error_handler(dev, &irqstatus);
+	omap_irq_fifo_underflow(priv, &irqstatus);
 
 	return IRQ_HANDLED;
 }
 
-static const u32 omap_underflow_irqs[] = {
-	[OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
-	[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
-	[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
-	[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
-};
-
 /*
  * We need a special version, instead of just using drm_irq_install(),
  * because we need to register the irq via omapdss.  Once omapdss and
@@ -249,29 +295,21 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
 int omap_drm_irq_install(struct drm_device *dev)
 {
 	struct omap_drm_private *priv = dev->dev_private;
-	unsigned int num_mgrs = priv->dispc_ops->get_num_mgrs();
-	unsigned int max_planes;
 	unsigned int i;
 	int ret;
 
 	spin_lock_init(&priv->wait_lock);
 	INIT_LIST_HEAD(&priv->wait_list);
 
-	priv->irq_mask = DISPC_IRQ_OCP_ERR;
-
-	max_planes = min(ARRAY_SIZE(priv->planes),
-			 ARRAY_SIZE(omap_underflow_irqs));
-	for (i = 0; i < max_planes; ++i) {
-		if (priv->planes[i])
-			priv->irq_mask |= omap_underflow_irqs[i];
-	}
+	priv->irq_mask.device = DSS_IRQ_DEVICE_OCP_ERR;
 
-	for (i = 0; i < num_mgrs; ++i)
-		priv->irq_mask |= priv->dispc_ops->mgr_get_sync_lost_irq(i);
+	for (i = 0; i < priv->num_planes; ++i)
+		priv->irq_mask.ovl[omap_plane_get_id(priv->planes[i])] |=
+			DSS_IRQ_OVL_FIFO_UNDERFLOW;
 
-	priv->dispc_ops->runtime_get();
-	priv->dispc_ops->clear_irqstatus(0xffffffff);
-	priv->dispc_ops->runtime_put();
+	for (i = 0; i < priv->num_crtcs; ++i)
+		priv->irq_mask.channel[omap_crtc_channel(priv->crtcs[i])] |=
+			DSS_IRQ_MGR_SYNC_LOST;
 
 	ret = priv->dispc_ops->request_irq(omap_irq_handler, dev);
 	if (ret < 0)
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 15e5d5d..ae13b70 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -241,12 +241,12 @@ static int omap_plane_atomic_get_property(struct drm_plane *plane,
 	.atomic_get_property = omap_plane_atomic_get_property,
 };
 
-static const char *plane_id_to_name[] = {
-	[OMAP_DSS_GFX] = "gfx",
-	[OMAP_DSS_VIDEO1] = "vid1",
-	[OMAP_DSS_VIDEO2] = "vid2",
-	[OMAP_DSS_VIDEO3] = "vid3",
-};
+enum omap_plane_id omap_plane_get_id(struct drm_plane *plane)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+
+	return omap_plane->id;
+}
 
 static const enum omap_plane_id plane_idx_to_id[] = {
 	OMAP_DSS_GFX,
@@ -274,7 +274,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 	id = plane_idx_to_id[idx];
 
-	DBG("%s: type=%d", plane_id_to_name[id], type);
+	DBG("%s: type=%d", priv->dispc_ops->get_ovl_name(id), type);
 
 	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
 	if (!omap_plane)
@@ -284,7 +284,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	for (nformats = 0; formats[nformats]; ++nformats)
 		;
 	omap_plane->id = id;
-	omap_plane->name = plane_id_to_name[id];
+	omap_plane->name = priv->dispc_ops->get_ovl_name(id);
 
 	plane = &omap_plane->base;
 
@@ -303,7 +303,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 error:
 	dev_err(dev->dev, "%s(): could not create plane: %s\n",
-		__func__, plane_id_to_name[id]);
+		__func__, priv->dispc_ops->get_ovl_name(id));
 
 	kfree(omap_plane);
 	return NULL;
