diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 1969f0d07d865..3796a2978a40b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -497,6 +497,7 @@ static void _dpu_kms_setup_displays(struct drm_device *dev,
 static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms)
 {
 	struct msm_drm_private *priv;
+	struct drm_crtc *crtc;
 	int i;
 
 	if (!dpu_kms) {
@@ -511,9 +512,8 @@ static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms)
 	}
 	priv = dpu_kms->dev->dev_private;
 
-	for (i = 0; i < priv->num_crtcs; i++)
-		priv->crtcs[i]->funcs->destroy(priv->crtcs[i]);
-	priv->num_crtcs = 0;
+	drm_for_each_crtc(crtc, dpu_kms->dev)
+		crtc->funcs->destroy(crtc);
 
 	for (i = 0; i < priv->num_planes; i++)
 		priv->planes[i]->funcs->destroy(priv->planes[i]);
@@ -598,12 +598,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
 			ret = PTR_ERR(crtc);
 			goto fail;
 		}
-		priv->crtcs[priv->num_crtcs++] = crtc;
 	}
 
 	/* All CRTCs are compatible with all encoders */
 	for (i = 0; i < priv->num_encoders; i++)
-		priv->encoders[i]->possible_crtcs = (1 << priv->num_crtcs) - 1;
+		priv->encoders[i]->possible_crtcs = (1 << max_crtc_count) - 1;
 
 	return 0;
 fail:
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
index b764d7f103127..7c597d21c97ba 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
@@ -15,6 +15,7 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <drm/drm_crtc.h>
 #include <drm/drm_print.h>
 
 #include "msm_drv.h"
@@ -79,8 +80,7 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
 	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
 	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
 	struct drm_device *dev = mdp4_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	unsigned int id;
+	struct drm_crtc *crtc;
 	uint32_t status, enable;
 
 	enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE);
@@ -91,9 +91,9 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
 
 	mdp_dispatch_irqs(mdp_kms, status);
 
-	for (id = 0; id < priv->num_crtcs; id++)
-		if (status & mdp4_crtc_vblank(priv->crtcs[id]))
-			drm_handle_vblank(dev, id);
+	drm_for_each_crtc(crtc, dev)
+		if (status & mdp4_crtc_vblank(crtc))
+			drm_handle_vblank(dev, drm_crtc_index(crtc));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index e437aa806f7be..f7f678c55e3ac 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -373,7 +373,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
 			goto fail;
 		}
 
