瀏覽代碼

Merge "disp: msm: move SMMU devices as separate devices"

qctecmdr 5 年之前
父節點
當前提交
5f4d6ef993
共有 1 個文件被更改,包括 91 次插入19 次删除
  1. 91 19
      msm/msm_smmu.c

+ 91 - 19
msm/msm_smmu.c

@@ -31,10 +31,12 @@
 
 struct msm_smmu_client {
 	struct device *dev;
+	const char *compat;
 	struct iommu_domain *domain;
 	const struct dma_map_ops *dma_ops;
 	bool domain_attached;
 	bool secure;
+	struct list_head smmu_list;
 };
 
 struct msm_smmu {
@@ -51,6 +53,12 @@ struct msm_smmu_domain {
 #define to_msm_smmu(x) container_of(x, struct msm_smmu, base)
 #define msm_smmu_to_client(smmu) (smmu->client)
 
+/* Serialization lock for smmu_list */
+static DEFINE_MUTEX(smmu_list_lock);
+
+/* List of all smmu devices installed */
+static LIST_HEAD(sde_smmu_list);
+
 static int msm_smmu_attach(struct msm_mmu *mmu, const char * const *names,
 		int cnt)
 {
@@ -335,12 +343,36 @@ static const struct of_device_id msm_smmu_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, msm_smmu_dt_match);
 
-static struct device *msm_smmu_device_create(struct device *dev,
+static struct msm_smmu_client *msm_smmu_get_smmu(const char *compat)
+{
+	struct msm_smmu_client *curr = NULL;
+	bool found = false;
+
+	if (!compat) {
+		pr_err("invalid param\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	mutex_lock(&smmu_list_lock);
+	list_for_each_entry(curr, &sde_smmu_list, smmu_list) {
+		if (of_compat_cmp(compat, curr->compat, strlen(compat)) == 0) {
+			DRM_DEBUG("found msm_smmu_client for %s\n", compat);
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&smmu_list_lock);
+
+	if (!found)
+		return ERR_PTR(-ENODEV);
+
+	return curr;
+}
+
+static struct device *msm_smmu_device_add(struct device *dev,
 		enum msm_mmu_domain_type domain,
 		struct msm_smmu *smmu)
 {
-	struct device_node *child;
-	struct platform_device *pdev;
 	int i;
 	const char *compat = NULL;
 
@@ -357,22 +389,14 @@ static struct device *msm_smmu_device_create(struct device *dev,
 	}
 	DRM_DEBUG("found domain %d compat: %s\n", domain, compat);
 
-	child = of_find_compatible_node(dev->of_node, NULL, compat);
-	if (!child) {
-		DRM_DEBUG("unable to find compatible node for %s\n", compat);
-		return ERR_PTR(-ENODEV);
-	}
-
-	pdev = of_platform_device_create(child, NULL, dev);
-	if (!pdev) {
-		DRM_ERROR("unable to create smmu platform dev for domain %d\n",
-				domain);
+	smmu->client = msm_smmu_get_smmu(compat);
+	if (IS_ERR_OR_NULL(smmu->client)) {
+		DRM_ERROR("unable to find domain %d compat: %s\n", domain,
+				compat);
 		return ERR_PTR(-ENODEV);
 	}
 
-	smmu->client = platform_get_drvdata(pdev);
-
-	return &pdev->dev;
+	return smmu->client->dev;
 }
 
 struct msm_mmu *msm_smmu_new(struct device *dev,
@@ -385,8 +409,8 @@ struct msm_mmu *msm_smmu_new(struct device *dev,
 	if (!smmu)
 		return ERR_PTR(-ENOMEM);
 
-	client_dev = msm_smmu_device_create(dev, domain, smmu);
-	if (IS_ERR(client_dev)) {
+	client_dev = msm_smmu_device_add(dev, domain, smmu);
+	if (IS_ERR_OR_NULL(client_dev)) {
 		kfree(smmu);
 		return (void *)client_dev ? : ERR_PTR(-ENODEV);
 	}
@@ -423,6 +447,34 @@ static int msm_smmu_fault_handler(struct iommu_domain *domain,
 	return rc;
 }
 
+/**
+ * msm_smmu_bind - bind smmu device with controlling device
+ * @dev:        Pointer to base of platform device
+ * @master:     Pointer to container of drm device
+ * @data:       Pointer to private data
+ * Returns:     Zero on success
+ */
+static int msm_smmu_bind(struct device *dev, struct device *master, void *data)
+{
+	return 0;
+}
+
+/**
+ * msm_smmu_unbind - unbind msm_smmu from controlling device
+ * @dev:        Pointer to base of platform device
+ * @master:     Pointer to container of drm device
+ * @data:       Pointer to private data
+ */
+static void msm_smmu_unbind(struct device *dev,
+		struct device *master, void *data)
+{
+}
+
+static const struct component_ops msm_smmu_comp_ops = {
+	.bind = msm_smmu_bind,
+	.unbind = msm_smmu_unbind,
+};
+
 /**
  * msm_smmu_probe()
  * @pdev: platform device
@@ -437,6 +489,7 @@ static int msm_smmu_probe(struct platform_device *pdev)
 	const struct of_device_id *match;
 	struct msm_smmu_client *client;
 	const struct msm_smmu_domain *domain;
+	int ret;
 
 	match = of_match_device(msm_smmu_dt_match, &pdev->dev);
 	if (!match || !match->data) {
@@ -462,6 +515,7 @@ static int msm_smmu_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "iommu get domain for dev failed\n");
 		return -EINVAL;
 	}
+	client->compat = match->compatible;
 	client->secure = domain->secure;
 	client->domain_attached = true;
 
@@ -479,16 +533,34 @@ static int msm_smmu_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, client);
 
-	return 0;
+	mutex_lock(&smmu_list_lock);
+	list_add(&client->smmu_list, &sde_smmu_list);
+	mutex_unlock(&smmu_list_lock);
+
+	ret = component_add(&pdev->dev, &msm_smmu_comp_ops);
+	if (ret)
+		pr_err("component add failed\n");
+
+	return ret;
 }
 
 static int msm_smmu_remove(struct platform_device *pdev)
 {
 	struct msm_smmu_client *client;
+	struct msm_smmu_client *curr, *next;
 
 	client = platform_get_drvdata(pdev);
 	client->domain_attached = false;
 
+	mutex_lock(&smmu_list_lock);
+	list_for_each_entry_safe(curr, next, &sde_smmu_list, smmu_list) {
+		if (curr == client) {
+			list_del(&client->smmu_list);
+			break;
+		}
+	}
+	mutex_unlock(&smmu_list_lock);
+
 	return 0;
 }