/* exynos_drm_iommu.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * Authoer: Inki Dae * * 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 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 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