-		crtc  = mdp4_crtc_init(dev, plane, priv->num_crtcs, i,
+		crtc  = mdp4_crtc_init(dev, plane, ARRAY_SIZE(mdp4_crtcs), i,
 				mdp4_crtcs[i]);
 		if (IS_ERR(crtc)) {
 			DRM_DEV_ERROR(dev->dev, "failed to construct crtc for %s\n",
@@ -381,8 +381,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
 			ret = PTR_ERR(crtc);
 			goto fail;
 		}
-
-		priv->crtcs[priv->num_crtcs++] = crtc;
 	}
 
 	/*
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
index 280e368bc9bb8..c66a7fbd9b9c3 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
@@ -17,6 +17,7 @@
 
 #include <linux/irq.h>
 
+#include <drm/drm_crtc.h>
 #include <drm/drm_print.h>
 
 #include "msm_drv.h"
@@ -92,8 +93,7 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
 	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
 	struct drm_device *dev = mdp5_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	unsigned int id;
+	struct drm_crtc *crtc;
 	uint32_t status, enable;
 
 	enable = mdp5_read(mdp5_kms, REG_MDP5_INTR_EN);
@@ -104,9 +104,9 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
 
 	mdp_dispatch_irqs(mdp_kms, status);
 
-	for (id = 0; id < priv->num_crtcs; id++)
-		if (status & mdp5_crtc_vblank(priv->crtcs[id]))
-			drm_handle_vblank(dev, id);
+	drm_for_each_crtc(crtc, dev)
+		if (status & mdp5_crtc_vblank(crtc))
+			drm_handle_vblank(dev, drm_crtc_index(crtc));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index d27e35a217bd7..4fb70532b0484 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -520,7 +520,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
 			DRM_DEV_ERROR(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
 			goto fail;
 		}
-		priv->crtcs[priv->num_crtcs++] = crtc;
 	}
 
 	/*
@@ -530,7 +529,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
 	for (i = 0; i < priv->num_encoders; i++) {
 		struct drm_encoder *encoder = priv->encoders[i];
 
-		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
+		encoder->possible_crtcs = (1 << num_crtcs) - 1;
 	}
 
 	return 0;
@@ -589,12 +588,11 @@ static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
 				ktime_t *stime, ktime_t *etime,
 				const struct drm_display_mode *mode)
 {
-	struct msm_drm_private *priv = dev->dev_private;
 	struct drm_crtc *crtc;
 	struct drm_encoder *encoder;
 	int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
 
-	crtc = priv->crtcs[pipe];
+	crtc = drm_crtc_from_index(dev, pipe);
 	if (!crtc) {
 		DRM_ERROR("Invalid crtc %d\n", pipe);
 		return false;
@@ -646,14 +644,10 @@ static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
 
 static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
-	struct msm_drm_private *priv = dev->dev_private;
 	struct drm_crtc *crtc;
 	struct drm_encoder *encoder;
 
-	if (pipe >= priv->num_crtcs)
-		return 0;
-
-	crtc = priv->crtcs[pipe];
+	crtc = drm_crtc_from_index(dev, pipe);
 	if (!crtc)
 		return 0;
 
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 81bfac744a555..dcc671eba24dc 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -224,15 +224,19 @@ static void vblank_ctrl_worker(struct kthread_work *work)
 
 	spin_lock_irqsave(&vbl_ctrl->lock, flags);
 	list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
+		struct drm_crtc *crtc = drm_crtc_from_index(priv->dev,
+							    vbl_ev->crtc_id);
+
+		if (WARN_ON(!crtc))
+			continue;
+
 		list_del(&vbl_ev->node);
 		spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
 
 		if (vbl_ev->enable)
-			kms->funcs->enable_vblank(kms,
-						priv->crtcs[vbl_ev->crtc_id]);
+			kms->funcs->enable_vblank(kms, crtc);
 		else
-			kms->funcs->disable_vblank(kms,
-						priv->crtcs[vbl_ev->crtc_id]);
+			kms->funcs->disable_vblank(kms, crtc);
 
 		kfree(vbl_ev);
 
@@ -270,12 +274,12 @@ static int msm_drm_uninit(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *ddev = platform_get_drvdata(pdev);
+	struct drm_crtc *crtc;
 	struct msm_drm_private *priv = ddev->dev_private;
 	struct msm_kms *kms = priv->kms;
 	struct msm_mdss *mdss = priv->mdss;
 	struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
 	struct vblank_event *vbl_ev, *tmp;
-	int i;
 
 	/* We must cancel and cleanup any pending vblank enable/disable
 	 * work before drm_irq_uninstall() to avoid work re-enabling an
@@ -288,17 +292,18 @@ static int msm_drm_uninit(struct device *dev)
 	}
 
 	/* clean up display commit/event worker threads */
-	for (i = 0; i < priv->num_crtcs; i++) {
-		if (priv->disp_thread[i].thread) {
-			kthread_flush_worker(&priv->disp_thread[i].worker);
-			kthread_stop(priv->disp_thread[i].thread);
-			priv->disp_thread[i].thread = NULL;
+	drm_for_each_crtc(crtc, ddev) {
+		unsigned int pipe = drm_crtc_index(crtc);
+		if (priv->disp_thread[pipe].thread) {
+			kthread_flush_worker(&priv->disp_thread[pipe].worker);
+			kthread_stop(priv->disp_thread[pipe].thread);
+			priv->disp_thread[pipe].thread = NULL;
 		}
 
-		if (priv->event_thread[i].thread) {
-			kthread_flush_worker(&priv->event_thread[i].worker);
-			kthread_stop(priv->event_thread[i].thread);
-			priv->event_thread[i].thread = NULL;
+		if (priv->event_thread[pipe].thread) {
+			kthread_flush_worker(&priv->event_thread[pipe].worker);
+			kthread_stop(priv->event_thread[pipe].thread);
+			priv->event_thread[pipe].thread = NULL;
 		}
 	}
 
@@ -438,10 +443,11 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *ddev;
+	struct drm_crtc *crtc;
 	struct msm_drm_private *priv;
 	struct msm_kms *kms;
 	struct msm_mdss *mdss;
-	int ret, i;
+	int ret;
 	struct sched_param param;
 
 	ddev = drm_dev_alloc(drv, dev);
@@ -547,39 +553,42 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 	 * other real time and normal priority task
 	 */
 	param.sched_priority = 16;
-	for (i = 0; i < priv->num_crtcs; i++) {
+	drm_for_each_crtc(crtc, ddev) {
+		unsigned int pipe = drm_crtc_index(crtc);
 
 		/* initialize display thread */
-		priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id;
-		kthread_init_worker(&priv->disp_thread[i].worker);
-		priv->disp_thread[i].dev = ddev;
-		priv->disp_thread[i].thread =
+		priv->disp_thread[pipe].crtc_id = crtc->base.id;
+		kthread_init_worker(&priv->disp_thread[pipe].worker);
+		priv->disp_thread[pipe].dev = ddev;
+		priv->disp_thread[pipe].thread =
 			kthread_run(kthread_worker_fn,
-				&priv->disp_thread[i].worker,
-				"crtc_commit:%d", priv->disp_thread[i].crtc_id);
-		if (IS_ERR(priv->disp_thread[i].thread)) {
+				&priv->disp_thread[pipe].worker,
+				"crtc_commit:%d",
+				priv->disp_thread[pipe].crtc_id);
+		if (IS_ERR(priv->disp_thread[pipe].thread)) {
 			DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n");
-			priv->disp_thread[i].thread = NULL;
+			priv->disp_thread[pipe].thread = NULL;
 			goto err_msm_uninit;
 		}
 
-		ret = sched_setscheduler(priv->disp_thread[i].thread,
+		ret = sched_setscheduler(priv->disp_thread[pipe].thread,
 					 SCHED_FIFO, &param);
 		if (ret)
 			dev_warn(dev, "disp_thread set priority failed: %d\n",
 				 ret);
 
 		/* initialize event thread */
-		priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id;
-		kthread_init_worker(&priv->event_thread[i].worker);
-		priv->event_thread[i].dev = ddev;
-		priv->event_thread[i].thread =
+		priv->event_thread[pipe].crtc_id = crtc->base.id;
+		kthread_init_worker(&priv->event_thread[pipe].worker);
+		priv->event_thread[pipe].dev = ddev;
+		priv->event_thread[pipe].thread =
 			kthread_run(kthread_worker_fn,
-				&priv->event_thread[i].worker,
-				"crtc_event:%d", priv->event_thread[i].crtc_id);
-		if (IS_ERR(priv->event_thread[i].thread)) {
+				&priv->event_thread[pipe].worker,
+				"crtc_event:%d",
+				priv->event_thread[pipe].crtc_id);
+		if (IS_ERR(priv->event_thread[pipe].thread)) {
 			DRM_DEV_ERROR(dev, "failed to create crtc_event kthread\n");
-			priv->event_thread[i].thread = NULL;
+			priv->event_thread[pipe].thread = NULL;
 			goto err_msm_uninit;
 		}
 
@@ -590,14 +599,14 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 		 * frame_pending counters beyond 2. This can lead to commit
 		 * failure at crtc commit level.
 		 */
-		ret = sched_setscheduler(priv->event_thread[i].thread,
+		ret = sched_setscheduler(priv->event_thread[pipe].thread,
 					 SCHED_FIFO, &param);
 		if (ret)
 			dev_warn(dev, "event_thread set priority failed:%d\n",
 				 ret);
 	}
 
-	ret = drm_vblank_init(ddev, priv->num_crtcs);
+	ret = drm_vblank_init(ddev, ddev->mode_config.num_crtc);
 	if (ret < 0) {
 		DRM_DEV_ERROR(dev, "failed to initialize vblank\n");
 		goto err_msm_uninit;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 71a03ce21da53..fc677da06e33b 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -194,9 +194,6 @@ struct msm_drm_private {
 	unsigned int num_planes;
 	struct drm_plane *planes[MAX_PLANES];
 
-	unsigned int num_crtcs;
-	struct drm_crtc *crtcs[MAX_CRTCS];
-
 	struct msm_drm_thread disp_thread[MAX_CRTCS];
 	struct msm_drm_thread event_thread[MAX_CRTCS];
 
