drm/msm/sde: fix msm drm driver probe sequence

Fix msm drm driver probe and binding based
on downstream implementation to support the
connector property. The patch also fixes the
smmu driver optional binding to switch physical
domain dynamically.

Change-Id: Ie857f215054fab3f2b91282173ee968d093ccadb
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 9fa1a20..50d34d16 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -17,6 +17,7 @@
  */
 
 #include <linux/of_address.h>
+#include <linux/kthread.h>
 #include "msm_drv.h"
 #include "msm_debugfs.h"
 #include "msm_fence.h"
@@ -222,8 +223,9 @@
 
 static int msm_drm_uninit(struct device *dev)
 {
-	struct msm_drm_private *priv = dev->dev_private;
-	struct platform_device *pdev = dev->platformdev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *ddev = platform_get_drvdata(pdev);
+	struct msm_drm_private *priv = ddev->dev_private;
 	struct msm_kms *kms = priv->kms;
 	struct msm_gpu *gpu = priv->gpu;
 	struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
@@ -243,6 +245,9 @@
 
 	drm_kms_helper_poll_fini(ddev);
 
+	drm_mode_config_cleanup(ddev);
+	drm_vblank_cleanup(ddev);
+
 	drm_dev_unregister(ddev);
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
@@ -284,21 +289,25 @@
 	sde_power_client_destroy(&priv->phandle, priv->pclient);
 	sde_power_resource_deinit(pdev, &priv->phandle);
 
-	component_unbind_all(dev->dev, dev);
+	component_unbind_all(dev, ddev);
+
+	sde_power_client_destroy(&priv->phandle, priv->pclient);
+
+	sde_power_resource_deinit(pdev, &priv->phandle);
 
 	msm_mdss_destroy(ddev);
 
 	ddev->dev_private = NULL;
-	drm_dev_unref(ddev);
-
 	kfree(priv);
 
+	drm_dev_unref(ddev);
+
 	return 0;
 }
 
-#define KMS_MDP4 0
-#define KMS_MDP5 1
-#define KMS_SDE  2
+#define KMS_MDP4 4
+#define KMS_MDP5 5
+#define KMS_SDE  3
 
 static int get_mdp_ver(struct platform_device *pdev)
 {
@@ -425,33 +434,43 @@
 	struct msm_kms *kms;
 	int ret;
 
+	ddev = drm_dev_alloc(drv, dev);
+	if (!ddev) {
+		dev_err(dev, "failed to allocate drm_device\n");
+		return -ENOMEM;
+	}
+
+	drm_mode_config_init(ddev);
+	platform_set_drvdata(pdev, ddev);
+	ddev->platformdev = pdev;
+
+	ret = drm_dev_register(ddev, 0);
+	if (ret)
+		goto fail;
+
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
-		drm_dev_unref(ddev);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto priv_alloc_fail;
 	}
 
 	ddev->dev_private = priv;
 	priv->dev = ddev;
 
+	ret = msm_mdss_init(ddev);
+	if (ret)
+		goto mdss_init_fail;
+
 	priv->wq = alloc_ordered_workqueue("msm_drm", 0);
-	init_waitqueue_head(&priv->fence_event);
+	priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0);
 	init_waitqueue_head(&priv->pending_crtcs_event);
 
 	INIT_LIST_HEAD(&priv->client_event_list);
 	INIT_LIST_HEAD(&priv->inactive_list);
-	INIT_LIST_HEAD(&priv->fence_cbs);
 	INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
-	init_kthread_work(&priv->vblank_ctrl.work, vblank_ctrl_worker);
+	INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker);
 	spin_lock_init(&priv->vblank_ctrl.lock);
 
-	drm_mode_config_init(dev);
-
-	priv->wq = alloc_ordered_workqueue("msm", 0);
-	priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0);
-	init_waitqueue_head(&priv->fence_event);
-	init_waitqueue_head(&priv->pending_crtcs_event);
-
 	ret = sde_power_resource_init(pdev, &priv->phandle);
 	if (ret) {
 		pr_err("sde power resource init failed\n");
@@ -466,30 +485,29 @@
 	}
 
 	/* Bind all our sub-components: */
-	ret = msm_component_bind_all(dev->dev, dev);
+	ret = msm_component_bind_all(dev, ddev);
 	if (ret)
 		return ret;
-	}
 
 	ret = msm_init_vram(ddev);
 	if (ret)
 		goto fail;
 
