Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f82c1372 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'exynos-drm-next' of...

Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

   This pull request adds to the rework patch series for IOMMU
   integration to support ARM64bit architecture with DMA-IOMMU
   glue code.

   With this patch series, Exynos DRM works well on Exynos5433 SoC
   with IOMMU enabled.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos: iommu: add support for ARM64 specific code for IOMMU glue
  drm/exynos: iommu: move ARM specific code to exynos_drm_iommu.h
  drm/exynos: iommu: remove unused entries from exynos_drm_private strcuture
  drm/exynos: iommu: add a check if all sub-devices have iommu controller
  drm/exynos: iommu: move dma_params configuration code to separate functions
parents 35b8a749 197adf0b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ if DRM_EXYNOS

config DRM_EXYNOS_IOMMU
	bool
	depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
	depends on EXYNOS_IOMMU
	default y

comment "CRTCs"
+1 −6
Original line number Diff line number Diff line
@@ -159,12 +159,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
	DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
		 dev_name(private->dma_dev));

	/*
	 * create mapping to manage iommu table and set a pointer to iommu
	 * mapping structure to iommu_mapping of private data.
	 * also this iommu_mapping can be used to check if iommu is supported
	 * or not.
	 */
	/* create common IOMMU mapping for all devices attached to Exynos DRM */
	ret = drm_create_iommu_mapping(dev);
	if (ret < 0) {
		DRM_ERROR("failed to create iommu mapping.\n");
+0 −2
Original line number Diff line number Diff line
@@ -224,8 +224,6 @@ struct exynos_drm_private {
	struct drm_property *plane_zpos_property;

	struct device *dma_dev;
	unsigned long da_start;
	unsigned long da_space_size;
	void *mapping;

	unsigned int pipe;
+33 −44
Original line number Diff line number Diff line
@@ -14,13 +14,27 @@

#include <linux/dma-mapping.h>
#include <linux/iommu.h>
#include <linux/kref.h>

#include <asm/dma-iommu.h>

#include "exynos_drm_drv.h"
#include "exynos_drm_iommu.h"

static inline int configure_dma_max_seg_size(struct device *dev)
{
	if (!dev->dma_parms)
		dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
	if (!dev->dma_parms)
		return -ENOMEM;

	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
	return 0;
}

static inline void clear_dma_max_seg_size(struct device *dev)
{
	kfree(dev->dma_parms);
	dev->dma_parms = NULL;
}

/*
 * drm_create_iommu_mapping - create a mapping structure
 *
@@ -28,38 +42,22 @@
 */
int drm_create_iommu_mapping(struct drm_device *drm_dev)
{
	struct dma_iommu_mapping *mapping = NULL;
	struct exynos_drm_private *priv = drm_dev->dev_private;

	if (!priv->da_start)
		priv->da_start = EXYNOS_DEV_ADDR_START;
	if (!priv->da_space_size)
		priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;

	mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
						priv->da_space_size);

	if (IS_ERR(mapping))
		return PTR_ERR(mapping);

	priv->mapping = mapping;

	return 0;
	return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START,
					     EXYNOS_DEV_ADDR_SIZE);
}

/*
 * drm_release_iommu_mapping - release iommu mapping structure
 *
 * @drm_dev: DRM device
 *
 * if mapping->kref becomes 0 then all things related to iommu mapping
 * will be released
 */
void drm_release_iommu_mapping(struct drm_device *drm_dev)
{
	struct exynos_drm_private *priv = drm_dev->dev_private;

	arm_iommu_release_mapping(priv->mapping);
	__exynos_iommu_release_mapping(priv);
}

/*
@@ -77,25 +75,19 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
	struct exynos_drm_private *priv = drm_dev->dev_private;
	int ret;

	if (!priv->mapping)
		return 0;

	subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
					sizeof(*subdrv_dev->dma_parms),
					GFP_KERNEL);
	if (!subdrv_dev->dma_parms)
		return -ENOMEM;

	dma_set_max_seg_size(subdrv_dev, 0xffffffffu);

	if (subdrv_dev->archdata.mapping)
		arm_iommu_detach_device(subdrv_dev);
	if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
		DRM_ERROR("Device %s lacks support for IOMMU\n",
			  dev_name(subdrv_dev));
		return -EINVAL;
	}

	ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
	if (ret < 0) {
		DRM_DEBUG_KMS("failed iommu attach.\n");
	ret = configure_dma_max_seg_size(subdrv_dev);
	if (ret)
		return ret;
	}

	ret = __exynos_iommu_attach(priv, subdrv_dev);
	if (ret)
		clear_dma_max_seg_size(subdrv_dev);

	return 0;
}
@@ -113,10 +105,7 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
				struct device *subdrv_dev)
{
	struct exynos_drm_private *priv = drm_dev->dev_private;
	struct dma_iommu_mapping *mapping = priv->mapping;

	if (!mapping || !mapping->domain)
		return;

	arm_iommu_detach_device(subdrv_dev);
	__exynos_iommu_detach(priv, subdrv_dev);
	clear_dma_max_seg_size(subdrv_dev);
}
+91 −0
Original line number Diff line number Diff line
@@ -17,6 +17,97 @@

#ifdef CONFIG_DRM_EXYNOS_IOMMU

#if defined(CONFIG_ARM_DMA_USE_IOMMU)
#include <asm/dma-iommu.h>

static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
					unsigned long start, unsigned long size)
{
	priv->mapping = arm_iommu_create_mapping(&platform_bus_type, start,
						 size);
	return IS_ERR(priv->mapping);
}

static inline void
__exynos_iommu_release_mapping(struct exynos_drm_private *priv)
{
	arm_iommu_release_mapping(priv->mapping);
}

static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
					struct device *dev)
{
	if (dev->archdata.mapping)
		arm_iommu_detach_device(dev);

	return arm_iommu_attach_device(dev, priv->mapping);
}

static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
					 struct device *dev)
{
	arm_iommu_detach_device(dev);
}

#elif defined(CONFIG_IOMMU_DMA)
#include <linux/dma-iommu.h>

static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
					unsigned long start, unsigned long size)
{
	struct iommu_domain *domain;
	int ret;

	domain = iommu_domain_alloc(priv->dma_dev->bus);
	if (!domain)
		return -ENOMEM;

	ret = iommu_get_dma_cookie(domain);
	if (ret)
		goto free_domain;

	ret = iommu_dma_init_domain(domain, start, size);
	if (ret)
		goto put_cookie;

	priv->mapping = domain;
	return 0;

put_cookie:
	iommu_put_dma_cookie(domain);
free_domain:
	iommu_domain_free(domain);
	return ret;
}

static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
{
	struct iommu_domain *domain = priv->mapping;

	iommu_put_dma_cookie(domain);
	iommu_domain_free(domain);
	priv->mapping = NULL;
}

static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
					struct device *dev)
{
	struct iommu_domain *domain = priv->mapping;

	return iommu_attach_device(domain, dev);
}

static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
					 struct device *dev)
{
	struct iommu_domain *domain = priv->mapping;

	iommu_detach_device(domain, dev);
}
#else
#error Unsupported architecture and IOMMU/DMA-mapping glue code
#endif

int drm_create_iommu_mapping(struct drm_device *drm_dev);

void drm_release_iommu_mapping(struct drm_device *drm_dev);