summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c10
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c4
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c178
-rw-r--r--drivers/gpu/drm/msm/msm_mmu.h13
6 files changed, 125 insertions, 84 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index b6cddee0cf34..d089ba600de8 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -515,15 +515,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
mdelay(16);
if (config->iommu) {
- struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu);
-
- if (IS_ERR(mmu)) {
- ret = PTR_ERR(mmu);
- goto fail;
- }
+ config->iommu->geometry.aperture_start = 0x1000;
+ config->iommu->geometry.aperture_end = 0xffffffff;
aspace = msm_gem_address_space_create(&pdev->dev,
- mmu, "mdp4", 0x1000, 0xffffffff);
+ config->iommu, MSM_IOMMU_DOMAIN_DEFAULT, "mdp4");
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
goto fail;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 943d73fa544d..d934819d1f1c 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -412,7 +412,7 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
/* For GPU and legacy display */
struct msm_gem_address_space *
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
- const char *name);
+ int type, const char *name);
struct msm_gem_address_space *
msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name,
uint64_t start, uint64_t end);
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 1f912ebff683..47f7436854fb 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -147,9 +147,9 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
struct msm_gem_address_space *
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
- const char *name)
+ int type, const char *name)
{
- struct msm_mmu *mmu = msm_iommu_new(dev, domain);
+ struct msm_mmu *mmu = msm_iommu_new(dev, type, domain);
if (IS_ERR(mmu))
return (struct msm_gem_address_space *) mmu;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 5a505a8bf328..cbc37dcce1d0 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -837,7 +837,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
dev_info(drm->dev, "%s: using IOMMU\n", name);
gpu->aspace = msm_gem_address_space_create(&pdev->dev,
- iommu, "gpu");
+ iommu, MSM_IOMMU_DOMAIN_USER, "gpu");
if (IS_ERR(gpu->aspace)) {
ret = PTR_ERR(gpu->aspace);
dev_err(drm->dev, "failed to init iommu: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index e465c737aab5..38b5cd6d45df 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -27,23 +27,41 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
return 0;
}
+static void enable_iommu_clocks(struct msm_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->nr_clocks; i++) {
+ if (iommu->clocks[i])
+ clk_prepare_enable(iommu->clocks[i]);
+ }
+}
+
+static void disable_iommu_clocks(struct msm_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->nr_clocks; i++) {
+ if (iommu->clocks[i])
+ clk_disable_unprepare(iommu->clocks[i]);
+ }
+}
+
/*
* Get and enable the IOMMU clocks so that we can make
* sure they stay on the entire duration so that we can
* safely change the pagetable from the GPU
*/
-static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
+static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev)
{
- struct msm_iommu *iommu = to_msm_iommu(mmu);
- struct device *dev;
struct property *prop;
const char *name;
int i = 0;
- if (WARN_ON(!pdev))
+ if (iommu->nr_clocks) {
+ enable_iommu_clocks(iommu);
return;
-
- dev = &pdev->dev;
+ }
iommu->nr_clocks =
of_property_count_strings(dev->of_node, "clock-names");
@@ -61,79 +79,40 @@ static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
break;
iommu->clocks[i] = clk_get(dev, name);
- if (iommu->clocks[i])
- clk_prepare_enable(iommu->clocks[i]);
-
i++;
}
+
+ enable_iommu_clocks(iommu);
}
-static int _attach_iommu_device(struct msm_mmu *mmu,
- struct iommu_domain *domain, const char **names, int cnt)
+static int msm_iommu_attach(struct msm_mmu *mmu, const char **names,
+ int cnt)
{
- int i;
-
- /* See if there is a iommus member in the current device. If not, look
- * for the names and see if there is one in there.
- */
-
- if (of_find_property(mmu->dev->of_node, "iommus", NULL))
- return iommu_attach_device(domain, mmu->dev);
-
- /* Look through the list of names for a target */
- for (i = 0; i < cnt; i++) {
- struct device_node *node =
- of_find_node_by_name(mmu->dev->of_node, names[i]);
-
- if (!node)
- continue;
-
- if (of_find_property(node, "iommus", NULL)) {
- struct platform_device *pdev;
-
- /* Get the platform device for the node */
- of_platform_populate(node->parent, NULL, NULL,
- mmu->dev);
-
- pdev = of_find_device_by_node(node);
-
- if (!pdev)
- continue;
-
- _get_iommu_clocks(mmu,
- of_find_device_by_node(node->parent));
-
- mmu->dev = &pdev->dev;
-
- return iommu_attach_device(domain, mmu->dev);
- }
- }
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
- dev_err(mmu->dev, "Couldn't find a IOMMU device\n");
- return -ENODEV;
+ return iommu_attach_device(iommu->domain, mmu->dev);
}
-static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
+static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names,
+ int cnt)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- int val = 1, ret;
+ int ret, val = 1;
/* Hope springs eternal */
- iommu->allow_dynamic = true;
+ iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain,
+ DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false;
- /* per-instance pagetables need TTBR1 support in the IOMMU driver */
- ret = iommu_domain_set_attr(iommu->domain,
- DOMAIN_ATTR_ENABLE_TTBR1, &val);
- if (ret)
- iommu->allow_dynamic = false;
+ get_iommu_clocks(iommu, mmu->dev->parent);
/* Mark the GPU as I/O coherent if it is supported */
iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node);
- /* Attach the device to the domain */
- ret = _attach_iommu_device(mmu, iommu->domain, names, cnt);
- if (ret)
+ ret = iommu_attach_device(iommu->domain, mmu->dev);
+ if (ret) {
+ disable_iommu_clocks(iommu);
return ret;
+ }
/*
* Get the context bank for the base domain; this will be shared with
@@ -179,14 +158,10 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names,
static void msm_iommu_detach(struct msm_mmu *mmu)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- int i;
iommu_detach_device(iommu->domain, mmu->dev);
- for (i = 0; i < iommu->nr_clocks; i++) {
- if (iommu->clocks[i])
- clk_disable(iommu->clocks[i]);
- }
+ disable_iommu_clocks(iommu);
}
static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
@@ -249,7 +224,30 @@ static void msm_iommu_destroy(struct msm_mmu *mmu)
kfree(iommu);
}
-static const struct msm_mmu_funcs funcs = {
+static struct device *find_context_bank(const char *name)
+{
+ struct device_node *node = of_find_node_by_name(NULL, name);
+ struct platform_device *pdev, *parent;
+
+ if (!node)
+ return ERR_PTR(-ENODEV);
+
+ if (!of_find_property(node, "iommus", NULL))
+ return ERR_PTR(-ENODEV);
+
+ /* Get the parent device */
+ parent = of_find_device_by_node(node->parent);
+
+ /* Populate the sub nodes */
+ of_platform_populate(parent->dev.of_node, NULL, NULL, &parent->dev);
+
+ /* Get the context bank device */
+ pdev = of_find_device_by_node(node);
+
+ return pdev ? &pdev->dev : ERR_PTR(-ENODEV);
+}
+
+static const struct msm_mmu_funcs default_funcs = {
.attach = msm_iommu_attach,
.detach = msm_iommu_detach,
.map = msm_iommu_map,
@@ -257,6 +255,14 @@ static const struct msm_mmu_funcs funcs = {
.destroy = msm_iommu_destroy,
};
+static const struct msm_mmu_funcs user_funcs = {
+ .attach = msm_iommu_attach_user,
+ .detach = msm_iommu_detach,
+ .map = msm_iommu_map,
+ .unmap = msm_iommu_unmap,
+ .destroy = msm_iommu_destroy,
+};
+
static const struct msm_mmu_funcs dynamic_funcs = {
.attach = msm_iommu_attach_dynamic,
.detach = msm_iommu_detach_dynamic,
@@ -265,8 +271,22 @@ static const struct msm_mmu_funcs dynamic_funcs = {
.destroy = msm_iommu_destroy,
};
-struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
- const struct msm_mmu_funcs *funcs)
+static const struct {
+ const char *cbname;
+ const struct msm_mmu_funcs *funcs;
+} msm_iommu_domains[] = {
+ [MSM_IOMMU_DOMAIN_DEFAULT] = {
+ .cbname = NULL,
+ .funcs = &default_funcs,
+ },
+ [MSM_IOMMU_DOMAIN_USER] = {
+ .cbname = "gfx3d_user",
+ .funcs = &user_funcs,
+ },
+};
+
+static struct msm_mmu *iommu_create(struct device *dev,
+ struct iommu_domain *domain, const struct msm_mmu_funcs *funcs)
{
struct msm_iommu *iommu;
@@ -280,9 +300,23 @@ struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
return &iommu->base;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
+
+struct msm_mmu *msm_iommu_new(struct device *parent,
+ enum msm_iommu_domain_type type, struct iommu_domain *domain)
{
- return _msm_iommu_new(dev, domain, &funcs);
+ struct device *dev = parent;
+
+ if (type >= ARRAY_SIZE(msm_iommu_domains) ||
+ !msm_iommu_domains[type].funcs)
+ return ERR_PTR(-ENODEV);
+
+ if (msm_iommu_domains[type].cbname) {
+ dev = find_context_bank(msm_iommu_domains[type].cbname);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+ }
+
+ return iommu_create(dev, domain, msm_iommu_domains[type].funcs);
}
/*
@@ -307,7 +341,7 @@ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *base)
if (!domain)
return ERR_PTR(-ENODEV);
- mmu = _msm_iommu_new(base->dev, domain, &dynamic_funcs);
+ mmu = iommu_create(base->dev, domain, &dynamic_funcs);
if (IS_ERR(mmu)) {
if (domain)
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index 2cbe5c7c7bf9..0292a9ae1d33 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -30,6 +30,11 @@ enum msm_mmu_domain_type {
MSM_SMMU_DOMAIN_MAX,
};
+enum msm_iommu_domain_type {
+ MSM_IOMMU_DOMAIN_DEFAULT,
+ MSM_IOMMU_DOMAIN_USER,
+};
+
struct msm_mmu_funcs {
int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
void (*detach)(struct msm_mmu *mmu);
@@ -52,9 +57,15 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
mmu->funcs = funcs;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
+/* Create a new SDE mmu device */
struct msm_mmu *msm_smmu_new(struct device *dev,
enum msm_mmu_domain_type domain);
+
+/* Create a new legacy MDP4 or GPU mmu device */
+struct msm_mmu *msm_iommu_new(struct device *parent,
+ enum msm_iommu_domain_type type, struct iommu_domain *domain);
+
+/* Create a new dynamic domain for GPU */
struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig);
#endif /* __MSM_MMU_H__ */