| /* exynos_drm_iommu.h |
| * |
| * Copyright (c) 2012 Samsung Electronics Co., Ltd. |
| * Authoer: Inki Dae <inki.dae@samsung.com> |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. |
| */ |
| |
| #ifndef _EXYNOS_DRM_IOMMU_H_ |
| #define _EXYNOS_DRM_IOMMU_H_ |
| |
| #define EXYNOS_DEV_ADDR_START 0x20000000 |
| #define EXYNOS_DEV_ADDR_SIZE 0x40000000 |
| |
| #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, NULL); |
| 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); |
| |
| int drm_iommu_attach_device(struct drm_device *drm_dev, |
| struct device *subdrv_dev); |
| |
| void drm_iommu_detach_device(struct drm_device *dev_dev, |
| struct device *subdrv_dev); |
| |
| static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) |
| { |
| struct exynos_drm_private *priv = drm_dev->dev_private; |
| |
| return priv->mapping ? true : false; |
| } |
| |
| #else |
| |
| static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) |
| { |
| return 0; |
| } |
| |
| static inline void drm_release_iommu_mapping(struct drm_device *drm_dev) |
| { |
| } |
| |
| static inline int drm_iommu_attach_device(struct drm_device *drm_dev, |
| struct device *subdrv_dev) |
| { |
| return 0; |
| } |
| |
| static inline void drm_iommu_detach_device(struct drm_device *drm_dev, |
| struct device *subdrv_dev) |
| { |
| } |
| |
| static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) |
| { |
| return false; |
| } |
| |
| #endif |
| #endif |