-	ret = sde_evtlog_init(dev->primary->debugfs_root);
+	ret = sde_evtlog_init(ddev->primary->debugfs_root);
 	if (ret) {
-		dev_err(dev->dev, "failed to init evtlog: %d\n", ret);
+		dev_err(dev, "failed to init evtlog: %d\n", ret);
 		goto fail;
 	}
 
 	switch (get_mdp_ver(pdev)) {
 	case KMS_MDP4:
-		kms = mdp4_kms_init(dev);
+		kms = mdp4_kms_init(ddev);
 		break;
 	case KMS_MDP5:
-		kms = mdp5_kms_init(dev);
+		kms = mdp5_kms_init(ddev);
 		break;
 	case KMS_SDE:
-		kms = sde_kms_init(dev);
+		kms = sde_kms_init(ddev);
 		break;
 	default:
 		kms = ERR_PTR(-ENODEV);
@@ -504,10 +522,12 @@
 		 * imx drm driver on iMX5
 		 */
 		priv->kms = NULL;
-		dev_err(dev->dev, "failed to load kms\n");
+		dev_err(dev, "failed to load kms\n");
 		ret = PTR_ERR(kms);
 		goto fail;
 	}
+	priv->kms = kms;
+	pm_runtime_enable(dev);
 
 	if (kms) {
 		ret = kms->funcs->hw_init(kms);
@@ -516,7 +536,6 @@
 			goto fail;
 		}
 	}
-
 	ddev->mode_config.funcs = &mode_config_funcs;
 
 	ret = drm_vblank_init(ddev, priv->num_crtcs);
@@ -527,7 +546,7 @@
 
 	if (kms) {
 		pm_runtime_get_sync(dev);
-		ret = drm_irq_install(ddev, kms->irq);
+		ret = drm_irq_install(ddev, platform_get_irq(pdev, 0));
 		pm_runtime_put_sync(dev);
 		if (ret < 0) {
 			dev_err(dev, "failed to install IRQ handler\n");
@@ -535,9 +554,6 @@
 		}
 	}
 
-	ret = drm_dev_register(ddev, 0);
-	if (ret)
-		goto fail;
 
 	drm_mode_config_reset(ddev);
 
@@ -554,18 +570,23 @@
 	if (kms && kms->funcs && kms->funcs->postinit) {
 		ret = kms->funcs->postinit(kms);
 		if (ret) {
-			dev_err(dev->dev, "kms post init failed: %d\n", ret);
+			pr_err("kms post init failed: %d\n", ret);
 			goto fail;
 		}
 	}
 
-	drm_kms_helper_poll_init(dev);
+	drm_kms_helper_poll_init(ddev);
 
 	return 0;
 
 fail:
 	msm_drm_uninit(dev);
 	return ret;
+mdss_init_fail:
+	kfree(priv);
+priv_alloc_fail:
+	drm_dev_unref(ddev);
+	return ret;
 }
 
 /*
@@ -1092,27 +1113,6 @@
 	SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume)
 };
 
-static int msm_drm_bind(struct device *dev)
-{
-	int ret;
-
-	ret = drm_platform_init(&msm_driver, to_platform_device(dev));
-	if (ret)
-		DRM_ERROR("drm_platform_init failed: %d\n", ret);
-
-	return ret;
-}
-
-static void msm_drm_unbind(struct device *dev)
-{
-	drm_put_dev(platform_get_drvdata(to_platform_device(dev)));
-}
-
-static const struct component_master_ops msm_drm_ops = {
-	.bind = msm_drm_bind,
-	.unbind = msm_drm_unbind,
-};
-
 /*
  * Componentized driver support:
  */
@@ -1196,11 +1196,64 @@
 
 static int compare_name_mdp(struct device *dev, void *data)
 {
+	return (strnstr(dev_name(dev), "mdp", strlen("mdp")) != NULL);
+}
+
+static int add_display_components(struct device *dev,
+				  struct component_match **matchptr)
+{
+	struct device *mdp_dev = NULL;
 	int ret;
 
-	ret = component_master_add_with_match(dev, &msm_drm_ops, match);
+	if (of_device_is_compatible(dev->of_node, "qcom,sde-kms")) {
+		struct device_node *np = dev->of_node;
+		unsigned int i;
+
+		for (i = 0; ; i++) {
+			struct device_node *node;
+
+			node = of_parse_phandle(np, "connectors", i);
+			if (!node)
+				break;
+
+			component_match_add(dev, matchptr, compare_of, node);
+		}
+		return 0;
+	}
+
+	/*
+	 * MDP5 based devices don't have a flat hierarchy. There is a top level
+	 * parent: MDSS, and children: MDP5, DSI, HDMI, eDP etc. Populate the
+	 * children devices, find the MDP5 node, and then add the interfaces
+	 * to our components list.
+	 */
+	if (of_device_is_compatible(dev->of_node, "qcom,mdss")) {
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+		if (ret) {
+			dev_err(dev, "failed to populate children devices\n");
+			return ret;
+		}
+
+		mdp_dev = device_find_child(dev, NULL, compare_name_mdp);
+		if (!mdp_dev) {
+			dev_err(dev, "failed to find MDSS MDP node\n");
+			of_platform_depopulate(dev);
+			return -ENODEV;
+		}
+
+		put_device(mdp_dev);
+
+		/* add the MDP component itself */
+		component_match_add(dev, matchptr, compare_of,
+				    mdp_dev->of_node);
+	} else {
+		/* MDP4 */
+		mdp_dev = dev;
+	}
+
+	ret = add_components_mdp(mdp_dev, matchptr);
 	if (ret)
-		DRM_ERROR("component add match failed: %d\n", ret);
+		of_platform_depopulate(dev);
 
 	return ret;
 }
