10519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae/* exynos_drm_iommu.c 20519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 30519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * Copyright (c) 2012 Samsung Electronics Co., Ltd. 40519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * Author: Inki Dae <inki.dae@samsung.com> 50519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 6d81aecb5e680311e1f3fd71e49e6a4072d2374d2Inki Dae * This program is free software; you can redistribute it and/or modify it 7d81aecb5e680311e1f3fd71e49e6a4072d2374d2Inki Dae * under the terms of the GNU General Public License as published by the 8d81aecb5e680311e1f3fd71e49e6a4072d2374d2Inki Dae * Free Software Foundation; either version 2 of the License, or (at your 9d81aecb5e680311e1f3fd71e49e6a4072d2374d2Inki Dae * option) any later version. 100519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae */ 110519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 120519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include <drmP.h> 130519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include <drm/exynos_drm.h> 140519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 150519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include <linux/dma-mapping.h> 160519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include <linux/iommu.h> 170519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include <linux/kref.h> 180519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 190519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include <asm/dma-iommu.h> 200519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 210519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include "exynos_drm_drv.h" 220519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae#include "exynos_drm_iommu.h" 230519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 240519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae/* 250519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * drm_create_iommu_mapping - create a mapping structure 260519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 270519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * @drm_dev: DRM device 280519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae */ 290519f9a12d0113caab78980c48a7902d2bd40c2cInki Daeint drm_create_iommu_mapping(struct drm_device *drm_dev) 300519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae{ 310519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct dma_iommu_mapping *mapping = NULL; 320519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct exynos_drm_private *priv = drm_dev->dev_private; 330519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct device *dev = drm_dev->dev; 340519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 350519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae if (!priv->da_start) 360519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae priv->da_start = EXYNOS_DEV_ADDR_START; 370519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae if (!priv->da_space_size) 380519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae priv->da_space_size = EXYNOS_DEV_ADDR_SIZE; 390519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 400519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start, 4168efd7d2fb32c2606f1da318b6a851d933813f27Marek Szyprowski priv->da_space_size); 4268efd7d2fb32c2606f1da318b6a851d933813f27Marek Szyprowski 43a0e41b562b3e302b47f887056d89189b816ce219Wei Yongjun if (IS_ERR(mapping)) 44a0e41b562b3e302b47f887056d89189b816ce219Wei Yongjun return PTR_ERR(mapping); 450519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 460519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), 470519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae GFP_KERNEL); 484db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat if (!dev->dma_parms) 494db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat goto error; 504db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat 510519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae dma_set_max_seg_size(dev, 0xffffffffu); 520519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae dev->archdata.mapping = mapping; 530519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 540519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae return 0; 554db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamaterror: 564db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat arm_iommu_release_mapping(mapping); 574db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat return -ENOMEM; 580519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae} 590519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 600519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae/* 610519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * drm_release_iommu_mapping - release iommu mapping structure 620519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 630519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * @drm_dev: DRM device 640519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 650519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * if mapping->kref becomes 0 then all things related to iommu mapping 660519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * will be released 670519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae */ 680519f9a12d0113caab78980c48a7902d2bd40c2cInki Daevoid drm_release_iommu_mapping(struct drm_device *drm_dev) 690519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae{ 700519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct device *dev = drm_dev->dev; 710519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 720519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae arm_iommu_release_mapping(dev->archdata.mapping); 730519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae} 740519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 750519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae/* 760519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * drm_iommu_attach_device- attach device to iommu mapping 770519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 780519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * @drm_dev: DRM device 790519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * @subdrv_dev: device to be attach 800519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 810519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * This function should be called by sub drivers to attach it to iommu 820519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * mapping. 830519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae */ 840519f9a12d0113caab78980c48a7902d2bd40c2cInki Daeint drm_iommu_attach_device(struct drm_device *drm_dev, 850519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct device *subdrv_dev) 860519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae{ 870519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct device *dev = drm_dev->dev; 880519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae int ret; 890519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 900519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae if (!dev->archdata.mapping) { 910519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae DRM_ERROR("iommu_mapping is null.\n"); 920519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae return -EFAULT; 930519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae } 940519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 950519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev, 960519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae sizeof(*subdrv_dev->dma_parms), 970519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae GFP_KERNEL); 984db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat if (!subdrv_dev->dma_parms) 994db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat return -ENOMEM; 1004db7fcdf59551d9d0a9fe59bd919a32feae925b2Sachin Kamat 1010519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae dma_set_max_seg_size(subdrv_dev, 0xffffffffu); 1020519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 1030519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping); 1040519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae if (ret < 0) { 1050519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae DRM_DEBUG_KMS("failed iommu attach.\n"); 1060519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae return ret; 1070519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae } 1080519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 1090519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae /* 1100519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * Set dma_ops to drm_device just one time. 1110519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 1120519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * The dma mapping api needs device object and the api is used 1130519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * to allocate physial memory and map it with iommu table. 1140519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * If iommu attach succeeded, the sub driver would have dma_ops 1150519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * for iommu and also all sub drivers have same dma_ops. 1160519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae */ 1170519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae if (!dev->archdata.dma_ops) 1180519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae dev->archdata.dma_ops = subdrv_dev->archdata.dma_ops; 1190519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 1200519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae return 0; 1210519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae} 1220519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 1230519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae/* 1240519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * drm_iommu_detach_device -detach device address space mapping from device 1250519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 1260519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * @drm_dev: DRM device 1270519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * @subdrv_dev: device to be detached 1280519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * 1290519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * This function should be called by sub drivers to detach it from iommu 1300519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae * mapping 1310519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae */ 1320519f9a12d0113caab78980c48a7902d2bd40c2cInki Daevoid drm_iommu_detach_device(struct drm_device *drm_dev, 1330519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct device *subdrv_dev) 1340519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae{ 1350519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct device *dev = drm_dev->dev; 1360519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae struct dma_iommu_mapping *mapping = dev->archdata.mapping; 1370519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 1380519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae if (!mapping || !mapping->domain) 1390519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae return; 1400519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae 1410519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae iommu_detach_device(mapping->domain, subdrv_dev); 1420519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae drm_release_iommu_mapping(drm_dev); 1430519f9a12d0113caab78980c48a7902d2bd40c2cInki Dae} 144