diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_drv.c')
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 81 |
1 files changed, 78 insertions, 3 deletions
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 14ab9a627d8b..1ed4cd09dbf8 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -26,6 +26,7 @@ #include "msm_gem.h" #include "msm_gpu.h" #include "msm_kms.h" +#include "msm_mmu.h" #include "adreno/adreno_gpu.h" /* @@ -267,12 +268,56 @@ static int msm_drm_uninit(struct device *dev) #include <linux/of_address.h> +struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) +{ + struct iommu_domain *domain; + struct msm_gem_address_space *aspace; + struct msm_mmu *mmu; + struct device *mdp_dev = dev->dev; + struct device *mdss_dev = mdp_dev->parent; + struct device *iommu_dev; + + /* + * IOMMUs can be a part of MDSS device tree binding, or the + * MDP/DPU device. + */ + if (device_iommu_mapped(mdp_dev)) + iommu_dev = mdp_dev; + else + iommu_dev = mdss_dev; + + domain = iommu_domain_alloc(iommu_dev->bus); + if (!domain) { + drm_info(dev, "no IOMMU, fallback to phys contig buffers for scanout\n"); + return NULL; + } + + mmu = msm_iommu_new(iommu_dev, domain); + if (IS_ERR(mmu)) { + iommu_domain_free(domain); + return ERR_CAST(mmu); + } + + aspace = msm_gem_address_space_create(mmu, "mdp_kms", + 0x1000, 0x100000000 - 0x1000); + if (IS_ERR(aspace)) + mmu->funcs->destroy(mmu); + + return aspace; +} + bool msm_use_mmu(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; - /* a2xx comes with its own MMU */ - return priv->is_a2xx || iommu_present(&platform_bus_type); + /* + * a2xx comes with its own MMU + * On other platforms IOMMU can be declared specified either for the + * MDP/DPU device or for its parent, MDSS device. + */ + return priv->is_a2xx || + device_iommu_mapped(dev->dev) || + device_iommu_mapped(dev->dev->parent); } static int msm_init_vram(struct drm_device *dev) @@ -633,12 +678,25 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_msm_gem_new *args = data; + uint32_t flags = args->flags; if (args->flags & ~MSM_BO_FLAGS) { DRM_ERROR("invalid flags: %08x\n", args->flags); return -EINVAL; } + /* + * Uncached CPU mappings are deprecated, as of: + * + * 9ef364432db4 ("drm/msm: deprecate MSM_BO_UNCACHED (map as writecombine instead)") + * + * So promote them to WC. + */ + if (flags & MSM_BO_UNCACHED) { + flags &= ~MSM_BO_CACHED; + flags |= MSM_BO_WC; + } + return msm_gem_new_handle(dev, file, args->size, args->flags, &args->handle, NULL); } @@ -948,7 +1006,24 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW), }; -DEFINE_DRM_GEM_FOPS(fops); +static void msm_fop_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct drm_file *file = f->private_data; + struct drm_device *dev = file->minor->dev; + struct msm_drm_private *priv = dev->dev_private; + struct drm_printer p = drm_seq_file_printer(m); + + if (!priv->gpu) + return; + + msm_gpu_show_fdinfo(priv->gpu, file->driver_priv, &p); +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + DRM_GEM_FOPS, + .show_fdinfo = msm_fop_show_fdinfo, +}; static const struct drm_driver msm_driver = { .driver_features = DRIVER_GEM | |