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

Commit 04f77673 authored by Marek Szyprowski's avatar Marek Szyprowski Committed by Sylwester Nawrocki
Browse files

media: s5p-mfc: add iommu support



This patch adds support for IOMMU to s5p-mfc device driver. MFC firmware
is limited and it cannot use the default configuration. If IOMMU is
available, the patch disables the default DMA address space
configuration and creates a new address space of size limited to 256M
and base address set to 0x20000000.

For now the same address space is shared by both 'left' and 'right'
memory channels, because the DMA/IOMMU frameworks do not support
configuring them separately. This is not optimal, but besides limiting
total address space available has no other drawbacks (MFC firmware
supports 256M of address space per each channel).

Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarJavier Martinez Canillas <javier@osg.samsung.com>
Tested-by: default avatarJavier Martinez Canillas <javier@osg.samsung.com>
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
parent c79667dd
Loading
Loading
Loading
Loading
+24 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@
#include "s5p_mfc_dec.h"
#include "s5p_mfc_dec.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_intr.h"
#include "s5p_mfc_intr.h"
#include "s5p_mfc_iommu.h"
#include "s5p_mfc_opr.h"
#include "s5p_mfc_opr.h"
#include "s5p_mfc_cmd.h"
#include "s5p_mfc_cmd.h"
#include "s5p_mfc_pm.h"
#include "s5p_mfc_pm.h"
@@ -1083,6 +1084,22 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev)
{
{
	struct device *dev = &mfc_dev->plat_dev->dev;
	struct device *dev = &mfc_dev->plat_dev->dev;


	/*
	 * When IOMMU is available, we cannot use the default configuration,
	 * because of MFC firmware requirements: address space limited to
	 * 256M and non-zero default start address.
	 * This is still simplified, not optimal configuration, but for now
	 * IOMMU core doesn't allow to configure device's IOMMUs channel
	 * separately.
	 */
	if (exynos_is_iommu_available(dev)) {
		int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE,
						 S5P_MFC_IOMMU_DMA_SIZE);
		if (ret == 0)
			mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev;
		return ret;
	}

	/*
	/*
	 * Create and initialize virtual devices for accessing
	 * Create and initialize virtual devices for accessing
	 * reserved memory regions.
	 * reserved memory regions.
@@ -1103,6 +1120,13 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev)


static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev)
static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev)
{
{
	struct device *dev = &mfc_dev->plat_dev->dev;

	if (exynos_is_iommu_available(dev)) {
		exynos_unconfigure_iommu(dev);
		return;
	}

	device_unregister(mfc_dev->mem_dev_l);
	device_unregister(mfc_dev->mem_dev_l);
	device_unregister(mfc_dev->mem_dev_r);
	device_unregister(mfc_dev->mem_dev_r);
}
}
+79 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2015 Samsung Electronics Co.Ltd
 * Authors: Marek Szyprowski <m.szyprowski@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 S5P_MFC_IOMMU_H_
#define S5P_MFC_IOMMU_H_

#define S5P_MFC_IOMMU_DMA_BASE	0x20000000lu
#define S5P_MFC_IOMMU_DMA_SIZE	SZ_256M

#ifdef CONFIG_EXYNOS_IOMMU

#include <asm/dma-iommu.h>

static inline bool exynos_is_iommu_available(struct device *dev)
{
	return dev->archdata.iommu != NULL;
}

static inline void exynos_unconfigure_iommu(struct device *dev)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);

	arm_iommu_detach_device(dev);
	arm_iommu_release_mapping(mapping);
}

static inline int exynos_configure_iommu(struct device *dev,
					 unsigned int base, unsigned int size)
{
	struct dma_iommu_mapping *mapping = NULL;
	int ret;

	/* Disable the default mapping created by device core */
	if (to_dma_iommu_mapping(dev))
		exynos_unconfigure_iommu(dev);

	mapping = arm_iommu_create_mapping(dev->bus, base, size);
	if (IS_ERR(mapping)) {
		pr_warn("Failed to create IOMMU mapping for device %s\n",
			dev_name(dev));
		return PTR_ERR(mapping);
	}

	ret = arm_iommu_attach_device(dev, mapping);
	if (ret) {
		pr_warn("Failed to attached device %s to IOMMU_mapping\n",
				dev_name(dev));
		arm_iommu_release_mapping(mapping);
		return ret;
	}

	return 0;
}

#else

static inline bool exynos_is_iommu_available(struct device *dev)
{
	return false;
}

static inline int exynos_configure_iommu(struct device *dev,
					 unsigned int base, unsigned int size)
{
	return -ENOSYS;
}

static inline void exynos_unconfigure_iommu(struct device *dev) { }

#endif

#endif /* S5P_MFC_IOMMU_H_ */