diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
index b466784d9822..6c2569175633 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
@@ -106,13 +106,10 @@ static const struct irq_domain_ops dpu_mdss_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onecell,
 };
 
-static int _dpu_mdss_irq_domain_add(struct dpu_mdss *dpu_mdss)
+static int _dpu_mdss_irq_domain_add(struct device *dev, struct dpu_mdss *dpu_mdss)
 {
-	struct device *dev;
 	struct irq_domain *domain;
 
-	dev = dpu_mdss->base.dev->dev;
-
 	domain = irq_domain_add_linear(dev->of_node, 32,
 			&dpu_mdss_irqdomain_ops, dpu_mdss);
 	if (!domain) {
@@ -194,7 +191,6 @@ static void dpu_mdss_destroy(struct drm_device *dev)
 
 	pm_runtime_suspend(dev->dev);
 	pm_runtime_disable(dev->dev);
-	_dpu_mdss_irq_domain_fini(dpu_mdss);
 	irq = platform_get_irq(pdev, 0);
 	irq_set_chained_handler_and_data(irq, NULL, NULL);
 	msm_dss_put_clk(mp->clk_config, mp->num_clk);
@@ -203,15 +199,43 @@ static void dpu_mdss_destroy(struct drm_device *dev)
 	if (dpu_mdss->mmio)
 		devm_iounmap(&pdev->dev, dpu_mdss->mmio);
 	dpu_mdss->mmio = NULL;
-	priv->mdss = NULL;
+}
+
+static void dpu_mdss_remove(struct msm_mdss *mdss)
+{
+	_dpu_mdss_irq_domain_fini(to_dpu_mdss(mdss));
 }
 
 static const struct msm_mdss_funcs mdss_funcs = {
 	.enable	= dpu_mdss_enable,
 	.disable = dpu_mdss_disable,
 	.destroy = dpu_mdss_destroy,
+	.remove = dpu_mdss_remove,
 };
 
+int dpu_mdss_early_init(struct device *dev, struct msm_drm_private *priv)
+{
+	struct dpu_mdss *dpu_mdss;
+	int ret;
+
+	dpu_mdss = devm_kzalloc(dev, sizeof(*dpu_mdss), GFP_KERNEL);
+	if (!dpu_mdss)
+		return -ENOMEM;
+
+	ret = _dpu_mdss_irq_domain_add(dev, dpu_mdss);
+	if (ret)
+		return ret;
+
+	/*
+	 * Here we have no drm_device yet, but still do the assignment
+	 * so that we can retrieve our struct dpu_mdss from the main
+	 * init function, since we allocate it here.
+	 */
+	priv->mdss = &dpu_mdss->base;
+
+	return 0;
+}
+
 int dpu_mdss_init(struct drm_device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev->dev);
@@ -221,9 +245,9 @@ int dpu_mdss_init(struct drm_device *dev)
 	int ret;
 	int irq;
 
-	dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL);
+	dpu_mdss = to_dpu_mdss(priv->mdss);
 	if (!dpu_mdss)
-		return -ENOMEM;
+		return -ENODATA;
 
 	dpu_mdss->mmio = msm_ioremap(pdev, "mdss", "mdss");
 	if (IS_ERR(dpu_mdss->mmio))
@@ -241,10 +265,6 @@ int dpu_mdss_init(struct drm_device *dev)
 	dpu_mdss->base.dev = dev;
 	dpu_mdss->base.funcs = &mdss_funcs;
 
-	ret = _dpu_mdss_irq_domain_add(dpu_mdss);
-	if (ret)
-		goto irq_domain_error;
-
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		ret = irq;
@@ -253,16 +273,10 @@ int dpu_mdss_init(struct drm_device *dev)
 
 	irq_set_chained_handler_and_data(irq, dpu_mdss_irq,
 					 dpu_mdss);
-
-	priv->mdss = &dpu_mdss->base;
-
 	pm_runtime_enable(dev->dev);
-
 	return 0;
 
 irq_error:
-	_dpu_mdss_irq_domain_fini(dpu_mdss);
-irq_domain_error:
 	msm_dss_put_clk(mp->clk_config, mp->num_clk);
 clk_parse_err:
 	devm_kfree(&pdev->dev, mp->clk_config);
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
index 0ea53420bc40..a99538ae4182 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
@@ -112,9 +112,8 @@ static const struct irq_domain_ops mdss_hw_irqdomain_ops = {
 };
 
 
-static int mdss_irq_domain_init(struct mdp5_mdss *mdp5_mdss)
+static int mdss_irq_domain_init(struct device *dev, struct mdp5_mdss *mdp5_mdss)
 {
-	struct device *dev = mdp5_mdss->base.dev->dev;
 	struct irq_domain *d;
 
 	d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops,
@@ -182,20 +181,52 @@ static void mdp5_mdss_destroy(struct drm_device *dev)
 	if (!mdp5_mdss)
 		return;
 
-	irq_domain_remove(mdp5_mdss->irqcontroller.domain);
-	mdp5_mdss->irqcontroller.domain = NULL;
-
 	regulator_disable(mdp5_mdss->vdd);
 
 	pm_runtime_disable(dev->dev);
 }
 
