diff options
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gem_vma.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_iommu.c | 178 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_mmu.h | 13 |
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__ */ |
