[go: nahoru, domu]

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