+static void mdp5_mdss_remove(struct msm_mdss *mdss)
+{
+	struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(mdss);
+
+	irq_domain_remove(mdp5_mdss->irqcontroller.domain);
+	mdp5_mdss->irqcontroller.domain = NULL;
+}
+
 static const struct msm_mdss_funcs mdss_funcs = {
 	.enable	= mdp5_mdss_enable,
 	.disable = mdp5_mdss_disable,
 	.destroy = mdp5_mdss_destroy,
+	.remove = mdp5_mdss_remove,
 };
 
+int mdp5_mdss_early_init(struct device *dev, struct msm_drm_private *priv)
+{
+	struct mdp5_mdss *mdp5_mdss;
+	int ret;
+
+	if (!of_device_is_compatible(dev->of_node, "qcom,mdss"))
+		return 0;
+
+	mdp5_mdss = devm_kzalloc(dev, sizeof(*mdp5_mdss), GFP_KERNEL);
+	if (!mdp5_mdss)
+		return -ENOMEM;
+
+	ret = mdss_irq_domain_init(dev, mdp5_mdss);
+	if (ret)
+		return ret;
+
+	/*
+	 * Here we have no drm_device yet, but still do the assignment
+	 * so that we can retrieve our struct mdp5_mdss from the main
+	 * init function, since we allocate it here.
+	 */
+	priv->mdss = &mdp5_mdss->base;
+
+	return 0;
+}
+
 int mdp5_mdss_init(struct drm_device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev->dev);
@@ -208,11 +239,9 @@ int mdp5_mdss_init(struct drm_device *dev)
 	if (!of_device_is_compatible(dev->dev->of_node, "qcom,mdss"))
 		return 0;
 
-	mdp5_mdss = devm_kzalloc(dev->dev, sizeof(*mdp5_mdss), GFP_KERNEL);
-	if (!mdp5_mdss) {
-		ret = -ENOMEM;
-		goto fail;
-	}
+	mdp5_mdss = to_mdp5_mdss(priv->mdss);
+	if (!mdp5_mdss)
+		return -ENODATA;
 
 	mdp5_mdss->base.dev = dev;
 
@@ -255,17 +284,8 @@ int mdp5_mdss_init(struct drm_device *dev)
 		goto fail_irq;
 	}
 
-	ret = mdss_irq_domain_init(mdp5_mdss);
-	if (ret) {
-		DRM_DEV_ERROR(dev->dev, "failed to init sub-block irqs: %d\n", ret);
-		goto fail_irq;
-	}
-
 	mdp5_mdss->base.funcs = &mdss_funcs;
-	priv->mdss = &mdp5_mdss->base;
-
 	pm_runtime_enable(dev->dev);
-
 	return 0;
 fail_irq:
 	regulator_disable(mdp5_mdss->vdd);
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 601814b12daf..e61fc806148b 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -1390,6 +1390,20 @@ static int msm_pdev_probe(struct platform_device *pdev)
 	if (!priv)
 		return -ENOMEM;
 
+	switch (get_mdp_ver(pdev)) {
+	case KMS_MDP5:
+		ret = mdp5_mdss_early_init(&pdev->dev, priv);
+		break;
+	case KMS_DPU:
+		ret = dpu_mdss_early_init(&pdev->dev, priv);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, priv);
 
 	if (get_mdp_ver(pdev)) {
@@ -1422,6 +1436,12 @@ static int msm_pdev_probe(struct platform_device *pdev)
 
 static int msm_pdev_remove(struct platform_device *pdev)
 {
+	struct msm_drm_private *priv = platform_get_drvdata(pdev);
+
+	if (priv->mdss && priv->mdss->funcs)
+		priv->mdss->funcs->remove(priv->mdss);
+
+	priv->mdss = NULL;
 	component_master_del(&pdev->dev, &msm_drm_ops);
 	of_platform_depopulate(&pdev->dev);
 
@@ -1433,7 +1453,7 @@ static void msm_pdev_shutdown(struct platform_device *pdev)
 	struct msm_drm_private *priv = platform_get_drvdata(pdev);
 	struct drm_device *drm = priv ? priv->dev : NULL;
 
-	if (!priv || !priv->kms)
+	if (!priv || !priv->kms || !drm->mode_config.funcs)
 		return;
 
 	drm_atomic_helper_shutdown(drm);
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 6a42b819abc4..2c539a228156 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -202,6 +202,7 @@ struct msm_mdss_funcs {
 	int (*enable)(struct msm_mdss *mdss);
 	int (*disable)(struct msm_mdss *mdss);
 	void (*destroy)(struct drm_device *dev);
+	void (*remove)(struct msm_mdss *mdss);
 };
 
 struct msm_mdss {
@@ -209,7 +210,9 @@ struct msm_mdss {
 	const struct msm_mdss_funcs *funcs;
 };
 
+int mdp5_mdss_early_init(struct device *dev, struct msm_drm_private *priv);
 int mdp5_mdss_init(struct drm_device *dev);
+int dpu_mdss_early_init(struct device *dev, struct msm_drm_private *priv);
 int dpu_mdss_init(struct drm_device *dev);
 
 #define for_each_crtc_mask(dev, crtc, crtc_mask) \