@@ -1232,18 +1285,20 @@
 	return 0;
 }
 
-#else
-static int compare_dev(struct device *dev, void *data)
+static int msm_drm_bind(struct device *dev)
 {
 	return msm_drm_init(dev, &msm_driver);
 }
 
-static int msm_add_master_component(struct device *dev,
-					struct component_match *match)
+static void msm_drm_unbind(struct device *dev)
 {
 	msm_drm_uninit(dev);
 }
-#endif
+
+static const struct component_master_ops msm_drm_ops = {
+	.bind = msm_drm_bind,
+	.unbind = msm_drm_unbind,
+};
 
 /*
  * Platform driver:
@@ -1254,49 +1309,31 @@
 	int ret;
 	struct component_match *match = NULL;
 
-#ifdef CONFIG_OF
-	add_components(&pdev->dev, &match, "connectors");
-	add_components(&pdev->dev, &match, "gpus");
-#else
-	/* For non-DT case, it kinda sucks.  We don't actually have a way
-	 * to know whether or not we are waiting for certain devices (or if
-	 * they are simply not present).  But for non-DT we only need to
-	 * care about apq8064/apq8060/etc (all mdp4/a3xx):
-	 */
-	static const char * const devnames[] = {
-			"hdmi_msm.0", "kgsl-3d0.0",
-	};
-	int i;
-
-	DBG("Adding components..");
-
-	for (i = 0; i < ARRAY_SIZE(devnames); i++) {
-		struct device *dev;
-
 	ret = add_display_components(&pdev->dev, &match);
 	if (ret)
 		return ret;
 
-		component_match_add(&pdev->dev, &match, compare_dev, dev);
-	}
-#endif
-	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-	ret = msm_add_master_component(&pdev->dev, match);
+	ret = add_gpu_components(&pdev->dev, &match);
+	if (ret)
+		return ret;
 
-	return ret;
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
 }
 
 static int msm_pdev_remove(struct platform_device *pdev)
 {
-	msm_drm_unbind(&pdev->dev);
 	component_master_del(&pdev->dev, &msm_drm_ops);
+	of_platform_depopulate(&pdev->dev);
+
+	msm_drm_unbind(&pdev->dev);
 	return 0;
 }
 
 static const struct of_device_id dt_match[] = {
-	{ .compatible = "qcom,mdp" },      /* mdp4 */
-	{ .compatible = "qcom,mdss_mdp" }, /* mdp5 */
-	{ .compatible = "qcom,sde-kms" },  /* sde  */
+	{ .compatible = "qcom,mdp4", .data = (void *)4 },	/* MDP4 */
+	{ .compatible = "qcom,mdss", .data = (void *)5 },	/* MDP5 MDSS */
+	{ .compatible = "qcom,sde-kms", .data = (void *)3 },	/* sde */
 	{}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 869833f6..e6fdeb9 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -232,7 +232,6 @@
 struct msm_drm_event {
 	struct drm_pending_event base;
 	struct drm_event event;
-	struct drm_msm_event_req info;
 	u8 data[];
 };
 
@@ -326,6 +325,12 @@
 
 	struct msm_vblank_ctrl vblank_ctrl;
 
+	/* task holding struct_mutex.. currently only used in submit path
+	 * to detect and reject faults from copy_from_user() for submit
+	 * ioctl.
+	 */
+	struct task_struct *struct_mutex_task;
+
 	/* list of clients waiting for events */
 	struct list_head client_event_list;
 };
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 9d4e04b..c4cc729 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -960,7 +960,7 @@
 			ret = PTR_ERR(mmu);
 			SDE_ERROR("failed to init iommu id %d: rc: %d\n", i,
 					ret);
-			goto fail;
+			continue;
 		}
 
 		ret = mmu->funcs->attach(mmu, (const char **)iommu_ports,
@@ -968,7 +968,7 @@
 		if (ret) {
 			SDE_ERROR("failed to attach iommu %d: %d\n", i, ret);
 			mmu->funcs->destroy(mmu);
-			goto fail;
+			continue;
 		}
 
 		sde_kms->mmu_id[i] = msm_register_mmu(sde_kms->dev, mmu);