Merge "drm/msm/sde: fix msm drm driver probe sequence" into msm-4.8
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);