linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update
@ 2011-03-04  9:01 Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC Marek Szyprowski
                   ` (7 more replies)
  0 siblings, 8 replies; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This patch series introduces new type of videbuf2 memory allocator -
vb2-s5p-iommu. This allocator can be used only on Samsung SoCs that have
IOMMU module. Currently only Samsung EXYNOS4 (former S5PV310) platform
has SYSMMU modules. The allocator is then used by s5p-fimc driver. To
make it possible some additional changes are required. Mainly platform
support for s5p-fimc for EXYNOS4 machines need to be defined. The
proposed solution has been tested on Universal C210 board (Samsung
S5PC210/EXYNOS4 based).

We decided to use driver private address space mode of the iommu driver.
This way each vb2-s5p-iommu client gets it's own address space for
memory buffers. This reduces kernel virtual memory fragmentation as well
as solves some non-trivial page table updates issues. The drawback is
the fact that the interface for s5p-sysmmu has been changed.

This IOMMU allocator has no dependences on other subsystems besides
Samsung platfrom core. We also ported s5p-mfc and s5p-tv drivers to this
allocator, they will be posted in separate patch series. This will
enable to get them working on EXYNOS4 (S5PV310) platform. Support for
S5PV210/S5PC110 platform still depends on CMA allocator that needs more
discussion on memory management mailing list and development. The
patches with updated s5p-mfc and s5p-tv drivers will follow.

To get FIMC module working on EXYNOS4/UniversalC210 board we also added
support for power domains and power gating.

This patch series contains a collection of patches for various platform
subsystems. Here is a detailed list:

[PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC
- adds basic platform resources for FIMC modules (for s5p-fimc driver)

[PATCH 2/7] ARM: S5PV310: power domains: fixes and code cleanup
- adds support for block gating in Samsung power domain driver and
  performs some cleanup

[PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
- a complete rewrite of sysmmu driver for Samsung platform:
- the new version introduces device private page tables (address space)
  mode
- simplified the resource management (no more horrible single platform
  device with 32 resources is needed)
- some other API chages required by upcoming videobuf2 allocator

[PATCH 4/7] v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator
- introduces new memory allocator for videobuf2, it uses s5p-sysmmu
  iommu driver, memory for video buffers is acuired by alloc_page() kernel
  function

[PATCH 5/7] s5p-fimc: add pm_runtime support
- adds support for pm_runtime in s5p-fimc driver

[PATCH 6/7] s5p-fimc: Add support for vb2-s5p-iommu allocator
- adds support for the newly introduces videbuf2-s5p-iommu allocator
  on EXYNOS4 platform

[PATCH 7/7] ARM: S5PC210: enable FIMC on Universal_C210
- adds all required machine definitions to get FIMC modules working
  on Universal C210 boards


The patch series is based on git://linuxtv.org/media_tree.git tree,
staging/for_v2.6.39 branch with the following Samsung platform patches:
1. [PATCH] ARM: Samsung: change suspend/resume code to depend on CONFIG_SUSPEND
http://www.mail-archive.com/linux-samsung-soc at vger.kernel.org/msg04025.html
2. [PATCH v2] ARM: S5PC210: add support for i2c PMICs on Universal_C210 board
http://www.mail-archive.com/linux-samsung-soc at vger.kernel.org/msg04029.html

This series has not been rebased onto the latest changes (S5PV310
renamed to EXYNOS4) in
git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git,
for-next branch. We will rebase them soon, but first we want to get
feedback and comments on the s5p-iommu videobuf2 allocator idea.

Best regards
-- 
Marek Szyprowski
Samsung Poland R&D Center


Complete patch summary:

Andrzej Pietrasiewicz (2):
  ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator

Marek Szyprowski (3):
  s5p-fimc: add pm_runtime support
  s5p-fimc: Add support for vb2-s5p-iommu allocator
  ARM: S5PC210: enable FIMC on Universal_C210

Sylwester Nawrocki (1):
  ARM: S5PV310: Add platform definitions for FIMC

Tomasz Stanislawski (1):
  ARM: S5PV310: power domains: fixes and code cleanup

 arch/arm/mach-s5pv310/Kconfig                    |    6 +
 arch/arm/mach-s5pv310/clock.c                    |   91 ++
 arch/arm/mach-s5pv310/cpu.c                      |    7 +
 arch/arm/mach-s5pv310/dev-pd.c                   |   93 ++-
 arch/arm/mach-s5pv310/dev-sysmmu.c               |  582 +++++++++----
 arch/arm/mach-s5pv310/include/mach/irqs.h        |   40 +-
 arch/arm/mach-s5pv310/include/mach/map.h         |    8 +
 arch/arm/mach-s5pv310/include/mach/regs-clock.h  |   12 +
 arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h |   23 +-
 arch/arm/mach-s5pv310/include/mach/sysmmu.h      |  122 ---
 arch/arm/mach-s5pv310/mach-universal_c210.c      |   20 +
 arch/arm/plat-s5p/Kconfig                        |   22 +-
 arch/arm/plat-s5p/Makefile                       |    1 +
 arch/arm/plat-s5p/dev-fimc3.c                    |   43 +
 arch/arm/plat-s5p/include/plat/sysmmu.h          |  127 +++
 arch/arm/plat-s5p/sysmmu.c                       |  988 +++++++++++++++-------
 arch/arm/plat-samsung/include/plat/devs.h        |    3 +-
 arch/arm/plat-samsung/include/plat/fimc-core.h   |    5 +
 arch/arm/plat-samsung/include/plat/pd.h          |    1 +
 drivers/media/video/Kconfig                      |   11 +-
 drivers/media/video/Makefile                     |    1 +
 drivers/media/video/s5p-fimc/fimc-capture.c      |    9 +-
 drivers/media/video/s5p-fimc/fimc-core.c         |   36 +-
 drivers/media/video/s5p-fimc/fimc-mem.h          |   87 ++
 drivers/media/video/videobuf2-s5p-iommu.c        |  444 ++++++++++
 include/media/videobuf2-s5p-iommu.h              |   50 ++
 26 files changed, 2129 insertions(+), 703 deletions(-)
 rewrite arch/arm/mach-s5pv310/dev-sysmmu.c (86%)
 delete mode 100644 arch/arm/mach-s5pv310/include/mach/sysmmu.h
 create mode 100644 arch/arm/plat-s5p/dev-fimc3.c
 create mode 100644 arch/arm/plat-s5p/include/plat/sysmmu.h
 rewrite arch/arm/plat-s5p/sysmmu.c (85%)
 create mode 100644 drivers/media/video/s5p-fimc/fimc-mem.h
 create mode 100644 drivers/media/video/videobuf2-s5p-iommu.c
 create mode 100644 include/media/videobuf2-s5p-iommu.h

-- 
1.7.1.569.g6f426

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-12  0:27   ` Kukjin Kim
  2011-03-04  9:01 ` [PATCH 2/7] ARM: S5PV310: power domains: fixes and code cleanup Marek Szyprowski
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sylwester Nawrocki <s.nawrocki@samsung.com>

Add support for fourth FIMC platform device definition and define
resources for FIMC modules on S5PV310 machines.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/mach-s5pv310/cpu.c                    |    7 ++++
 arch/arm/mach-s5pv310/include/mach/irqs.h      |    4 ++
 arch/arm/mach-s5pv310/include/mach/map.h       |    8 ++++
 arch/arm/plat-s5p/Kconfig                      |    5 +++
 arch/arm/plat-s5p/Makefile                     |    1 +
 arch/arm/plat-s5p/dev-fimc3.c                  |   43 ++++++++++++++++++++++++
 arch/arm/plat-samsung/include/plat/devs.h      |    1 +
 arch/arm/plat-samsung/include/plat/fimc-core.h |    5 +++
 8 files changed, 74 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s5p/dev-fimc3.c

diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c
index 0db0fb6..0bdb0b0 100644
--- a/arch/arm/mach-s5pv310/cpu.c
+++ b/arch/arm/mach-s5pv310/cpu.c
@@ -21,6 +21,8 @@
 #include <plat/clock.h>
 #include <plat/s5pv310.h>
 #include <plat/sdhci.h>
+#include <plat/devs.h>
+#include <plat/fimc-core.h>
 
 #include <mach/regs-irq.h>
 
@@ -114,6 +116,11 @@ void __init s5pv310_map_io(void)
 	s5pv310_default_sdhci1();
 	s5pv310_default_sdhci2();
 	s5pv310_default_sdhci3();
+
+	s3c_fimc_setname(0, "s5pv310-fimc");
+	s3c_fimc_setname(1, "s5pv310-fimc");
+	s3c_fimc_setname(2, "s5pv310-fimc");
+	s3c_fimc_setname(3, "s5pv310-fimc");
 }
 
 void __init s5pv310_init_clocks(int xtal)
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h
index 536b0b5..0e99968 100644
--- a/arch/arm/mach-s5pv310/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv310/include/mach/irqs.h
@@ -107,6 +107,10 @@
 
 #define IRQ_MIPI_CSIS0		COMBINER_IRQ(30, 0)
 #define IRQ_MIPI_CSIS1		COMBINER_IRQ(30, 1)
+#define IRQ_FIMC0		COMBINER_IRQ(32, 0)
+#define IRQ_FIMC1		COMBINER_IRQ(32, 1)
+#define IRQ_FIMC2		COMBINER_IRQ(33, 0)
+#define IRQ_FIMC3		COMBINER_IRQ(33, 1)
 
 #define IRQ_ONENAND_AUDI	COMBINER_IRQ(34, 0)
 
diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h
index 901657f..0db3a47 100644
--- a/arch/arm/mach-s5pv310/include/mach/map.h
+++ b/arch/arm/mach-s5pv310/include/mach/map.h
@@ -25,6 +25,10 @@
 
 #define S5PV310_PA_SYSRAM		0x02025000
 
+#define S5PV310_PA_FIMC0		0x11800000
+#define S5PV310_PA_FIMC1		0x11810000
+#define S5PV310_PA_FIMC2		0x11820000
+#define S5PV310_PA_FIMC3		0x11830000
 #define S5PV310_PA_I2S0			0x03830000
 #define S5PV310_PA_I2S1			0xE3100000
 #define S5PV310_PA_I2S2			0xE2A00000
@@ -121,6 +125,10 @@
 #define S5P_PA_CHIPID			S5PV310_PA_CHIPID
 #define S5P_PA_MIPI_CSIS0		S5PV310_PA_MIPI_CSIS0
 #define S5P_PA_MIPI_CSIS1		S5PV310_PA_MIPI_CSIS1
+#define S5P_PA_FIMC0			S5PV310_PA_FIMC0
+#define S5P_PA_FIMC1			S5PV310_PA_FIMC1
+#define S5P_PA_FIMC2			S5PV310_PA_FIMC2
+#define S5P_PA_FIMC3			S5PV310_PA_FIMC3
 #define S5P_PA_ONENAND			S5PC210_PA_ONENAND
 #define S5P_PA_ONENAND_DMA		S5PC210_PA_ONENAND_DMA
 #define S5P_PA_SDRAM			S5PV310_PA_SDRAM
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 557f8c5..0db2a7a 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -60,6 +60,11 @@ config S5P_DEV_FIMC2
 	help
 	  Compile in platform device definitions for FIMC controller 2
 
+config S5P_DEV_FIMC3
+	bool
+	help
+	  Compile in platform device definitions for FIMC controller 3
+	  
 config S5P_DEV_ONENAND
 	bool
 	help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index ce5a0a7..cfcd1db 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_SUSPEND)		+= irq-pm.o
 obj-$(CONFIG_S5P_DEV_FIMC0)	+= dev-fimc0.o
 obj-$(CONFIG_S5P_DEV_FIMC1)	+= dev-fimc1.o
 obj-$(CONFIG_S5P_DEV_FIMC2)	+= dev-fimc2.o
+obj-$(CONFIG_S5P_DEV_FIMC3)	+= dev-fimc3.o
 obj-$(CONFIG_S5P_DEV_ONENAND)	+= dev-onenand.o
 obj-$(CONFIG_S5P_DEV_CSIS0)	+= dev-csis0.o
 obj-$(CONFIG_S5P_DEV_CSIS1)	+= dev-csis1.o
diff --git a/arch/arm/plat-s5p/dev-fimc3.c b/arch/arm/plat-s5p/dev-fimc3.c
new file mode 100644
index 0000000..ef31bec
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-fimc3.c
@@ -0,0 +1,43 @@
+/* linux/arch/arm/plat-s5p/dev-fimc3.c
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * Base S5P FIMC3 resource and device definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <mach/map.h>
+
+static struct resource s5p_fimc3_resource[] = {
+	[0] = {
+		.start	= S5P_PA_FIMC3,
+		.end	= S5P_PA_FIMC3 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_FIMC3,
+		.end	= IRQ_FIMC3,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 s5p_fimc3_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device s5p_device_fimc3 = {
+	.name		= "s5p-fimc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(s5p_fimc3_resource),
+	.resource	= s5p_fimc3_resource,
+	.dev		= {
+		.dma_mask		= &s5p_fimc3_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index b4d208b..b0123f3 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -133,6 +133,7 @@ extern struct platform_device samsung_device_keypad;
 extern struct platform_device s5p_device_fimc0;
 extern struct platform_device s5p_device_fimc1;
 extern struct platform_device s5p_device_fimc2;
+extern struct platform_device s5p_device_fimc3;
 
 extern struct platform_device s5p_device_mipi_csis0;
 extern struct platform_device s5p_device_mipi_csis1;
diff --git a/arch/arm/plat-samsung/include/plat/fimc-core.h b/arch/arm/plat-samsung/include/plat/fimc-core.h
index 81a3bfe..945a99d 100644
--- a/arch/arm/plat-samsung/include/plat/fimc-core.h
+++ b/arch/arm/plat-samsung/include/plat/fimc-core.h
@@ -38,6 +38,11 @@ static inline void s3c_fimc_setname(int id, char *name)
 		s5p_device_fimc2.name = name;
 		break;
 #endif
+#ifdef CONFIG_S5P_DEV_FIMC3
+	case 3:
+		s5p_device_fimc3.name = name;
+		break;
+#endif
 	}
 }
 
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 2/7] ARM: S5PV310: power domains: fixes and code cleanup
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver Marek Szyprowski
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tomasz Stanislawski <t.stanislaws@samsung.com>

This patch extends power domain driver with support for enabling and
disabling modules in S5P_CLKGATE_BLOCK register. It also performs a
little code cleanup to avoid confusion between s5pv310_device_pd array
index and power domain id.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/mach-s5pv310/dev-pd.c                  |   93 +++++++++++++++++------
 arch/arm/mach-s5pv310/include/mach/regs-clock.h |    9 ++
 arch/arm/plat-samsung/include/plat/pd.h         |    1 +
 3 files changed, 81 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-s5pv310/dev-pd.c b/arch/arm/mach-s5pv310/dev-pd.c
index 58a50c2..e051998 100644
--- a/arch/arm/mach-s5pv310/dev-pd.c
+++ b/arch/arm/mach-s5pv310/dev-pd.c
@@ -16,13 +16,17 @@
 #include <linux/delay.h>
 
 #include <mach/regs-pmu.h>
+#include <mach/regs-clock.h>
 
 #include <plat/pd.h>
 
+static spinlock_t gate_block_slock = SPIN_LOCK_UNLOCKED;
+
 static int s5pv310_pd_enable(struct device *dev)
 {
 	struct samsung_pd_info *pdata =  dev->platform_data;
 	u32 timeout;
+	int ret = 0;
 
 	__raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base);
 
@@ -31,21 +35,39 @@ static int s5pv310_pd_enable(struct device *dev)
 	while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN)
 		!= S5P_INT_LOCAL_PWR_EN) {
 		if (timeout == 0) {
-			printk(KERN_ERR "Power domain %s enable failed.\n",
-				dev_name(dev));
-			return -ETIMEDOUT;
+			dev_err(dev, "enable failed\n");
+			ret = -ETIMEDOUT;
+			goto done;
 		}
 		timeout--;
 		udelay(100);
 	}
 
-	return 0;
+	/* configure clk gate mask if it is present */
+	if (pdata->gate_mask) {
+		unsigned long flags;
+		unsigned long value;
+
+		spin_lock_irqsave(&gate_block_slock, flags);
+
+		value  = __raw_readl(S5P_CLKGATE_BLOCK);
+		value |= pdata->gate_mask;
+		__raw_writel(value, S5P_CLKGATE_BLOCK);
+
+		spin_unlock_irqrestore(&gate_block_slock, flags);
+	}
+
+done:
+	dev_info(dev, "enable finished\n");
+
+	return ret;
 }
 
 static int s5pv310_pd_disable(struct device *dev)
 {
 	struct samsung_pd_info *pdata =  dev->platform_data;
 	u32 timeout;
+	int ret = 0;
 
 	__raw_writel(0, pdata->base);
 
@@ -53,81 +75,108 @@ static int s5pv310_pd_disable(struct device *dev)
 	timeout = 10;
 	while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) {
 		if (timeout == 0) {
-			printk(KERN_ERR "Power domain %s disable failed.\n",
-				dev_name(dev));
-			return -ETIMEDOUT;
+			dev_err(dev, "disable failed\n");
+			ret = -ETIMEDOUT;
+			goto done;
 		}
 		timeout--;
 		udelay(100);
 	}
 
-	return 0;
+	if (pdata->gate_mask) {
+		unsigned long flags;
+		unsigned long value;
+
+		spin_lock_irqsave(&gate_block_slock, flags);
+
+		value  = __raw_readl(S5P_CLKGATE_BLOCK);
+		value &= ~pdata->gate_mask;
+		__raw_writel(value, S5P_CLKGATE_BLOCK);
+
+		spin_unlock_irqrestore(&gate_block_slock, flags);
+	}
+done:
+	dev_info(dev, "disable finished\n");
+
+	return ret;
 }
 
 struct platform_device s5pv310_device_pd[] = {
-	{
+	[PD_MFC] = {
 		.name		= "samsung-pd",
-		.id		= 0,
+		.id		= PD_MFC,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
 				.disable	= s5pv310_pd_disable,
 				.base		= S5P_PMU_MFC_CONF,
+				.gate_mask	= S5P_CLKGATE_BLOCK_MFC,
 			},
 		},
-	}, {
+	},
+	[PD_G3D] = {
 		.name		= "samsung-pd",
-		.id		= 1,
+		.id		= PD_G3D,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
 				.disable	= s5pv310_pd_disable,
 				.base		= S5P_PMU_G3D_CONF,
+				.gate_mask	= S5P_CLKGATE_BLOCK_G3D,
 			},
 		},
-	}, {
+	},
+	[PD_LCD0] = {
 		.name		= "samsung-pd",
-		.id		= 2,
+		.id		= PD_LCD0,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
 				.disable	= s5pv310_pd_disable,
 				.base		= S5P_PMU_LCD0_CONF,
+				.gate_mask	= S5P_CLKGATE_BLOCK_LCD0,
 			},
 		},
-	}, {
+	},
+	[PD_LCD1] = {
 		.name		= "samsung-pd",
-		.id		= 3,
+		.id		= PD_LCD1,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
 				.disable	= s5pv310_pd_disable,
 				.base		= S5P_PMU_LCD1_CONF,
+				.gate_mask	= S5P_CLKGATE_BLOCK_LCD1,
 			},
 		},
-	}, {
+	},
+	[PD_TV] = {
 		.name		= "samsung-pd",
-		.id		= 4,
+		.id		= PD_TV,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
 				.disable	= s5pv310_pd_disable,
 				.base		= S5P_PMU_TV_CONF,
+				.gate_mask	= S5P_CLKGATE_BLOCK_TV,
 			},
 		},
-	}, {
+	},
+	[PD_CAM] = {
 		.name		= "samsung-pd",
-		.id		= 5,
+		.id		= PD_CAM,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
 				.disable	= s5pv310_pd_disable,
 				.base		= S5P_PMU_CAM_CONF,
+				.gate_mask	= S5P_CLKGATE_BLOCK_CAM,
 			},
 		},
-	}, {
+	},
+	[PD_GPS] = {
 		.name		= "samsung-pd",
-		.id		= 6,
+		.id		= PD_GPS,
 		.dev = {
 			.platform_data = &(struct samsung_pd_info) {
 				.enable		= s5pv310_pd_enable,
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
index b5c4ada..341571a 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
@@ -73,6 +73,7 @@
 #define S5P_CLKGATE_IP_FSYS		S5P_CLKREG(0x0C940)
 #define S5P_CLKGATE_IP_PERIL		S5P_CLKREG(0x0C950)
 #define S5P_CLKGATE_IP_PERIR		S5P_CLKREG(0x0C960)
+#define S5P_CLKGATE_BLOCK		S5P_CLKREG(0x0C970)
 
 #define S5P_CLKSRC_DMC			S5P_CLKREG(0x10200)
 #define S5P_CLKDIV_DMC0			S5P_CLKREG(0x10500)
@@ -160,6 +161,14 @@
 #define S5P_CLKDIV_BUS_GPLR_SHIFT	(4)
 #define S5P_CLKDIV_BUS_GPLR_MASK	(0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT)
 
+/* CLKGATE_BLOCK */
+#define S5P_CLKGATE_BLOCK_CAM		(1 << 0)
+#define S5P_CLKGATE_BLOCK_TV		(1 << 1)
+#define S5P_CLKGATE_BLOCK_MFC		(1 << 2)
+#define S5P_CLKGATE_BLOCK_G3D		(1 << 3)
+#define S5P_CLKGATE_BLOCK_LCD0		(1 << 4)
+#define S5P_CLKGATE_BLOCK_LCD1		(1 << 5)
+
 /* Compatibility defines */
 
 #define S5P_EPLL_CON			S5P_EPLL_CON0
diff --git a/arch/arm/plat-samsung/include/plat/pd.h b/arch/arm/plat-samsung/include/plat/pd.h
index 5f0ad85..36ba851 100644
--- a/arch/arm/plat-samsung/include/plat/pd.h
+++ b/arch/arm/plat-samsung/include/plat/pd.h
@@ -15,6 +15,7 @@ struct samsung_pd_info {
 	int (*enable)(struct device *dev);
 	int (*disable)(struct device *dev);
 	void __iomem *base;
+	unsigned long gate_mask;
 };
 
 enum s5pv310_pd_block {
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 2/7] ARM: S5PV310: power domains: fixes and code cleanup Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-04 16:04   ` Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 4/7] v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator Marek Szyprowski
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>

This patch performs a complete rewrite of sysmmu driver for Samsung platform:
- the new version introduces an api to construct device private page
  tables and enables to use device private address space mode
- simplified the resource management: no more single platform
  device with 32 resources is needed, better fits into linux driver model,
  each sysmmu instance has it's own resource definition
- added support for sysmmu clocks
- some other minor API chages required by upcoming videobuf2 allocator

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/mach-s5pv310/clock.c                    |   91 ++
 arch/arm/mach-s5pv310/dev-sysmmu.c               |  582 +++++++++----
 arch/arm/mach-s5pv310/include/mach/irqs.h        |   36 +-
 arch/arm/mach-s5pv310/include/mach/regs-clock.h  |    3 +
 arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h |   23 +-
 arch/arm/mach-s5pv310/include/mach/sysmmu.h      |  122 ---
 arch/arm/plat-s5p/Kconfig                        |   17 +-
 arch/arm/plat-s5p/include/plat/sysmmu.h          |  127 +++
 arch/arm/plat-s5p/sysmmu.c                       |  988 +++++++++++++++-------
 arch/arm/plat-samsung/include/plat/devs.h        |    2 +-
 10 files changed, 1323 insertions(+), 668 deletions(-)
 rewrite arch/arm/mach-s5pv310/dev-sysmmu.c (86%)
 delete mode 100644 arch/arm/mach-s5pv310/include/mach/sysmmu.h
 create mode 100644 arch/arm/plat-s5p/include/plat/sysmmu.h
 rewrite arch/arm/plat-s5p/sysmmu.c (85%)

diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c
index fc7c2f8..f142b8c 100644
--- a/arch/arm/mach-s5pv310/clock.c
+++ b/arch/arm/mach-s5pv310/clock.c
@@ -20,6 +20,7 @@
 #include <plat/pll.h>
 #include <plat/s5p-clock.h>
 #include <plat/clock-clksrc.h>
+#include <plat/sysmmu.h>
 
 #include <mach/map.h>
 #include <mach/regs-clock.h>
@@ -116,6 +117,21 @@ static int s5pv310_clk_ip_perir_ctrl(struct clk *clk, int enable)
 	return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable);
 }
 
+static int s5pv310_clk_ip_dmc_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_DMC, clk, enable);
+}
+
+static int s5pv310_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int s5pv310_clk_ip_tv_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_TV, clk, enable);
+}
+
 /* Core list of CMU_CPU side */
 
 static struct clksrc_clk clk_mout_apll = {
@@ -422,6 +438,81 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5pv310_clk_ip_cam_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
+		.name           = "sysmmu",
+		.id             = S5P_SYSMMU_MFC_L,
+		.enable         = s5pv310_clk_ip_mfc_ctrl,
+		.ctrlbit        = ((15 << 1) | 1),
+	}, {
+		.name           = "sysmmu",
+		.id             = S5P_SYSMMU_MFC_R,
+		.enable         = s5pv310_clk_ip_mfc_ctrl,
+		.ctrlbit        = ((15 << 1) | 1),
+	}, {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC0,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC1,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 8),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC2,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 9),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC3,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 10),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_JPEG,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 11),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_TV,
+		.enable		= s5pv310_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_G2D,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 3),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_ROTATOR,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_MDMA,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 5),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMD0,
+		.enable		= s5pv310_clk_ip_lcd0_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMD1,
+		.enable		= s5pv310_clk_ip_lcd1_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_PCIe,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 18),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_SSS,
+		.enable		= s5pv310_clk_ip_dmc_ctrl,
+		.ctrlbit	= (1 << 12),
+	} , {
 		.name		= "fimd",
 		.id		= 0,
 		.enable		= s5pv310_clk_ip_lcd0_ctrl,
diff --git a/arch/arm/mach-s5pv310/dev-sysmmu.c b/arch/arm/mach-s5pv310/dev-sysmmu.c
dissimilarity index 86%
index e1bb200..73c1541 100644
--- a/arch/arm/mach-s5pv310/dev-sysmmu.c
+++ b/arch/arm/mach-s5pv310/dev-sysmmu.c
@@ -1,187 +1,395 @@
-/* linux/arch/arm/mach-s5pv310/dev-sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-
-#include <mach/map.h>
-#include <mach/irqs.h>
-
-static struct resource s5pv310_sysmmu_resource[] = {
-	[0] = {
-		.start	= S5PV310_PA_SYSMMU_MDMA,
-		.end	= S5PV310_PA_SYSMMU_MDMA + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_SYSMMU_MDMA0_0,
-		.end	= IRQ_SYSMMU_MDMA0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[2] = {
-		.start	= S5PV310_PA_SYSMMU_SSS,
-		.end	= S5PV310_PA_SYSMMU_SSS + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[3] = {
-		.start	= IRQ_SYSMMU_SSS_0,
-		.end	= IRQ_SYSMMU_SSS_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[4] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC0,
-		.end	= S5PV310_PA_SYSMMU_FIMC0 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[5] = {
-		.start	= IRQ_SYSMMU_FIMC0_0,
-		.end	= IRQ_SYSMMU_FIMC0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[6] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC1,
-		.end	= S5PV310_PA_SYSMMU_FIMC1 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[7] = {
-		.start	= IRQ_SYSMMU_FIMC1_0,
-		.end	= IRQ_SYSMMU_FIMC1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[8] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC2,
-		.end	= S5PV310_PA_SYSMMU_FIMC2 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[9] = {
-		.start	= IRQ_SYSMMU_FIMC2_0,
-		.end	= IRQ_SYSMMU_FIMC2_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[10] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC3,
-		.end	= S5PV310_PA_SYSMMU_FIMC3 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[11] = {
-		.start	= IRQ_SYSMMU_FIMC3_0,
-		.end	= IRQ_SYSMMU_FIMC3_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[12] = {
-		.start	= S5PV310_PA_SYSMMU_JPEG,
-		.end	= S5PV310_PA_SYSMMU_JPEG + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[13] = {
-		.start	= IRQ_SYSMMU_JPEG_0,
-		.end	= IRQ_SYSMMU_JPEG_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[14] = {
-		.start	= S5PV310_PA_SYSMMU_FIMD0,
-		.end	= S5PV310_PA_SYSMMU_FIMD0 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[15] = {
-		.start	= IRQ_SYSMMU_LCD0_M0_0,
-		.end	= IRQ_SYSMMU_LCD0_M0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[16] = {
-		.start	= S5PV310_PA_SYSMMU_FIMD1,
-		.end	= S5PV310_PA_SYSMMU_FIMD1 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[17] = {
-		.start	= IRQ_SYSMMU_LCD1_M1_0,
-		.end	= IRQ_SYSMMU_LCD1_M1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[18] = {
-		.start	= S5PV310_PA_SYSMMU_PCIe,
-		.end	= S5PV310_PA_SYSMMU_PCIe + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[19] = {
-		.start	= IRQ_SYSMMU_PCIE_0,
-		.end	= IRQ_SYSMMU_PCIE_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[20] = {
-		.start	= S5PV310_PA_SYSMMU_G2D,
-		.end	= S5PV310_PA_SYSMMU_G2D + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[21] = {
-		.start	= IRQ_SYSMMU_2D_0,
-		.end	= IRQ_SYSMMU_2D_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[22] = {
-		.start	= S5PV310_PA_SYSMMU_ROTATOR,
-		.end	= S5PV310_PA_SYSMMU_ROTATOR + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[23] = {
-		.start	= IRQ_SYSMMU_ROTATOR_0,
-		.end	= IRQ_SYSMMU_ROTATOR_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[24] = {
-		.start	= S5PV310_PA_SYSMMU_MDMA2,
-		.end	= S5PV310_PA_SYSMMU_MDMA2 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[25] = {
-		.start	= IRQ_SYSMMU_MDMA1_0,
-		.end	= IRQ_SYSMMU_MDMA1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[26] = {
-		.start	= S5PV310_PA_SYSMMU_TV,
-		.end	= S5PV310_PA_SYSMMU_TV + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[27] = {
-		.start	= IRQ_SYSMMU_TV_M0_0,
-		.end	= IRQ_SYSMMU_TV_M0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[28] = {
-		.start	= S5PV310_PA_SYSMMU_MFC_L,
-		.end	= S5PV310_PA_SYSMMU_MFC_L + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[29] = {
-		.start	= IRQ_SYSMMU_MFC_M0_0,
-		.end	= IRQ_SYSMMU_MFC_M0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[30] = {
-		.start	= S5PV310_PA_SYSMMU_MFC_R,
-		.end	= S5PV310_PA_SYSMMU_MFC_R + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[31] = {
-		.start	= IRQ_SYSMMU_MFC_M1_0,
-		.end	= IRQ_SYSMMU_MFC_M1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device s5pv310_device_sysmmu = {
-	.name		= "s5p-sysmmu",
-	.id		= 32,
-	.num_resources	= ARRAY_SIZE(s5pv310_sysmmu_resource),
-	.resource	= s5pv310_sysmmu_resource,
-};
-
-EXPORT_SYMBOL(s5pv310_device_sysmmu);
+/* linux/arch/arm/mach-s5pv310/dev-sysmmu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/sysmmu.h>
+
+static struct resource s5p_sysmmu_resource[][2] = {
+	[S5P_SYSMMU_MDMA] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MDMA,
+			.end	= S5PV310_PA_SYSMMU_MDMA + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MDMA0,
+			.end	= IRQ_SYSMMU_MDMA0,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_SSS] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_SSS,
+			.end	= S5PV310_PA_SYSMMU_SSS + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_SSS,
+			.end	= IRQ_SYSMMU_SSS,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC0] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC0,
+			.end   = S5PV310_PA_SYSMMU_FIMC0 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC0,
+			.end   = IRQ_SYSMMU_FIMC0,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC1] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC1,
+			.end   = S5PV310_PA_SYSMMU_FIMC1 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC1,
+			.end   = IRQ_SYSMMU_FIMC1,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC2] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC2,
+			.end   = S5PV310_PA_SYSMMU_FIMC2 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC2,
+			.end   = IRQ_SYSMMU_FIMC2,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC3] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC3,
+			.end   = S5PV310_PA_SYSMMU_FIMC3 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC3,
+			.end   = IRQ_SYSMMU_FIMC3,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_JPEG] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_JPEG,
+			.end	= S5PV310_PA_SYSMMU_JPEG + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_JPEG,
+			.end	= IRQ_SYSMMU_JPEG,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMD0] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_FIMD0,
+			.end	= S5PV310_PA_SYSMMU_FIMD0 + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_FIMD0,
+			.end	= IRQ_SYSMMU_FIMD0,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMD1] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_FIMD1,
+			.end	= S5PV310_PA_SYSMMU_FIMD1 + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_FIMD1,
+			.end	= IRQ_SYSMMU_FIMD1,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_PCIe] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_PCIe,
+			.end	= S5PV310_PA_SYSMMU_PCIe + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_PCIE,
+			.end	= IRQ_SYSMMU_PCIE,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_G2D] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_G2D,
+			.end	= S5PV310_PA_SYSMMU_G2D + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_2D,
+			.end	= IRQ_SYSMMU_2D,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_ROTATOR] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_ROTATOR,
+			.end	= S5PV310_PA_SYSMMU_ROTATOR + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_ROTATOR,
+			.end	= IRQ_SYSMMU_ROTATOR,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_MDMA2] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MDMA2,
+			.end	= S5PV310_PA_SYSMMU_MDMA2 + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MDMA1,
+			.end	= IRQ_SYSMMU_MDMA1,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_TV] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_TV,
+			.end	= S5PV310_PA_SYSMMU_TV + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_TV,
+			.end	= IRQ_SYSMMU_TV,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_MFC_L] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MFC_L,
+			.end	= S5PV310_PA_SYSMMU_MFC_L + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MFC_L,
+			.end	= IRQ_SYSMMU_MFC_L,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_MFC_R] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MFC_R,
+			.end	= S5PV310_PA_SYSMMU_MFC_R + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MFC_R,
+			.end	= IRQ_SYSMMU_MFC_R,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+};
+
+static u64 s5p_sysmmu_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv310_device_sysmmu[] = {
+	[S5P_SYSMMU_MDMA] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MDMA,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MDMA]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MDMA],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_SSS] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_SSS,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_SSS]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_SSS],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC0] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC0,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC0]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC0],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC1] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC1,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC1]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC1],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC2] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC2,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC2]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC2],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC3] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC3,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC3]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC3],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_JPEG] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_JPEG,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_JPEG]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_JPEG],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMD0] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMD0,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMD0]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMD0],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMD1] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMD1,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMD1]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMD1],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_PCIe] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_PCIe,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_PCIe]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_PCIe],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_G2D] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_G2D,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_G2D]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_G2D],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_ROTATOR] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_ROTATOR,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_ROTATOR]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_ROTATOR],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_MDMA2] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MDMA2,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MDMA2]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MDMA2],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_TV] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_TV,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_TV]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_TV],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_MFC_L] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MFC_L,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MFC_L]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MFC_L],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_MFC_R] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MFC_R,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MFC_R]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MFC_R],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+};
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h
index 0e99968..f6b99c6 100644
--- a/arch/arm/mach-s5pv310/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv310/include/mach/irqs.h
@@ -55,23 +55,24 @@
 #define COMBINER_GROUP(x)	((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
 #define COMBINER_IRQ(x, y)	(COMBINER_GROUP(x) + y)
 
-#define IRQ_SYSMMU_MDMA0_0	COMBINER_IRQ(4, 0)
-#define IRQ_SYSMMU_SSS_0	COMBINER_IRQ(4, 1)
-#define IRQ_SYSMMU_FIMC0_0	COMBINER_IRQ(4, 2)
-#define IRQ_SYSMMU_FIMC1_0	COMBINER_IRQ(4, 3)
-#define IRQ_SYSMMU_FIMC2_0	COMBINER_IRQ(4, 4)
-#define IRQ_SYSMMU_FIMC3_0	COMBINER_IRQ(4, 5)
-#define IRQ_SYSMMU_JPEG_0	COMBINER_IRQ(4, 6)
-#define IRQ_SYSMMU_2D_0		COMBINER_IRQ(4, 7)
-
-#define IRQ_SYSMMU_ROTATOR_0	COMBINER_IRQ(5, 0)
-#define IRQ_SYSMMU_MDMA1_0	COMBINER_IRQ(5, 1)
-#define IRQ_SYSMMU_LCD0_M0_0	COMBINER_IRQ(5, 2)
-#define IRQ_SYSMMU_LCD1_M1_0	COMBINER_IRQ(5, 3)
-#define IRQ_SYSMMU_TV_M0_0	COMBINER_IRQ(5, 4)
-#define IRQ_SYSMMU_MFC_M0_0	COMBINER_IRQ(5, 5)
-#define IRQ_SYSMMU_MFC_M1_0	COMBINER_IRQ(5, 6)
-#define IRQ_SYSMMU_PCIE_0	COMBINER_IRQ(5, 7)
+#define IRQ_SYSMMU_MDMA0	COMBINER_IRQ(4, 0)
+#define IRQ_SYSMMU_SSS		COMBINER_IRQ(4, 1)
+#define IRQ_SYSMMU_FIMC0	COMBINER_IRQ(4, 2)
+#define IRQ_SYSMMU_FIMC1	COMBINER_IRQ(4, 3)
+#define IRQ_SYSMMU_FIMC2	COMBINER_IRQ(4, 4)
+#define IRQ_SYSMMU_FIMC3	COMBINER_IRQ(4, 5)
+#define IRQ_SYSMMU_JPEG		COMBINER_IRQ(4, 6)
+#define IRQ_SYSMMU_2D		COMBINER_IRQ(4, 7)
+
+#define IRQ_SYSMMU_ROTATOR	COMBINER_IRQ(5, 0)
+#define IRQ_SYSMMU_MDMA1	COMBINER_IRQ(5, 1)
+#define IRQ_SYSMMU_FIMD0	COMBINER_IRQ(5, 2)
+#define IRQ_SYSMMU_FIMD1	COMBINER_IRQ(5, 3)
+#define IRQ_SYSMMU_TV		COMBINER_IRQ(5, 4)
+#define IRQ_SYSMMU_MFC_L	COMBINER_IRQ(5, 5)
+#define IRQ_SYSMMU_MFC_R	COMBINER_IRQ(5, 6)
+#define IRQ_SYSMMU_PCIE		COMBINER_IRQ(5, 7)
+
 
 #define IRQ_PDMA0		COMBINER_IRQ(21, 0)
 #define IRQ_PDMA1		COMBINER_IRQ(21, 1)
@@ -147,4 +148,5 @@
 
 #define NR_IRQS			(S5P_IRQ_EINT_BASE + 32)
 
+
 #endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
index 341571a..9ef5f0c 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
@@ -67,6 +67,8 @@
 #define S5P_CLKDIV_STAT_TOP		S5P_CLKREG(0x0C610)
 
 #define S5P_CLKGATE_IP_CAM		S5P_CLKREG(0x0C920)
+#define S5P_CLKGATE_IP_MFC		S5P_CLKREG(0x0C928)
+#define S5P_CLKGATE_IP_TV		S5P_CLKREG(0x0C924)
 #define S5P_CLKGATE_IP_IMAGE		S5P_CLKREG(0x0C930)
 #define S5P_CLKGATE_IP_LCD0		S5P_CLKREG(0x0C934)
 #define S5P_CLKGATE_IP_LCD1		S5P_CLKREG(0x0C938)
@@ -78,6 +80,7 @@
 #define S5P_CLKSRC_DMC			S5P_CLKREG(0x10200)
 #define S5P_CLKDIV_DMC0			S5P_CLKREG(0x10500)
 #define S5P_CLKDIV_STAT_DMC0		S5P_CLKREG(0x10600)
+#define S5P_CLKGATE_IP_DMC		S5P_CLKREG(0x10900)
 
 #define S5P_APLL_LOCK			S5P_CLKREG(0x14000)
 #define S5P_MPLL_LOCK			S5P_CLKREG(0x14004)
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h b/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
index 0b28e81..dd2a954 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
@@ -13,12 +13,21 @@
 #ifndef __ASM_ARCH_REGS_SYSMMU_H
 #define __ASM_ARCH_REGS_SYSMMU_H __FILE__
 
-#define S5P_MMU_CTRL			0x000
-#define S5P_MMU_CFG			0x004
-#define S5P_MMU_STATUS			0x008
-#define S5P_MMU_FLUSH			0x00C
-#define S5P_PT_BASE_ADDR		0x014
-#define S5P_INT_STATUS			0x018
-#define S5P_PAGE_FAULT_ADDR		0x024
+#define S5P_MMU_CTRL		(0x000)
+#define S5P_MMU_CFG		(0x004)
+#define S5P_MMU_STATUS		(0x008)
+#define S5P_MMU_FLUSH		(0x00C)
+#define S5P_MMU_FLUSH_ENTRY	(0x010)
+#define S5P_PT_BASE_ADDR	(0x014)
+#define S5P_INT_STATUS		(0x018)
+#define S5P_INT_CLEAR		(0x01C)
+#define S5P_INT_MASK		(0x020)
+#define S5P_PAGE_FAULT_ADDR	(0x024)
+#define S5P_AW_FAULT_ADDR	(0x028)
+#define S5P_AR_FAULT_ADDR	(0x02C)
+#define S5P_DEFAULT_SLAVE_ADDR	(0x030)
+#define S5P_MMU_VERSION		(0x034)
+#define S5P_TLB_READ            (0x038)
+#define S5P_TLB_DATA            (0x03C)
 
 #endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/sysmmu.h b/arch/arm/mach-s5pv310/include/mach/sysmmu.h
deleted file mode 100644
index 598fc5c..0000000
--- a/arch/arm/mach-s5pv310/include/mach/sysmmu.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/sysmmu.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * Samsung sysmmu driver for S5PV310
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARM_ARCH_SYSMMU_H
-#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
-
-#define S5PV310_SYSMMU_TOTAL_IPNUM	16
-#define S5P_SYSMMU_TOTAL_IPNUM		S5PV310_SYSMMU_TOTAL_IPNUM
-
-enum s5pv310_sysmmu_ips {
-	SYSMMU_MDMA,
-	SYSMMU_SSS,
-	SYSMMU_FIMC0,
-	SYSMMU_FIMC1,
-	SYSMMU_FIMC2,
-	SYSMMU_FIMC3,
-	SYSMMU_JPEG,
-	SYSMMU_FIMD0,
-	SYSMMU_FIMD1,
-	SYSMMU_PCIe,
-	SYSMMU_G2D,
-	SYSMMU_ROTATOR,
-	SYSMMU_MDMA2,
-	SYSMMU_TV,
-	SYSMMU_MFC_L,
-	SYSMMU_MFC_R,
-};
-
-static char *sysmmu_ips_name[S5PV310_SYSMMU_TOTAL_IPNUM] = {
-	"SYSMMU_MDMA"	,
-	"SYSMMU_SSS"	,
-	"SYSMMU_FIMC0"	,
-	"SYSMMU_FIMC1"	,
-	"SYSMMU_FIMC2"	,
-	"SYSMMU_FIMC3"	,
-	"SYSMMU_JPEG"	,
-	"SYSMMU_FIMD0"	,
-	"SYSMMU_FIMD1"	,
-	"SYSMMU_PCIe"	,
-	"SYSMMU_G2D"	,
-	"SYSMMU_ROTATOR",
-	"SYSMMU_MDMA2"	,
-	"SYSMMU_TV"	,
-	"SYSMMU_MFC_L"	,
-	"SYSMMU_MFC_R"	,
-};
-
-typedef enum s5pv310_sysmmu_ips sysmmu_ips;
-
-struct sysmmu_tt_info {
-	unsigned long *pgd;
-	unsigned long pgd_paddr;
-	unsigned long *pte;
-};
-
-struct sysmmu_controller {
-	const char		*name;
-
-	/* channels registers */
-	void __iomem		*regs;
-
-	/* channel irq */
-	unsigned int		irq;
-
-	sysmmu_ips		ips;
-
-	/* Translation Table Info. */
-	struct sysmmu_tt_info	*tt_info;
-
-	struct resource		*mem;
-	struct device		*dev;
-
-	/* SysMMU controller enable - true : enable */
-	bool			enable;
-};
-
-/**
- * s5p_sysmmu_enable() - enable system mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function enable system mmu to transfer address
- * from virtual address to physical address
- */
-int s5p_sysmmu_enable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_disable() - disable sysmmu mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function disable system mmu to transfer address
- * from virtual address to physical address
- */
-int s5p_sysmmu_disable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
- * @ips: The ip connected system mmu.
- * @pgd: The page table base address.
- *
- * This function set page table base address
- * When system mmu transfer address from virtaul address to physical address,
- * system mmu refer address information from page table
- */
-int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
- * @ips: The ip connected system mmu.
- *
- * This function flush all TLB entry in system mmu
- */
-int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
-#endif /* __ASM_ARM_ARCH_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 0db2a7a..4166964 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -37,14 +37,6 @@ config S5P_GPIO_INT
 	help
 	  Common code for the GPIO interrupts (other than external interrupts.)
 
-comment "System MMU"
-
-config S5P_SYSTEM_MMU
-	bool "S5P SYSTEM MMU"
-	depends on ARCH_S5PV310
-	help
-	  Say Y here if you want to enable System MMU
-
 config S5P_DEV_FIMC0
 	bool
 	help
@@ -79,3 +71,12 @@ config S5P_DEV_CSIS1
 	bool
 	help
 	  Compile in platform device definitions for MIPI-CSIS channel 1
+
+comment "System MMU"
+
+config S5P_SYSTEM_MMU
+	bool "S5P SYSTEM MMU"
+	depends on ARCH_S5PV310
+	help
+	  Say Y here if you want to enable System MMU
+
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
new file mode 100644
index 0000000..9051af4
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/sysmmu.h
@@ -0,0 +1,127 @@
+/*
+ * sysmmu.h
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@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.
+ */
+#ifndef __S5P_SYSMMU_H__
+#define __S5P_SYSMMU_H__
+
+struct device;
+
+/**
+ * enum s5p_sysmmu_cmd - sysmmu control commands
+ * @S5P_SYSMMU_ENABLE_SHARED:	enable sysmmu, share page tables with ARM CPU
+ * @S5P_SYSMMU_ENABLE_PRIVATE:	enable sysmmu, use private page tables
+ * @S5P_SYSMMU_DISABLE:		disable sysmmu
+ * @S5P_SYSMMU_TLB_INVALIDATE:	invalidate sysmmu TLB contents
+ */
+enum s5p_sysmmu_cmd {
+	S5P_SYSMMU_ENABLE_SHARED,
+	S5P_SYSMMU_ENABLE_PRIVATE,
+	S5P_SYSMMU_DISABLE,
+	S5P_SYSMMU_TLB_INVALIDATE,
+};
+
+/**
+ * enum s5p_sysmmu_ip - integrated peripherals identifiers
+ * @S5P_SYSMMU_MDMA:	MDMA
+ * @S5P_SYSMMU_SSS:	SSS
+ * @S5P_SYSMMU_FIMC0:	FIMC0
+ * @S5P_SYSMMU_FIMC1:	FIMC1
+ * @S5P_SYSMMU_FIMC2:	FIMC2
+ * @S5P_SYSMMU_FIMC3:	FIMC3
+ * @S5P_SYSMMU_JPEG:	JPEG
+ * @S5P_SYSMMU_FIMD0:	FIMD0
+ * @S5P_SYSMMU_FIMD1:	FIMD1
+ * @S5P_SYSMMU_PCIe:	PCIe
+ * @S5P_SYSMMU_G2D:	G2D
+ * @S5P_SYSMMU_ROTATOR:	ROTATOR
+ * @S5P_SYSMMU_MDMA2:	MDMA2
+ * @S5P_SYSMMU_TV:	TV
+ * @S5P_SYSMMU_MFC_L:	MFC_L
+ * @S5P_SYSMMU_MFC_R:	MFC_R
+ */
+enum s5p_sysmmu_ip {
+	S5P_SYSMMU_MDMA,
+	S5P_SYSMMU_SSS,
+	S5P_SYSMMU_FIMC0,
+	S5P_SYSMMU_FIMC1,
+	S5P_SYSMMU_FIMC2,
+	S5P_SYSMMU_FIMC3,
+	S5P_SYSMMU_JPEG,
+	S5P_SYSMMU_FIMD0,
+	S5P_SYSMMU_FIMD1,
+	S5P_SYSMMU_PCIe,
+	S5P_SYSMMU_G2D,
+	S5P_SYSMMU_ROTATOR,
+	S5P_SYSMMU_MDMA2,
+	S5P_SYSMMU_TV,
+	S5P_SYSMMU_MFC_L,
+	S5P_SYSMMU_MFC_R,
+};
+
+/**
+ * s5p_sysmmu_get() - get sysmmu handle for a device
+ * @dev:	device which needs to use its sysmmu
+ * @ip:		integrated peripheral identifier of the device
+ */
+void *s5p_sysmmu_get(struct device *dev, enum s5p_sysmmu_ip ip);
+
+/**
+ * s5p_sysmmu_put() - release sysmmu handle for a device
+ * @dev_id:	sysmmu handle obtained from s5p_sysmmu_get()
+ */
+void s5p_sysmmu_put(void *dev_id);
+
+/**
+ * s5p_sysmmu_control() - control a sysmmu
+ * @dev_id:	sysmmu handle obtained from s5p_sysmmu_get()
+ * @cmd:	command to perform
+ */
+int s5p_sysmmu_control(void *dev_id, enum s5p_sysmmu_cmd cmd);
+
+/**
+ * s5p_sysmmu_map_area() - map an area of device's virtual memory,
+ 			underlying memory is described by struct pages
+ * @dev_id:		sysmmu handle obtained from s5p_sysmmu_get()
+ * @varea_start:	beginning virtual address of the mapped area,
+ *			must be page aligned
+ * @num_pages:		number of pages to map starting from varea_start
+ * @pages:		an array of struct page pointers representing
+ *			the physical pages which will be mapped
+ */
+int s5p_sysmmu_map_area(void *dev_id, unsigned long varea_start,
+			unsigned long num_pages, struct page **pages);
+
+/**
+ * s5p_sysmmu_map_phys_area() - map an area of device's virtual memory,
+ *			underlying memory is a physically contiguous block
+ * @dev_id:		sysmmu handle obtained from s5p_sysmmu_get()
+ * @varea_start:	beginning virtual address of the mapped area,
+ *			must be page aligned
+ * @phys_area_start:	beginning physical adddress of the underlying memory
+ * @num_pages:		number of pages to map starting from phys_area_start
+ */
+int s5p_sysmmu_map_phys_area(void *dev_id, unsigned long varea_start,
+			     unsigned long phys_area_start,
+			     unsigned long num_pages);
+
+/**
+ * s5p_sysmmu_unmap_area() - unmap an area of device's virtual memory
+ * @dev_id:		sysmmu handle obtained from s5p_sysmmu_get()
+ * @varea_start:	beginning virtual address of the mapped area,
+ *			must be page aligned and correspond to the address
+ * 			used while mapping
+ * @num_pages:		number of pages to unmap starting from phys_area_start,
+ *			must correspond to the number used while mapping
+ */
+void s5p_sysmmu_unmap_area(void *dev_id, unsigned long varea_start,
+			   unsigned long num_pages);
+
+#endif /* __S5P_SYSMMU_H__ */
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
dissimilarity index 85%
index ffe8a48..45adbf4 100644
--- a/arch/arm/plat-s5p/sysmmu.c
+++ b/arch/arm/plat-s5p/sysmmu.c
@@ -1,326 +1,662 @@
-/* linux/arch/arm/plat-s5p/sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <mach/map.h>
-#include <mach/regs-sysmmu.h>
-#include <mach/sysmmu.h>
-
-struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
-
-void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
-{
-	unsigned int reg_mmu_ctrl;
-	unsigned int reg_mmu_status;
-	unsigned int reg_pt_base_addr;
-	unsigned int reg_int_status;
-	unsigned int reg_page_ft_addr;
-
-	reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
-	reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
-	reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
-	reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
-
-	printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
-	printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
-	printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
-	printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
-
-	switch (reg_int_status & 0xFF) {
-	case 0x1:
-		printk(KERN_INFO "%s: Page fault\n", __func__);
-		printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
-		break;
-	case 0x2:
-		printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
-		break;
-	case 0x4:
-		printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
-		break;
-	case 0x8:
-		printk(KERN_INFO "%s: Bus error\n", __func__);
-		break;
-	case 0x10:
-		printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
-		break;
-	case 0x20:
-		printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
-		break;
-	case 0x40:
-		printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
-		break;
-	case 0x80:
-		printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
-		break;
-	}
-}
-
-static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
-{
-	unsigned int i;
-	unsigned int reg_int_status;
-	struct sysmmu_controller *sysmmuconp;
-
-	for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
-		sysmmuconp = &s5p_sysmmu_cntlrs[i];
-
-		if (sysmmuconp->enable == true) {
-			reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
-
-			if (reg_int_status & 0xFF)
-				s5p_sysmmu_register(sysmmuconp);
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
-{
-	struct sysmmu_controller *sysmmuconp = NULL;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	/* Set sysmmu page table base address */
-	__raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
-
-	if (s5p_sysmmu_tlb_invalidate(ips) != 0)
-		printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
-
-	return 0;
-}
-
-static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
-{
-	unsigned int pg;
-	struct sysmmu_controller *sysmmuconp;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	__asm__("mrc	p15, 0, %0, c2, c0, 0"	\
-		: "=r" (pg) : : "cc");		\
-		pg &= ~0x3fff;
-
-	printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
-
-	/* Set sysmmu page table base address */
-	__raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
-
-	return 0;
-}
-
-int s5p_sysmmu_enable(sysmmu_ips ips)
-{
-	unsigned int reg;
-
-	struct sysmmu_controller *sysmmuconp;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	s5p_sysmmu_set_tablebase(ips);
-
-	/* replacement policy : LRU */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
-	reg |= 0x1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
-
-	/* Enable interrupt, Enable MMU */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg |= (0x1 << 2) | (0x1 << 0);
-
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	sysmmuconp->enable = true;
-
-	return 0;
-}
-
-int s5p_sysmmu_disable(sysmmu_ips ips)
-{
-	unsigned int reg;
-
-	struct sysmmu_controller *sysmmuconp = NULL;
-
-	if (ips > S5P_SYSMMU_TOTAL_IPNUM)
-		printk(KERN_ERR "failed to get ips parameter\n");
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
-
-	/* replacement policy : LRU */
-	reg |= 0x1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
-
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-
-	/* Disable MMU */
-	reg &= ~0x1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	sysmmuconp->enable = false;
-
-	return 0;
-}
-
-int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
-	unsigned int reg;
-	struct sysmmu_controller *sysmmuconp = NULL;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	/* set Block MMU for flush TLB */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg |= 0x1 << 1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	/* flush all TLB entry */
-	__raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH);
-
-	/* set Un-block MMU after flush TLB */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg &= ~(0x1 << 1);
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	return 0;
-}
-
-static int s5p_sysmmu_probe(struct platform_device *pdev)
-{
-	int i;
-	int ret;
-	struct resource *res;
-	struct sysmmu_controller *sysmmuconp;
-	sysmmu_ips ips;
-
-	for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
-		sysmmuconp = &s5p_sysmmu_cntlrs[i];
-		if (sysmmuconp == NULL) {
-			printk(KERN_ERR "failed to get ip's sysmmu info\n");
-			ret = -ENOENT;
-			goto err_res;
-		}
-
-		sysmmuconp->name = sysmmu_ips_name[i];
-
-		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res) {
-			printk(KERN_ERR "failed to get sysmmu resource\n");
-			ret = -ENODEV;
-			goto err_res;
-		}
-
-		sysmmuconp->mem = request_mem_region(res->start,
-				((res->end) - (res->start)) + 1, pdev->name);
-		if (!sysmmuconp->mem) {
-			pr_err("failed to request sysmmu memory region\n");
-			ret = -EBUSY;
-			goto err_res;
-		}
-
-		sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1);
-		if (!sysmmuconp->regs) {
-			pr_err("failed to sysmmu ioremap\n");
-			ret = -ENXIO;
-			goto err_reg;
-		}
-
-		sysmmuconp->irq = platform_get_irq(pdev, i);
-		if (sysmmuconp->irq <= 0) {
-			pr_err("failed to get sysmmu irq resource\n");
-			ret = -ENOENT;
-			goto err_map;
-		}
-
-		ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp);
-		if (ret) {
-			pr_err("failed to request irq\n");
-			ret = -ENOENT;
-			goto err_map;
-		}
-
-		ips = (sysmmu_ips)i;
-
-		sysmmuconp->ips = ips;
-	}
-
-	return 0;
-
-err_reg:
-	release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
-err_map:
-	iounmap(sysmmuconp->regs);
-err_res:
-	return ret;
-}
-
-static int s5p_sysmmu_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-int s5p_sysmmu_runtime_suspend(struct device *dev)
-{
-	return 0;
-}
-
-int s5p_sysmmu_runtime_resume(struct device *dev)
-{
-	return 0;
-}
-
-const struct dev_pm_ops s5p_sysmmu_pm_ops = {
-	.runtime_suspend	= s5p_sysmmu_runtime_suspend,
-	.runtime_resume		= s5p_sysmmu_runtime_resume,
-};
-
-static struct platform_driver s5p_sysmmu_driver = {
-	.probe		= s5p_sysmmu_probe,
-	.remove		= s5p_sysmmu_remove,
-	.driver		= {
-		.owner		= THIS_MODULE,
-		.name		= "s5p-sysmmu",
-		.pm		= &s5p_sysmmu_pm_ops,
-	}
-};
-
-static int __init s5p_sysmmu_init(void)
-{
-	return platform_driver_register(&s5p_sysmmu_driver);
-}
-arch_initcall(s5p_sysmmu_init);
+/* linux/arch/arm/plat-s5p/sysmmu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+
+#include <asm/memory.h>
+
+#include <plat/irqs.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/sysmmu.h>
+
+#include <mach/map.h>
+#include <mach/regs-sysmmu.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define sysmmu_debug(level, fmt, arg...)				 \
+	do {								 \
+		if (debug >= level)					 \
+			printk(KERN_DEBUG "[%s] " fmt, __func__, ## arg);\
+	} while (0)
+
+struct s5p_sysmmu_info {
+	struct mutex		mutex;
+	struct resource		*ioarea;
+	void __iomem		*regs;
+	unsigned int		irq;
+	struct clk		*clk;
+	bool			enabled;
+	bool			page_tables_allocated;
+	enum s5p_sysmmu_ip	ip;
+	enum s5p_sysmmu_cmd	mode;
+
+	unsigned long		flpt;
+	unsigned long		flpt_vaddr;
+	/* one table entry per 4 entries of the first level page table */
+	unsigned long		*vaddr;
+	/* one table entry per 4 entries of the first level page table */
+	u16			*refcount;
+
+	struct device		*dev;
+
+	struct list_head	entry;
+};
+
+static LIST_HEAD(sysmmu_list);
+static DEFINE_SPINLOCK(sysmmu_list_slock);
+
+void *s5p_sysmmu_get(struct device *dev, enum s5p_sysmmu_ip ip)
+{
+	struct s5p_sysmmu_info *ret;
+	unsigned long flags;
+
+	sysmmu_debug(3, "for %s\n", dev_name(dev));
+
+	spin_lock_irqsave(&sysmmu_list_slock, flags);
+	list_for_each_entry(ret, &sysmmu_list, entry) {
+		if (ret->ip == ip) {
+			try_module_get(THIS_MODULE);
+			spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+			return ret;
+		}
+	}
+	spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_get);
+
+void s5p_sysmmu_put(void *dev_id)
+{
+	module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_put);
+
+static void s5p_sysmmu_configure(struct s5p_sysmmu_info *sysmmu,
+				 unsigned long pg)
+{
+	unsigned int reg;
+
+	writel(pg, sysmmu->regs + S5P_PT_BASE_ADDR);
+
+	reg = readl(sysmmu->regs + S5P_MMU_CFG);
+	reg |= (0x1<<0);		/* replacement policy : LRU */
+	writel(reg, sysmmu->regs + S5P_MMU_CFG);
+
+	reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+	reg |= ((0x1<<2)|(0x1<<0));	/* Enable interrupt, Enable MMU */
+	writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+
+	sysmmu_debug(3, "CFG:0x%x\n", readl(sysmmu->regs + S5P_MMU_CFG));
+	sysmmu_debug(3, "CTRL:0x%x\n", readl(sysmmu->regs + S5P_MMU_CTRL));
+	sysmmu_debug(3, "STATUS:0x%x\n", readl(sysmmu->regs + S5P_MMU_STATUS));
+
+	sysmmu->enabled = true;
+}
+
+static int s5p_sysmmu_control_locked(struct s5p_sysmmu_info *sysmmu,
+				     enum s5p_sysmmu_cmd cmd)
+{
+	unsigned int pg, reg;
+
+	sysmmu_debug(3, "%d\n", cmd);
+
+	sysmmu->mode = cmd;
+
+	switch (cmd) {
+	case S5P_SYSMMU_ENABLE_SHARED:
+		/*
+		 * coprocessor 15 == mmu;
+		 * copy system page tables base from there
+		 */
+		__asm__("mrc p15, 0, %0, c2, c0, 0" : "=r" (pg) : : "cc");
+		pg &= ~0x3fff;
+
+		s5p_sysmmu_configure(sysmmu, pg);
+
+		return 0;
+	break;
+
+	case S5P_SYSMMU_ENABLE_PRIVATE:
+		pm_runtime_get_sync(sysmmu->dev);
+		if (!sysmmu->page_tables_allocated) {
+			/*
+			 * first-level page table holds
+			 * 4k second-level descriptors == 16kB == 4 pages
+			 */
+			sysmmu->flpt_vaddr = (unsigned long)dma_alloc_coherent(
+				sysmmu->dev,
+				4 * PAGE_SIZE,
+				(dma_addr_t *)&sysmmu->flpt,
+				GFP_KERNEL | __GFP_ZERO);
+			if (!sysmmu->flpt_vaddr)
+				return -ENOMEM;
+
+			sysmmu->refcount = kzalloc(1024 * sizeof(u16),
+						   GFP_KERNEL);
+			if (!sysmmu->refcount) {
+				dma_free_coherent(sysmmu->dev, 4 * PAGE_SIZE,
+					(dma_addr_t *)sysmmu->flpt_vaddr,
+					sysmmu->flpt);
+				return -ENOMEM;
+			}
+
+			sysmmu->vaddr = kzalloc(1024 * sizeof(unsigned long),
+						GFP_KERNEL);
+			if (!sysmmu->vaddr) {
+				kfree(sysmmu->refcount);
+				dma_free_coherent(sysmmu->dev, 4 * PAGE_SIZE,
+					(void *)sysmmu->flpt_vaddr,
+					sysmmu->flpt);
+				return -ENOMEM;
+			}
+			sysmmu->page_tables_allocated = true;
+		}
+		s5p_sysmmu_configure(sysmmu, sysmmu->flpt);
+
+		return 0;
+	break;
+
+	case S5P_SYSMMU_DISABLE:
+		reg = readl(sysmmu->regs + S5P_MMU_CFG);
+		reg |= (0x1<<0);		/* replacement policy : LRU */
+		writel(reg, sysmmu->regs + S5P_MMU_CFG);
+
+		reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+		reg &= ~(0x1);			/* Disable MMU */
+		writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+		sysmmu->enabled = false;
+ 		pm_runtime_put_sync(sysmmu->dev);
+		return 0;
+	break;
+
+	case S5P_SYSMMU_TLB_INVALIDATE:
+		reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+		reg |= (0x1<<1);		/* Block MMU */
+		writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+
+		writel(0x1, sysmmu->regs + S5P_MMU_FLUSH);
+						/* Flush_entry */
+
+		reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+		reg &= ~(0x1<<1);		/* Un-block MMU */
+		writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+		return 0;
+	break;
+
+	default:
+		;
+	}
+	return -EINVAL;
+}
+
+int s5p_sysmmu_control(void *dev_id, enum s5p_sysmmu_cmd cmd)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	int ret;
+
+	mutex_lock(&sysmmu->mutex);
+	ret = s5p_sysmmu_control_locked(sysmmu, cmd);
+	mutex_unlock(&sysmmu->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_control);
+
+#define dereference_vaddr(vaddr) (*((unsigned long *)(vaddr)))
+
+#define make_flpt_entry(slpt, k) \
+	((((slpt) + (k) * 256 * 4) & ~0x3FF) | 0x1)
+#define make_slpt_phys_entry(phys) (((phys) & ~0xFFF) | 0x2)
+
+#define flpt_offset(vaddr) (((vaddr) >> 18) & 0x3FFC)
+#define slpt_offset(slpt, vaddr) \
+	(((slpt) & (0x3 << 10)) + (((vaddr) >> 10) & 0x3FC))
+
+#define slpt_number(vaddr) (((vaddr) >> 22) & 0x3FF)
+
+#define get_slpt(flpt_entry_vaddr) \
+	(dereference_vaddr(flpt_entry_vaddr) & ~0x3FF)
+#define get_slpt_four(flpt_entry_vaddr) \
+	(dereference_vaddr(flpt_entry_vaddr) & ~0xFFF)
+
+#define invalidate_slpt_entry(slpt_entry_vaddr) \
+	(dereference_vaddr(slpt_entry_vaddr) &= ~0x3)
+
+/*
+ * vaddr:
+ * X X X X X X X X X X X X  X X X X X X X X  X X X X X X X X X X 0 0
+ * 31--------------------20 19------------12 11--------------------0
+ *     index into flpt       idx into slpt      offset within page
+ */
+static int s5p_sysmmu_map_page(struct s5p_sysmmu_info *sysmmu,
+	   		       unsigned long vaddr, unsigned long paddr)
+{
+	unsigned long flpt_entry_vaddr, slpt_entry_vaddr, slpt, slpt_vaddr;
+	int four_entry = slpt_number(vaddr);
+
+	flpt_entry_vaddr = sysmmu->flpt_vaddr + flpt_offset(vaddr);
+	if (0 == dereference_vaddr(flpt_entry_vaddr)) {
+		int k;
+		unsigned long flpt_four = flpt_entry_vaddr & ~0xF;
+
+		slpt_vaddr = (unsigned long)dma_alloc_coherent(
+			sysmmu->dev,
+			PAGE_SIZE,
+			(dma_addr_t *)&slpt,
+			GFP_KERNEL | __GFP_ZERO);
+		if (!slpt_vaddr)
+			return -1;
+
+		sysmmu->vaddr[four_entry] = slpt_vaddr;
+
+		for (k = 0; k < 4; ++k)
+			dereference_vaddr(flpt_four + 4 * k) =
+						make_flpt_entry(slpt, k);
+
+		sysmmu_debug(3, "4-entry:%d\n", four_entry);
+	}
+	slpt = get_slpt(flpt_entry_vaddr);
+	slpt_entry_vaddr = sysmmu->vaddr[four_entry] + slpt_offset(slpt, vaddr);
+	dereference_vaddr(slpt_entry_vaddr) = make_slpt_phys_entry(paddr);
+	sysmmu->refcount[four_entry]++;
+
+	return 0;
+}
+
+static void s5p_unmap_page(struct s5p_sysmmu_info *sysmmu, unsigned long vaddr)
+{
+	unsigned long flpt_entry_vaddr, slpt_entry_vaddr, slpt;
+	int four_entry = slpt_number(vaddr);
+
+	flpt_entry_vaddr = sysmmu->flpt_vaddr + flpt_offset(vaddr);
+	if (--sysmmu->refcount[four_entry]) {
+		slpt = get_slpt(flpt_entry_vaddr);
+		slpt_entry_vaddr = sysmmu->vaddr[four_entry] +
+				slpt_offset(slpt, vaddr);
+		invalidate_slpt_entry(slpt_entry_vaddr);
+	} else {
+		dma_free_coherent(sysmmu->dev, PAGE_SIZE,
+			(void *)sysmmu->vaddr[four_entry],
+			get_slpt_four(flpt_entry_vaddr));
+
+		memset((void *)(flpt_entry_vaddr & ~0xF), 0, 16);
+
+		sysmmu->vaddr[four_entry] = 0;
+	}
+}
+
+int s5p_sysmmu_map_area(void *dev_id, unsigned long varea_start,
+			unsigned long num_pages, struct page **pages)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	int i, ret;
+
+	sysmmu_debug(3, "varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	mutex_lock(&sysmmu->mutex);
+	for (i = 0; i < num_pages; varea_start += PAGE_SIZE, ++i) {
+		ret = s5p_sysmmu_map_page(sysmmu,
+				     varea_start, page_to_phys(pages[i]));
+		if (ret < 0)
+			goto slpt_pg_alloc_fail;
+	}
+
+	mutex_unlock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "MAPPING DONE for varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start - num_pages * PAGE_SIZE, num_pages);
+
+	return 0;
+
+slpt_pg_alloc_fail:
+	while (--i >= 0) {
+		varea_start -= PAGE_SIZE;
+		s5p_unmap_page(sysmmu, varea_start);
+	}
+	s5p_sysmmu_control_locked(sysmmu, S5P_SYSMMU_TLB_INVALIDATE);
+	mutex_unlock(&sysmmu->mutex);
+	return -1;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_map_area);
+
+int s5p_sysmmu_map_phys_area(void *dev_id, unsigned long varea_start,
+			unsigned long phys_area_start, unsigned long num_pages)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	int i;
+
+	sysmmu_debug(3, "varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	mutex_lock(&sysmmu->mutex);
+	for (i = 0; i < num_pages;
+		varea_start += PAGE_SIZE, phys_area_start += PAGE_SIZE, ++i)
+		if (s5p_sysmmu_map_page(sysmmu, varea_start, phys_area_start) < 0)
+			goto slpt_pg_alloc_fail;
+
+	mutex_unlock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "MAPPING DONE for varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start - num_pages * PAGE_SIZE, num_pages);
+
+	return 0;
+
+slpt_pg_alloc_fail:
+	while (--i >= 0) {
+		varea_start -= PAGE_SIZE;
+		s5p_unmap_page(sysmmu, varea_start);
+	}
+	s5p_sysmmu_control_locked(sysmmu, S5P_SYSMMU_TLB_INVALIDATE);
+	mutex_unlock(&sysmmu->mutex);
+	return -1;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_map_phys_area);
+
+void s5p_sysmmu_unmap_area(void *dev_id, unsigned long varea_start,
+			   unsigned long num_pages)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	unsigned long vaddr = varea_start;
+	int i;
+
+	mutex_lock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	for (i = 0; i < num_pages; vaddr += PAGE_SIZE, ++i)
+		s5p_unmap_page(sysmmu, vaddr);
+
+	s5p_sysmmu_control_locked(sysmmu, S5P_SYSMMU_TLB_INVALIDATE);
+	mutex_unlock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "UNMAPPING DONE for varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	return;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_unmap_area)
+
+static void s5p_sysmmu_pg_fault(struct s5p_sysmmu_info *sysmmu)
+{
+	void __iomem *regbase = sysmmu->regs;
+	unsigned long fault;
+
+	fault = readl(regbase + S5P_PAGE_FAULT_ADDR);
+	sysmmu_debug(3, "Page fault occured for virtual address 0x%08lx\n",
+		     fault);
+}
+
+static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	unsigned int reg_INT_STATUS;
+
+	if (false == sysmmu->enabled)
+		return IRQ_HANDLED;
+
+	reg_INT_STATUS = readl(sysmmu->regs + S5P_INT_STATUS);
+	if (reg_INT_STATUS & 0xFF) {
+		switch (reg_INT_STATUS & 0xFF) {
+		case 0x1:
+			/* page fault */
+			sysmmu_debug(3, "irq:pg fault\n");
+			s5p_sysmmu_pg_fault(sysmmu);
+			break;
+		case 0x2:
+			/* AR multi-hit fault */
+			sysmmu_debug(3, "irq:ar multi hit\n");
+			break;
+		case 0x4:
+			/* AW multi-hit fault */
+			sysmmu_debug(3, "irq:aw multi hit\n");
+			break;
+		case 0x8:
+			/* bus error */
+			sysmmu_debug(3, "irq:bus error\n");
+			break;
+		case 0x10:
+			/* AR security protection fault */
+			sysmmu_debug(3, "irq:ar security protection fault\n");
+			break;
+		case 0x20:
+			/* AR access protection fault */
+			sysmmu_debug(3, "irq:ar access protection fault\n");
+			break;
+		case 0x40:
+			/* AW security protection fault */
+			sysmmu_debug(3, "irq:aw security protection fault\n");
+			break;
+		case 0x80:
+			/* AW access protection fault */
+			sysmmu_debug(3, "irq:aw access protection fault\n");
+			break;
+		}
+		writel(reg_INT_STATUS, sysmmu->regs + S5P_INT_CLEAR);
+	}
+	return IRQ_HANDLED;
+}
+
+static int s5p_sysmmu_probe(struct platform_device *pdev)
+{
+	struct s5p_sysmmu_info *sysmmu;
+	struct resource *res;
+	int ret;
+	unsigned long flags;
+
+	sysmmu = kzalloc(sizeof(struct s5p_sysmmu_info), GFP_KERNEL);
+	if (!sysmmu) {
+		dev_err(&pdev->dev, "no memory for state\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (NULL == res) {
+		dev_err(&pdev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err_s5p_sysmmu_info_allocated;
+	}
+
+	sysmmu->ioarea = request_mem_region(res->start, resource_size(res),
+					 pdev->name);
+
+	if (NULL == sysmmu->ioarea) {
+		dev_err(&pdev->dev, "cannot request IO\n");
+		ret = -ENXIO;
+		goto err_s5p_sysmmu_info_allocated;
+	}
+
+	sysmmu->regs = ioremap(res->start, resource_size(res));
+
+	if (NULL == sysmmu->regs) {
+		dev_err(&pdev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_ioarea_requested;
+	}
+
+	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+		sysmmu->regs, sysmmu->ioarea, res);
+
+	sysmmu->irq = ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "cannot find IRQ\n");
+		goto err_iomap_done;
+	}
+
+	ret = request_irq(sysmmu->irq, s5p_sysmmu_irq, 0,
+			  dev_name(&pdev->dev), sysmmu);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot claim IRQ %d\n", sysmmu->irq);
+		goto err_iomap_done;
+	}
+
+	sysmmu->clk = clk_get(&pdev->dev, "sysmmu");
+	if (IS_ERR_OR_NULL(sysmmu->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		ret = -ENOENT;
+		goto err_request_irq_done;
+	}
+	dev_dbg(&pdev->dev, "clock source %p\n", sysmmu->clk);
+	clk_enable(sysmmu->clk);
+
+	sysmmu->ip = pdev->id;
+
+	spin_lock_irqsave(&sysmmu_list_slock, flags);
+	list_add(&sysmmu->entry, &sysmmu_list);
+	spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+
+	sysmmu->dev = &pdev->dev;
+
+	mutex_init(&sysmmu->mutex);
+
+	platform_set_drvdata(pdev, sysmmu);
+
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	dev_info(&pdev->dev, "Samsung S5P SYSMMU (IOMMU)\n");
+	return 0;
+
+err_request_irq_done:
+	free_irq(sysmmu->irq, sysmmu);
+
+err_iomap_done:
+	iounmap(sysmmu->regs);
+
+err_ioarea_requested:
+	release_resource(sysmmu->ioarea);
+	kfree(sysmmu->ioarea);
+
+err_s5p_sysmmu_info_allocated:
+	kfree(sysmmu);
+	return ret;
+}
+
+static int s5p_sysmmu_remove(struct platform_device *pdev)
+{
+	struct s5p_sysmmu_info *sysmmu = platform_get_drvdata(pdev);
+	unsigned long flags;
+	int i = 1024;
+
+ 	pm_runtime_disable(sysmmu->dev);
+
+	if ((S5P_SYSMMU_ENABLE_PRIVATE == sysmmu->mode)) {
+		while (i >= 0) {
+			if (sysmmu->refcount[i]) {
+				unsigned long flpt_entry;
+				flpt_entry = dereference_vaddr(
+					sysmmu->flpt_vaddr + 4 * 4 * i);
+				dma_free_coherent(sysmmu->dev,
+					PAGE_SIZE,
+					(void *)sysmmu->vaddr[i],
+					flpt_entry & ~0xFFF);
+			}
+			--i;
+		}
+
+		if (sysmmu->flpt) {
+			dma_free_coherent(sysmmu->dev, 4 * PAGE_SIZE,
+				(void *)sysmmu->flpt_vaddr, sysmmu->flpt);
+		}
+		kfree(sysmmu->refcount);
+		kfree(sysmmu->vaddr);
+	}
+
+	spin_lock_irqsave(&sysmmu_list_slock, flags);
+	list_del(&sysmmu->entry);
+	spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+
+	clk_disable(sysmmu->clk);
+	clk_put(sysmmu->clk);
+
+	free_irq(sysmmu->irq, sysmmu);
+
+	iounmap(sysmmu->regs);
+
+	release_resource(sysmmu->ioarea);
+	kfree(sysmmu->ioarea);
+
+	kfree(sysmmu);
+
+	return 0;
+}
+
+static int s5p_sysmmu_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int s5p_sysmmu_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static int s5p_sysmmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+static int s5p_sysmmu_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops s5p_sysmmu_pm_ops = {
+	.runtime_suspend = s5p_sysmmu_runtime_suspend,
+	.runtime_resume	 = s5p_sysmmu_runtime_resume,
+};
+
+static struct platform_driver s5p_sysmmu_driver = {
+	.probe = s5p_sysmmu_probe,
+	.remove = s5p_sysmmu_remove,
+	.suspend = s5p_sysmmu_suspend,
+	.resume = s5p_sysmmu_resume,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "s5p-sysmmu",
+		.pm = &s5p_sysmmu_pm_ops,
+	},
+};
+
+static int __init s5p_sysmmu_register(void)
+{
+	return platform_driver_register(&s5p_sysmmu_driver);
+}
+
+static void __exit s5p_sysmmu_unregister(void)
+{
+	platform_driver_unregister(&s5p_sysmmu_driver);
+}
+
+module_init(s5p_sysmmu_register);
+module_exit(s5p_sysmmu_unregister);
+
+MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_DESCRIPTION("Samsung System MMU (IOMMU) driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index b0123f3..9f42dee 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -138,7 +138,7 @@ extern struct platform_device s5p_device_fimc3;
 extern struct platform_device s5p_device_mipi_csis0;
 extern struct platform_device s5p_device_mipi_csis1;
 
-extern struct platform_device s5pv310_device_sysmmu;
+extern struct platform_device s5pv310_device_sysmmu[];
 
 /* s3c2440 specific devices */
 
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 4/7] v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
                   ` (2 preceding siblings ...)
  2011-03-04  9:01 ` [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 5/7] s5p-fimc: add pm_runtime support Marek Szyprowski
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>

This patch adds new videobuf2 memory allocator dedicated to Samsung SoC
series with IOMMU module. It requires s5p-sysmmu low level driver for
controlling iommu. This allocator aquires memory with standard
alloc_page() call and doesn't suffer from memory fragmentation issues.
Curretnly it supports only iommu module on Sasmung S5PV310 SoC series.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/media/video/Kconfig               |    8 +-
 drivers/media/video/Makefile              |    1 +
 drivers/media/video/videobuf2-s5p-iommu.c |  444 +++++++++++++++++++++++++++++
 include/media/videobuf2-s5p-iommu.h       |   50 ++++
 4 files changed, 502 insertions(+), 1 deletions(-)
 create mode 100644 drivers/media/video/videobuf2-s5p-iommu.c
 create mode 100644 include/media/videobuf2-s5p-iommu.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index e2f5a69..9806505 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -60,12 +60,18 @@ config VIDEOBUF2_VMALLOC
 	select VIDEOBUF2_MEMOPS
 	tristate
 
-
 config VIDEOBUF2_DMA_SG
 	#depends on HAS_DMA
 	select VIDEOBUF2_CORE
 	select VIDEOBUF2_MEMOPS
 	tristate
+
+config VIDEOBUF2_S5P_IOMMU
+	select GENERIC_ALLOCATOR
+	select VIDEOBUF2_CORE
+	select VIDEOBUF2_MEMOPS
+	tristate
+
 #
 # Multimedia Video device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ac54652..fd9488d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS)		+= videobuf2-memops.o
 obj-$(CONFIG_VIDEOBUF2_VMALLOC)		+= videobuf2-vmalloc.o
 obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG)	+= videobuf2-dma-contig.o
 obj-$(CONFIG_VIDEOBUF2_DMA_SG)		+= videobuf2-dma-sg.o
+obj-$(CONFIG_VIDEOBUF2_S5P_IOMMU)	+= videobuf2-s5p-iommu.o
 
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
diff --git a/drivers/media/video/videobuf2-s5p-iommu.c b/drivers/media/video/videobuf2-s5p-iommu.c
new file mode 100644
index 0000000..5826fe0
--- /dev/null
+++ b/drivers/media/video/videobuf2-s5p-iommu.c
@@ -0,0 +1,444 @@
+/*
+ * videobuf2-s5p-iommu.c - SYSMMU (IOMMU) based memory allocator for videobuf2
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@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.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/genalloc.h>
+#include <linux/device.h>
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+#include <media/videobuf2-s5p-iommu.h>
+
+/*
+ * 17: single piece of memory (one bitmap entry) equals 128k,
+ * so by default the genalloc's bitmap occupies 4kB (one page
+ * for a number of architectures)
+ */
+#define VB2_S5P_IOMMU_PIECE_ORDER	17
+
+/* -1: use default node id to allocate gen_pool/gen_pool_chunk structure from */
+#define VB2_S5P_IOMMU_NODE_ID		-1
+
+/*
+ * starting address of the virtual address space of the client device
+ * must not be zero
+ */
+#define VB2_S5P_IOMMU_MEM_BASE		0x30000000
+
+/* size of the virtual address space of the client device */
+#define VB2_S5P_IOMMU_MEM_SIZE		0x40000000
+
+struct vb2_s5p_iommu_alloc_ctx {
+	/* not interpreted here; only passed to the sysmmu driver */
+	void *sysmmu;
+
+	struct gen_pool *pool;
+};
+
+struct vb2_s5p_iommu_desc {
+	unsigned long		size;
+	unsigned int		num_pages;
+	struct page		**pages;
+};
+
+struct vb2_s5p_iommu_buf {
+	unsigned long			drv_addr;
+	unsigned long			vaddr;
+
+	struct vb2_s5p_iommu_desc	info;
+	int				offset;
+	atomic_t			refcount;
+	int				write;
+	struct vm_area_struct		*vma;
+
+	struct vb2_vmarea_handler	handler;
+
+	struct vb2_s5p_iommu_alloc_ctx	*ctx;
+};
+
+static void vb2_s5p_iommu_put(void *buf_priv);
+
+static void *vb2_s5p_iommu_alloc(void *alloc_ctx, unsigned long size)
+{
+	struct vb2_s5p_iommu_alloc_ctx *ctx = alloc_ctx;
+	struct vb2_s5p_iommu_buf *buf;
+	int i, ret;
+
+	BUG_ON(NULL == alloc_ctx);
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	buf->drv_addr = gen_pool_alloc(ctx->pool, size);
+	if (0 == buf->drv_addr)
+		goto gen_pool_alloc_fail;
+
+	buf->info.size = size;
+	buf->info.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	buf->ctx = ctx;
+	buf->info.pages = kzalloc(
+		buf->info.num_pages * sizeof(struct page *), GFP_KERNEL);
+	if (!buf->info.pages)
+		goto fail_pages_array_alloc;
+
+	for (i = 0; i < buf->info.num_pages; ++i) {
+		buf->info.pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
+		if (NULL == buf->info.pages[i])
+			goto fail_pages_alloc;
+	}
+
+	buf->handler.refcount = &buf->refcount;
+	buf->handler.put = vb2_s5p_iommu_put;
+	buf->handler.arg = buf;
+
+	atomic_inc(&buf->refcount);
+
+	ret = s5p_sysmmu_map_area(ctx->sysmmu, buf->drv_addr,
+		buf->info.num_pages, buf->info.pages);
+
+	if (ret < 0)
+		goto fail_sysmmu_map_area;
+
+	/*
+	 * TODO: Ensure no one else flushes the cache later onto our memory
+	 * which already contains important data.
+	 * Perhaps find a better way to do it.
+	 */
+	flush_cache_all();
+	outer_flush_all();
+	return buf;
+
+fail_sysmmu_map_area:
+fail_pages_alloc:
+	while (--i >= 0)
+		__free_page(buf->info.pages[i]);
+	kfree(buf->info.pages);
+
+fail_pages_array_alloc:
+	gen_pool_free(ctx->pool, buf->drv_addr, size);
+
+gen_pool_alloc_fail:
+	kfree(buf);
+	return NULL;
+}
+
+static void vb2_s5p_iommu_put(void *buf_priv)
+{
+	struct vb2_s5p_iommu_buf *buf = buf_priv;
+	int i = buf->info.num_pages;
+
+	if (atomic_dec_and_test(&buf->refcount)) {
+		s5p_sysmmu_unmap_area(buf->ctx->sysmmu, buf->drv_addr,
+				      buf->info.num_pages);
+		if (buf->vaddr)
+			vm_unmap_ram((void *)buf->vaddr, buf->info.num_pages);
+		while (--i >= 0)
+			__free_page(buf->info.pages[i]);
+		kfree(buf->info.pages);
+		gen_pool_free(buf->ctx->pool, buf->drv_addr, buf->info.size);
+		kfree(buf);
+	}
+}
+
+static void *vb2_s5p_iommu_get_userptr(void *alloc_ctx, unsigned long vaddr,
+				    unsigned long size, int write)
+{
+	struct vb2_s5p_iommu_alloc_ctx *ctx = alloc_ctx;
+	struct vb2_s5p_iommu_buf *buf;
+	unsigned long first, last;
+	int num_pages_from_user, ret;
+	void *rv = NULL;
+
+	BUG_ON(NULL == alloc_ctx);
+
+	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	if (!buf)
+		return rv;
+
+	buf->drv_addr = gen_pool_alloc(ctx->pool, size);
+	if (0 == buf->drv_addr) {
+		rv = ERR_PTR(-ENOMEM);
+		goto userptr_gen_pool_alloc_fail;
+	}
+
+	buf->write = write;
+	buf->offset = vaddr & ~PAGE_MASK;
+	buf->info.size = size;
+	first = (vaddr           & PAGE_MASK) >> PAGE_SHIFT;
+	last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
+	buf->info.num_pages = last - first + 1;
+	buf->ctx = ctx;
+	buf->info.pages = kzalloc(buf->info.num_pages * sizeof(struct page *),
+				  GFP_KERNEL);
+	if (!buf->info.pages) {
+		rv = ERR_PTR(-ENOMEM);
+		goto userptr_fail_pages_array_alloc;
+	}
+
+	down_read(&current->mm->mmap_sem);
+	num_pages_from_user = get_user_pages(current, current->mm,
+					     vaddr & PAGE_MASK,
+					     buf->info.num_pages,
+					     write,
+					     1, /* force */
+					     buf->info.pages,
+					     NULL);
+	up_read(&current->mm->mmap_sem);
+
+	if (num_pages_from_user == buf->info.num_pages) {
+		ret = s5p_sysmmu_map_area(ctx->sysmmu, buf->drv_addr,
+			buf->info.num_pages, buf->info.pages);
+
+		if (ret)
+			goto userptr_fail_sysmmu_map_area;
+
+		return buf;
+	} else if (num_pages_from_user < 0) {
+		struct vm_area_struct *vma;
+		dma_addr_t paddr = 0;
+
+		ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
+
+		if (ret) {
+			rv = ERR_PTR(ret);
+			goto userptr_fail_get_contig;
+		}
+
+		buf->vma = vma;
+
+		ret = s5p_sysmmu_map_phys_area(ctx->sysmmu, buf->drv_addr,
+					       paddr, buf->info.num_pages);
+		if (ret)
+			goto userptr_fail_sysmmu_map_area;
+
+		return buf;
+	}
+	/* else fail */
+
+userptr_fail_sysmmu_map_area:
+	while (--num_pages_from_user >= 0)
+		put_page(buf->info.pages[num_pages_from_user]);
+	if (buf->vma)
+		vb2_put_vma(buf->vma);
+userptr_fail_get_contig:
+	kfree(buf->info.pages);
+
+userptr_fail_pages_array_alloc:
+	gen_pool_free(ctx->pool, buf->drv_addr, size);
+
+userptr_gen_pool_alloc_fail:
+	kfree(buf);
+	return rv;
+}
+
+/*
+ * @put_userptr: inform the allocator that a USERPTR buffer will no longer
+ *		 be used
+ */
+static void vb2_s5p_iommu_put_userptr(void *buf_priv)
+{
+	struct vb2_s5p_iommu_buf *buf = buf_priv;
+	int i = buf->info.num_pages;
+
+	printk(KERN_DEBUG "%s: Releasing userspace buffer of %d pages\n",
+	       __func__, buf->info.num_pages);
+	if (buf->vaddr)
+		vm_unmap_ram((void *)buf->vaddr, buf->info.num_pages);
+	s5p_sysmmu_unmap_area(buf->ctx->sysmmu, buf->drv_addr,
+			      buf->info.num_pages);
+	if (buf->vma) {
+		vb2_put_vma(buf->vma);
+	} else {
+		while (--i >= 0) {
+			if (buf->write)
+				set_page_dirty_lock(buf->info.pages[i]);
+			put_page(buf->info.pages[i]);
+		}
+	}
+	kfree(buf->info.pages);
+	gen_pool_free(buf->ctx->pool, buf->drv_addr, buf->info.size);
+	kfree(buf);
+}
+
+static void *vb2_s5p_iommu_vaddr(void *buf_priv)
+{
+	struct vb2_s5p_iommu_buf *buf = buf_priv;
+
+	BUG_ON(!buf);
+
+	if (!buf->vaddr)
+		buf->vaddr = (unsigned long)vm_map_ram(buf->info.pages,
+					buf->info.num_pages,
+					-1,
+					pgprot_writecombine(PAGE_KERNEL));
+
+	/* add offset in case userptr is not page-aligned */
+	return (void *)(buf->vaddr + buf->offset);
+}
+
+static unsigned int vb2_s5p_iommu_num_users(void *buf_priv)
+{
+	struct vb2_s5p_iommu_buf *buf = buf_priv;
+
+	return atomic_read(&buf->refcount);
+}
+
+static int vb2_s5p_iommu_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	struct vb2_s5p_iommu_buf *buf = buf_priv;
+	unsigned long uaddr = vma->vm_start;
+	unsigned long usize = vma->vm_end - vma->vm_start;
+	int i = 0;
+
+	if (!buf) {
+		printk(KERN_ERR "No memory to map\n");
+		return -EINVAL;
+	}
+
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	do {
+		int ret;
+
+		ret = vm_insert_page(vma, uaddr, buf->info.pages[i++]);
+		if (ret) {
+			printk(KERN_ERR "Remapping memory, error: %d\n", ret);
+			return ret;
+		}
+
+		uaddr += PAGE_SIZE;
+		usize -= PAGE_SIZE;
+	} while (usize > 0);
+
+
+	/*
+	 * Use common vm_area operations to track buffer refcount.
+	 */
+	vma->vm_private_data	= &buf->handler;
+	vma->vm_ops		= &vb2_common_vm_ops;
+
+	vma->vm_ops->open(vma);
+
+	return 0;
+}
+
+static void *vb2_s5p_iommu_cookie(void *buf_priv)
+{
+	struct vb2_s5p_iommu_buf *buf = buf_priv;
+
+	return (void *)buf->drv_addr + buf->offset;
+}
+
+const struct vb2_mem_ops vb2_s5p_iommu_memops = {
+	.alloc		= vb2_s5p_iommu_alloc,
+	.put		= vb2_s5p_iommu_put,
+	.get_userptr	= vb2_s5p_iommu_get_userptr,
+	.put_userptr	= vb2_s5p_iommu_put_userptr,
+	.vaddr		= vb2_s5p_iommu_vaddr,
+	.mmap		= vb2_s5p_iommu_mmap,
+	.num_users	= vb2_s5p_iommu_num_users,
+	.cookie		= vb2_s5p_iommu_cookie,
+};
+EXPORT_SYMBOL_GPL(vb2_s5p_iommu_memops);
+
+void
+*vb2_s5p_iommu_init(struct device *dev, struct vb2_s5p_iommu_request *iommu_req)
+{
+	struct vb2_s5p_iommu_alloc_ctx *ctx;
+	unsigned long mem_base, mem_size;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
+
+	if (iommu_req->align_order && iommu_req->align_order < PAGE_SHIFT)
+		iommu_req->align_order = PAGE_SHIFT;
+
+	ctx->pool = gen_pool_create(
+		iommu_req->align_order ? iommu_req->align_order :
+		VB2_S5P_IOMMU_PIECE_ORDER,
+		VB2_S5P_IOMMU_NODE_ID);
+
+	if (!ctx->pool)
+		goto pool_alloc_fail;
+
+	if (0 == iommu_req->mem_base && 0 == iommu_req->mem_size) {
+		mem_base = VB2_S5P_IOMMU_MEM_BASE;
+		mem_size = VB2_S5P_IOMMU_MEM_SIZE;
+	} else {
+		mem_base = iommu_req->mem_base;
+		mem_size = iommu_req->mem_size;
+	}
+
+	if (gen_pool_add(ctx->pool, mem_base, mem_size, VB2_S5P_IOMMU_NODE_ID))
+		goto chunk_add_fail;
+
+	ctx->sysmmu = s5p_sysmmu_get(dev, iommu_req->ip);
+	if (!ctx->sysmmu) {
+		dev_err(dev, "SYSMMU get failed\n");
+		goto chunk_add_fail;
+	}
+
+	return ctx;
+
+chunk_add_fail:
+	gen_pool_destroy(ctx->pool);
+pool_alloc_fail:
+	kfree(ctx);
+	return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL_GPL(vb2_s5p_iommu_init);
+
+void vb2_s5p_iommu_cleanup(void *alloc_ctx)
+{
+	struct vb2_s5p_iommu_alloc_ctx *ctx = alloc_ctx;
+
+	BUG_ON(NULL == alloc_ctx);
+
+	s5p_sysmmu_put(ctx->sysmmu);
+
+	gen_pool_destroy(ctx->pool);
+
+	kfree(alloc_ctx);
+}
+EXPORT_SYMBOL_GPL(vb2_s5p_iommu_cleanup);
+
+int vb2_s5p_iommu_enable(void *alloc_ctx)
+{
+	struct vb2_s5p_iommu_alloc_ctx *ctx = alloc_ctx;
+
+	BUG_ON(NULL == alloc_ctx);
+
+	return s5p_sysmmu_control(ctx->sysmmu, S5P_SYSMMU_ENABLE_PRIVATE);
+}
+EXPORT_SYMBOL_GPL(vb2_s5p_iommu_enable);
+
+int vb2_s5p_iommu_disable(void *alloc_ctx)
+{
+	struct vb2_s5p_iommu_alloc_ctx *ctx = alloc_ctx;
+
+	BUG_ON(NULL == alloc_ctx);
+
+	return s5p_sysmmu_control(ctx->sysmmu, S5P_SYSMMU_DISABLE);
+}
+EXPORT_SYMBOL_GPL(vb2_s5p_iommu_disable);
+
+MODULE_DESCRIPTION("s5p iommu memory handling routines for videobuf2");
+MODULE_AUTHOR("Andrzej Pietrasiewicz");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-s5p-iommu.h b/include/media/videobuf2-s5p-iommu.h
new file mode 100644
index 0000000..5bad763
--- /dev/null
+++ b/include/media/videobuf2-s5p-iommu.h
@@ -0,0 +1,50 @@
+/*
+ * videobuf2-s5p-iommu.h - SYSMMU (IOMMU)-based memory allocator for videobuf2
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@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.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_S5P_IOMMU_H
+#define _MEDIA_VIDEOBUF2_S5P_IOMMU_H
+
+#include <media/videobuf2-core.h>
+#include <plat/sysmmu.h>
+
+struct device;
+
+struct vb2_s5p_iommu_request {
+	/* mem_base and mem_size both 0 => use allocator's default */
+	unsigned long		mem_base;
+	unsigned long		mem_size;
+	enum s5p_sysmmu_ip	ip;
+	/*
+	 * align_order 0 => use allocator's default
+	 * 0 < align_order < PAGE_SHIFT => rounded to PAGE_SHIFT by allocator
+	 */
+	int			align_order;
+};
+
+static inline unsigned long vb2_s5p_iommu_plane_addr(
+		struct vb2_buffer *vb, unsigned int plane_no)
+{
+	return (unsigned long)vb2_plane_cookie(vb, plane_no);
+}
+
+extern const struct vb2_mem_ops vb2_s5p_iommu_memops;
+
+void *vb2_s5p_iommu_init(struct device *dev,
+			 struct vb2_s5p_iommu_request *iommu_req);
+
+void vb2_s5p_iommu_cleanup(void *alloc_ctx);
+
+int vb2_s5p_iommu_enable(void *alloc_ctx);
+
+int vb2_s5p_iommu_disable(void *alloc_ctx);
+
+#endif
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 5/7] s5p-fimc: add pm_runtime support
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
                   ` (3 preceding siblings ...)
  2011-03-04  9:01 ` [PATCH 4/7] v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 6/7] s5p-fimc: Add support for vb2-s5p-iommu allocator Marek Szyprowski
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds basic support for pm_runtime to s5p-fimc driver. PM
runtime support is required to enable the driver on S5PV310 series with
power domain driver enabled.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/video/s5p-fimc/fimc-capture.c |    5 +++++
 drivers/media/video/s5p-fimc/fimc-core.c    |   14 ++++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 59123a6..f8d7de5 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
@@ -395,6 +396,8 @@ static int fimc_capture_open(struct file *file)
 	if (fimc_m2m_active(fimc))
 		return -EBUSY;
 
+	pm_runtime_get_sync(&fimc->pdev->dev);
+
 	if (++fimc->vid_cap.refcnt == 1) {
 		ret = fimc_isp_subdev_init(fimc, 0);
 		if (ret) {
@@ -425,6 +428,8 @@ static int fimc_capture_close(struct file *file)
 		fimc_subdev_unregister(fimc);
 	}
 
+	pm_runtime_put_sync(&fimc->pdev->dev);
+
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index db3e730..c92dbdb 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/list.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -1407,6 +1408,8 @@ static int fimc_m2m_open(struct file *file)
 	if (fimc->vid_cap.refcnt > 0)
 		return -EBUSY;
 
+	pm_runtime_get_sync(&fimc->pdev->dev);
+
 	fimc->m2m.refcnt++;
 	set_bit(ST_OUTDMA_RUN, &fimc->state);
 
@@ -1449,6 +1452,8 @@ static int fimc_m2m_release(struct file *file)
 	if (--fimc->m2m.refcnt <= 0)
 		clear_bit(ST_OUTDMA_RUN, &fimc->state);
 
+	pm_runtime_put_sync(&fimc->pdev->dev);
+
 	return 0;
 }
 
@@ -1646,6 +1651,11 @@ static int fimc_probe(struct platform_device *pdev)
 		goto err_req_region;
 	}
 
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	pm_runtime_get_sync(&pdev->dev);
+
 	fimc->num_clocks = MAX_FIMC_CLOCKS - 1;
 
 	/* Check if a video capture node needs to be registered. */
@@ -1703,6 +1713,8 @@ static int fimc_probe(struct platform_device *pdev)
 	dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
 		__func__, fimc->id);
 
+	pm_runtime_put_sync(&pdev->dev);
+
 	return 0;
 
 err_m2m:
@@ -1737,6 +1749,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
 
 	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
 
+	pm_runtime_disable(&pdev->dev);
+
 	iounmap(fimc->regs);
 	release_resource(fimc->regs_res);
 	kfree(fimc->regs_res);
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 6/7] s5p-fimc: Add support for vb2-s5p-iommu allocator
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
                   ` (4 preceding siblings ...)
  2011-03-04  9:01 ` [PATCH 5/7] s5p-fimc: add pm_runtime support Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-04  9:01 ` [PATCH 7/7] ARM: S5PC210: enable FIMC on Universal_C210 Marek Szyprowski
  2011-03-08  7:28 ` [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Kukjin Kim
  7 siblings, 0 replies; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds support for videobuf2-s5p-iommu allocator to s5p-fimc
driver. This allocator is selected only on systems that contains support
for S5P SYSMMU module. Otherwise the standard videobuf2-dma-contig is
used.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/video/Kconfig                 |    3 +-
 drivers/media/video/s5p-fimc/fimc-capture.c |    4 +-
 drivers/media/video/s5p-fimc/fimc-core.c    |   22 ++++---
 drivers/media/video/s5p-fimc/fimc-mem.h     |   87 +++++++++++++++++++++++++++
 4 files changed, 104 insertions(+), 12 deletions(-)
 create mode 100644 drivers/media/video/s5p-fimc/fimc-mem.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9806505..12fb325 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1018,7 +1018,8 @@ config VIDEO_MEM2MEM_TESTDEV
 config  VIDEO_SAMSUNG_S5P_FIMC
 	tristate "Samsung S5P FIMC (video postprocessor) driver"
 	depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
-	select VIDEOBUF2_DMA_CONTIG
+	select VIDEOBUF2_S5P_IOMMU if S5P_SYSTEM_MMU
+	select VIDEOBUF2_DMA_CONTIG if !S5P_SYSTEM_MMU
 	select V4L2_MEM2MEM_DEV
 	help
 	  This is a v4l2 driver for the S5P camera interface
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index f8d7de5..6819908 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -29,8 +29,8 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
 
+#include "fimc-mem.h"
 #include "fimc-core.h"
 
 static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
@@ -881,7 +881,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
 	q->io_modes = VB2_MMAP | VB2_USERPTR;
 	q->drv_priv = fimc->vid_cap.ctx;
 	q->ops = &fimc_capture_qops;
-	q->mem_ops = &vb2_dma_contig_memops;
+	q->mem_ops = &fimc_vb2_allocator_memops;
 	q->buf_struct_size = sizeof(struct fimc_vid_buffer);
 
 	vb2_queue_init(q);
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index c92dbdb..f06aaea 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -27,8 +27,8 @@
 #include <linux/clk.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
 
+#include "fimc-mem.h"
 #include "fimc-core.h"
 
 static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
@@ -458,7 +458,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
 	dbg("memplanes= %d, colplanes= %d, pix_size= %d",
 		frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
 
-	paddr->y = vb2_dma_contig_plane_paddr(vb, 0);
+	paddr->y = fimc_vb2_plane_addr(vb, 0);
 
 	if (frame->fmt->memplanes == 1) {
 		switch (frame->fmt->colplanes) {
@@ -486,10 +486,10 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
 		}
 	} else {
 		if (frame->fmt->memplanes >= 2)
-			paddr->cb = vb2_dma_contig_plane_paddr(vb, 1);
+			paddr->cb = fimc_vb2_plane_addr(vb, 1);
 
 		if (frame->fmt->memplanes == 3)
-			paddr->cr = vb2_dma_contig_plane_paddr(vb, 2);
+			paddr->cr = fimc_vb2_plane_addr(vb, 2);
 	}
 
 	dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
@@ -1375,7 +1375,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 	src_vq->drv_priv = ctx;
 	src_vq->ops = &fimc_qops;
-	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->mem_ops = &fimc_vb2_allocator_memops;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 
 	ret = vb2_queue_init(src_vq);
@@ -1387,7 +1387,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 	dst_vq->drv_priv = ctx;
 	dst_vq->ops = &fimc_qops;
-	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->mem_ops = &fimc_vb2_allocator_memops;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 
 	return vb2_queue_init(dst_vq);
@@ -1685,12 +1685,15 @@ static int fimc_probe(struct platform_device *pdev)
 		goto err_clk;
 	}
 
-	/* Initialize contiguous memory allocator */
-	fimc->alloc_ctx = vb2_dma_contig_init_ctx(&fimc->pdev->dev);
+	/* Initialize memory allocator */
+	fimc->alloc_ctx = fimc_vb2_allocator_init(pdev);
 	if (IS_ERR(fimc->alloc_ctx)) {
 		ret = PTR_ERR(fimc->alloc_ctx);
 		goto err_irq;
 	}
+	ret = fimc_vb2_allocator_enable(fimc->alloc_ctx);
+	if (ret)
+		goto err_irq;
 
 	ret = fimc_register_m2m_device(fimc);
 	if (ret)
@@ -1747,7 +1750,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
 
 	fimc_clk_release(fimc);
 
-	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+	fimc_vb2_allocator_disable(fimc->alloc_ctx);
+	fimc_vb2_allocator_cleanup(fimc->alloc_ctx);
 
 	pm_runtime_disable(&pdev->dev);
 
diff --git a/drivers/media/video/s5p-fimc/fimc-mem.h b/drivers/media/video/s5p-fimc/fimc-mem.h
new file mode 100644
index 0000000..9ac9bc6
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-mem.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_MEM_H_
+#define FIMC_MEM_H_
+
+/*
+ * fimc-mem.h is the interface for videbuf2 allocator. It is a proxy
+ * to real allocator depending on system capabilities.
+ * 1. on S5PC100 & S5PV210/S5PC110 systems vb2-dma-contig is used
+ * 2. on S5PV310/S5PC210 systems vb2-s5p-iommu allocator is selected.
+ *
+ */
+
+#ifdef CONFIG_S5P_SYSTEM_MMU
+
+#include <media/videobuf2-s5p-iommu.h>
+
+#define fimc_vb2_allocator_memops vb2_s5p_iommu_memops
+
+static inline void *fimc_vb2_allocator_init(struct platform_device *pdev)
+{
+	struct vb2_s5p_iommu_request iommu_req;
+	memset(&iommu_req, 0, sizeof(iommu_req));
+	iommu_req.ip = S5P_SYSMMU_FIMC0 + pdev->id;
+	return vb2_s5p_iommu_init(&pdev->dev, &iommu_req);
+}
+
+static inline void fimc_vb2_allocator_cleanup(void *alloc_ctx)
+{
+	return vb2_s5p_iommu_cleanup(alloc_ctx);
+}
+
+static inline unsigned long fimc_vb2_plane_addr(struct vb2_buffer *b, int n)
+{
+	return vb2_s5p_iommu_plane_addr(b, n);
+}
+
+static inline int fimc_vb2_allocator_enable(void *alloc_ctx)
+{
+	return vb2_s5p_iommu_enable(alloc_ctx);
+}
+
+static inline int fimc_vb2_allocator_disable(void *alloc_ctx)
+{
+	return vb2_s5p_iommu_disable(alloc_ctx);
+}
+
+#else	/* use vb2-dma-contig allocator */
+
+#include <media/videobuf2-dma-contig.h>
+
+#define fimc_vb2_allocator_memops vb2_dma_contig_memops
+
+static inline void *fimc_vb2_allocator_init(struct platform_device *pdev)
+{
+	return vb2_dma_contig_init_ctx(&pdev->dev);
+}
+
+static inline void fimc_vb2_allocator_cleanup(void *alloc_ctx)
+{
+	vb2_dma_contig_cleanup_ctx(alloc_ctx);
+}
+
+static inline unsigned long fimc_vb2_plane_addr(struct vb2_buffer *b, int n)
+{
+	return vb2_dma_contig_plane_paddr(b, n);
+}
+
+static inline int fimc_vb2_allocator_enable(void *alloc_ctx)
+{
+	return 0;
+}
+
+static inline int fimc_vb2_allocator_disable(void *alloc_ctx)
+{
+	return 0;
+}
+
+#endif
+
+#endif /* FIMC_CORE_H_ */
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 7/7] ARM: S5PC210: enable FIMC on Universal_C210
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
                   ` (5 preceding siblings ...)
  2011-03-04  9:01 ` [PATCH 6/7] s5p-fimc: Add support for vb2-s5p-iommu allocator Marek Szyprowski
@ 2011-03-04  9:01 ` Marek Szyprowski
  2011-03-08  7:28 ` [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Kukjin Kim
  7 siblings, 0 replies; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds definitions to enable support for s5p-fimc driver
together with required power domains and sysmmu controller on Universal
C210 board.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv310/Kconfig               |    6 ++++++
 arch/arm/mach-s5pv310/mach-universal_c210.c |   20 ++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s5pv310/Kconfig b/arch/arm/mach-s5pv310/Kconfig
index a8b0425..c850086 100644
--- a/arch/arm/mach-s5pv310/Kconfig
+++ b/arch/arm/mach-s5pv310/Kconfig
@@ -97,12 +97,18 @@ config MACH_UNIVERSAL_C210
 	bool "Mobile UNIVERSAL_C210 Board"
 	select CPU_S5PV310
 	select S5P_DEV_ONENAND
+	select S5P_DEV_FIMC0
+	select S5P_DEV_FIMC1
+	select S5P_DEV_FIMC2
+	select S5P_DEV_FIMC3
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC2
 	select S3C_DEV_HSMMC3
 	select S5PV310_SETUP_SDHCI
 	select S3C_DEV_I2C1
 	select S3C_DEV_I2C5
+	select S5PV310_DEV_PD
+	select S5PV310_DEV_SYSMMU
 	select S5PV310_SETUP_I2C1
 	select S5PV310_SETUP_I2C5
 	help
diff --git a/arch/arm/mach-s5pv310/mach-universal_c210.c b/arch/arm/mach-s5pv310/mach-universal_c210.c
index eece381..f153895 100644
--- a/arch/arm/mach-s5pv310/mach-universal_c210.c
+++ b/arch/arm/mach-s5pv310/mach-universal_c210.c
@@ -24,7 +24,9 @@
 #include <plat/s5pv310.h>
 #include <plat/cpu.h>
 #include <plat/devs.h>
+#include <plat/pd.h>
 #include <plat/sdhci.h>
+#include <plat/sysmmu.h>
 
 #include <mach/map.h>
 #include <mach/gpio.h>
@@ -816,6 +818,15 @@ static struct platform_device *universal_devices[] __initdata = {
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc2,
 	&s3c_device_hsmmc3,
+	&s5p_device_fimc0,
+	&s5p_device_fimc1,
+	&s5p_device_fimc2,
+	&s5p_device_fimc3,
+	&s5pv310_device_pd[PD_CAM],
+	&s5pv310_device_sysmmu[S5P_SYSMMU_FIMC0],
+	&s5pv310_device_sysmmu[S5P_SYSMMU_FIMC1],
+	&s5pv310_device_sysmmu[S5P_SYSMMU_FIMC2],
+	&s5pv310_device_sysmmu[S5P_SYSMMU_FIMC3],
 
 	/* Universal Devices */
 	&universal_gpio_keys,
@@ -842,6 +853,15 @@ static void __init universal_machine_init(void)
 
 	/* Last */
 	platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices));
+
+	s5p_device_fimc0.dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5p_device_fimc1.dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5p_device_fimc2.dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5p_device_fimc3.dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5pv310_device_sysmmu[S5P_SYSMMU_FIMC0].dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5pv310_device_sysmmu[S5P_SYSMMU_FIMC1].dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5pv310_device_sysmmu[S5P_SYSMMU_FIMC2].dev.parent = &s5pv310_device_pd[PD_CAM].dev;
+	s5pv310_device_sysmmu[S5P_SYSMMU_FIMC3].dev.parent = &s5pv310_device_pd[PD_CAM].dev;
 }
 
 MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-04  9:01 ` [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver Marek Szyprowski
@ 2011-03-04 16:04   ` Marek Szyprowski
  2011-03-10 14:52     ` Arnd Bergmann
  0 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-04 16:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>

This patch performs a complete rewrite of sysmmu driver for Samsung platform:
- the new version introduces an api to construct device private page
  tables and enables to use device private address space mode
- simplified the resource management: no more single platform
  device with 32 resources is needed, better fits into linux driver model,
  each sysmmu instance has it's own resource definition
- added support for sysmmu clocks
- some other minor API chages required by upcoming videobuf2 allocator

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---

Hello,

I'm really sorry for breaking this patch in the previous mail. The
semi-colon is missing in the "EXPORT_SYMBOL_GPL(s5p_sysmmu_unmap_area)"
line. This is the fixed version.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

---
 arch/arm/mach-s5pv310/clock.c                    |   91 ++
 arch/arm/mach-s5pv310/dev-sysmmu.c               |  582 +++++++++----
 arch/arm/mach-s5pv310/include/mach/irqs.h        |   36 +-
 arch/arm/mach-s5pv310/include/mach/regs-clock.h  |    3 +
 arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h |   23 +-
 arch/arm/mach-s5pv310/include/mach/sysmmu.h      |  122 ---
 arch/arm/plat-s5p/Kconfig                        |   17 +-
 arch/arm/plat-s5p/include/plat/sysmmu.h          |  127 +++
 arch/arm/plat-s5p/sysmmu.c                       |  988 +++++++++++++++-------
 arch/arm/plat-samsung/include/plat/devs.h        |    2 +-
 10 files changed, 1323 insertions(+), 668 deletions(-)
 rewrite arch/arm/mach-s5pv310/dev-sysmmu.c (86%)
 delete mode 100644 arch/arm/mach-s5pv310/include/mach/sysmmu.h
 create mode 100644 arch/arm/plat-s5p/include/plat/sysmmu.h
 rewrite arch/arm/plat-s5p/sysmmu.c (85%)

diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c
index fc7c2f8..f142b8c 100644
--- a/arch/arm/mach-s5pv310/clock.c
+++ b/arch/arm/mach-s5pv310/clock.c
@@ -20,6 +20,7 @@
 #include <plat/pll.h>
 #include <plat/s5p-clock.h>
 #include <plat/clock-clksrc.h>
+#include <plat/sysmmu.h>
 
 #include <mach/map.h>
 #include <mach/regs-clock.h>
@@ -116,6 +117,21 @@ static int s5pv310_clk_ip_perir_ctrl(struct clk *clk, int enable)
 	return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable);
 }
 
+static int s5pv310_clk_ip_dmc_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_DMC, clk, enable);
+}
+
+static int s5pv310_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int s5pv310_clk_ip_tv_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_TV, clk, enable);
+}
+
 /* Core list of CMU_CPU side */
 
 static struct clksrc_clk clk_mout_apll = {
@@ -422,6 +438,81 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5pv310_clk_ip_cam_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
+		.name           = "sysmmu",
+		.id             = S5P_SYSMMU_MFC_L,
+		.enable         = s5pv310_clk_ip_mfc_ctrl,
+		.ctrlbit        = ((15 << 1) | 1),
+	}, {
+		.name           = "sysmmu",
+		.id             = S5P_SYSMMU_MFC_R,
+		.enable         = s5pv310_clk_ip_mfc_ctrl,
+		.ctrlbit        = ((15 << 1) | 1),
+	}, {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC0,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC1,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 8),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC2,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 9),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMC3,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 10),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_JPEG,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 11),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_TV,
+		.enable		= s5pv310_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_G2D,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 3),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_ROTATOR,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_MDMA,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 5),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMD0,
+		.enable		= s5pv310_clk_ip_lcd0_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_FIMD1,
+		.enable		= s5pv310_clk_ip_lcd1_ctrl,
+		.ctrlbit	= (1 << 4),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_PCIe,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 18),
+	} , {
+		.name		= "sysmmu",
+		.id		= S5P_SYSMMU_SSS,
+		.enable		= s5pv310_clk_ip_dmc_ctrl,
+		.ctrlbit	= (1 << 12),
+	} , {
 		.name		= "fimd",
 		.id		= 0,
 		.enable		= s5pv310_clk_ip_lcd0_ctrl,
diff --git a/arch/arm/mach-s5pv310/dev-sysmmu.c b/arch/arm/mach-s5pv310/dev-sysmmu.c
dissimilarity index 86%
index e1bb200..73c1541 100644
--- a/arch/arm/mach-s5pv310/dev-sysmmu.c
+++ b/arch/arm/mach-s5pv310/dev-sysmmu.c
@@ -1,187 +1,395 @@
-/* linux/arch/arm/mach-s5pv310/dev-sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-
-#include <mach/map.h>
-#include <mach/irqs.h>
-
-static struct resource s5pv310_sysmmu_resource[] = {
-	[0] = {
-		.start	= S5PV310_PA_SYSMMU_MDMA,
-		.end	= S5PV310_PA_SYSMMU_MDMA + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_SYSMMU_MDMA0_0,
-		.end	= IRQ_SYSMMU_MDMA0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[2] = {
-		.start	= S5PV310_PA_SYSMMU_SSS,
-		.end	= S5PV310_PA_SYSMMU_SSS + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[3] = {
-		.start	= IRQ_SYSMMU_SSS_0,
-		.end	= IRQ_SYSMMU_SSS_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[4] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC0,
-		.end	= S5PV310_PA_SYSMMU_FIMC0 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[5] = {
-		.start	= IRQ_SYSMMU_FIMC0_0,
-		.end	= IRQ_SYSMMU_FIMC0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[6] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC1,
-		.end	= S5PV310_PA_SYSMMU_FIMC1 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[7] = {
-		.start	= IRQ_SYSMMU_FIMC1_0,
-		.end	= IRQ_SYSMMU_FIMC1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[8] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC2,
-		.end	= S5PV310_PA_SYSMMU_FIMC2 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[9] = {
-		.start	= IRQ_SYSMMU_FIMC2_0,
-		.end	= IRQ_SYSMMU_FIMC2_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[10] = {
-		.start	= S5PV310_PA_SYSMMU_FIMC3,
-		.end	= S5PV310_PA_SYSMMU_FIMC3 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[11] = {
-		.start	= IRQ_SYSMMU_FIMC3_0,
-		.end	= IRQ_SYSMMU_FIMC3_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[12] = {
-		.start	= S5PV310_PA_SYSMMU_JPEG,
-		.end	= S5PV310_PA_SYSMMU_JPEG + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[13] = {
-		.start	= IRQ_SYSMMU_JPEG_0,
-		.end	= IRQ_SYSMMU_JPEG_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[14] = {
-		.start	= S5PV310_PA_SYSMMU_FIMD0,
-		.end	= S5PV310_PA_SYSMMU_FIMD0 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[15] = {
-		.start	= IRQ_SYSMMU_LCD0_M0_0,
-		.end	= IRQ_SYSMMU_LCD0_M0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[16] = {
-		.start	= S5PV310_PA_SYSMMU_FIMD1,
-		.end	= S5PV310_PA_SYSMMU_FIMD1 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[17] = {
-		.start	= IRQ_SYSMMU_LCD1_M1_0,
-		.end	= IRQ_SYSMMU_LCD1_M1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[18] = {
-		.start	= S5PV310_PA_SYSMMU_PCIe,
-		.end	= S5PV310_PA_SYSMMU_PCIe + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[19] = {
-		.start	= IRQ_SYSMMU_PCIE_0,
-		.end	= IRQ_SYSMMU_PCIE_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[20] = {
-		.start	= S5PV310_PA_SYSMMU_G2D,
-		.end	= S5PV310_PA_SYSMMU_G2D + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[21] = {
-		.start	= IRQ_SYSMMU_2D_0,
-		.end	= IRQ_SYSMMU_2D_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[22] = {
-		.start	= S5PV310_PA_SYSMMU_ROTATOR,
-		.end	= S5PV310_PA_SYSMMU_ROTATOR + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[23] = {
-		.start	= IRQ_SYSMMU_ROTATOR_0,
-		.end	= IRQ_SYSMMU_ROTATOR_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[24] = {
-		.start	= S5PV310_PA_SYSMMU_MDMA2,
-		.end	= S5PV310_PA_SYSMMU_MDMA2 + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[25] = {
-		.start	= IRQ_SYSMMU_MDMA1_0,
-		.end	= IRQ_SYSMMU_MDMA1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[26] = {
-		.start	= S5PV310_PA_SYSMMU_TV,
-		.end	= S5PV310_PA_SYSMMU_TV + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[27] = {
-		.start	= IRQ_SYSMMU_TV_M0_0,
-		.end	= IRQ_SYSMMU_TV_M0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[28] = {
-		.start	= S5PV310_PA_SYSMMU_MFC_L,
-		.end	= S5PV310_PA_SYSMMU_MFC_L + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[29] = {
-		.start	= IRQ_SYSMMU_MFC_M0_0,
-		.end	= IRQ_SYSMMU_MFC_M0_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[30] = {
-		.start	= S5PV310_PA_SYSMMU_MFC_R,
-		.end	= S5PV310_PA_SYSMMU_MFC_R + SZ_64K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[31] = {
-		.start	= IRQ_SYSMMU_MFC_M1_0,
-		.end	= IRQ_SYSMMU_MFC_M1_0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device s5pv310_device_sysmmu = {
-	.name		= "s5p-sysmmu",
-	.id		= 32,
-	.num_resources	= ARRAY_SIZE(s5pv310_sysmmu_resource),
-	.resource	= s5pv310_sysmmu_resource,
-};
-
-EXPORT_SYMBOL(s5pv310_device_sysmmu);
+/* linux/arch/arm/mach-s5pv310/dev-sysmmu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/sysmmu.h>
+
+static struct resource s5p_sysmmu_resource[][2] = {
+	[S5P_SYSMMU_MDMA] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MDMA,
+			.end	= S5PV310_PA_SYSMMU_MDMA + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MDMA0,
+			.end	= IRQ_SYSMMU_MDMA0,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_SSS] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_SSS,
+			.end	= S5PV310_PA_SYSMMU_SSS + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_SSS,
+			.end	= IRQ_SYSMMU_SSS,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC0] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC0,
+			.end   = S5PV310_PA_SYSMMU_FIMC0 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC0,
+			.end   = IRQ_SYSMMU_FIMC0,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC1] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC1,
+			.end   = S5PV310_PA_SYSMMU_FIMC1 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC1,
+			.end   = IRQ_SYSMMU_FIMC1,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC2] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC2,
+			.end   = S5PV310_PA_SYSMMU_FIMC2 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC2,
+			.end   = IRQ_SYSMMU_FIMC2,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMC3] = {
+		[0] = {
+			.start = S5PV310_PA_SYSMMU_FIMC3,
+			.end   = S5PV310_PA_SYSMMU_FIMC3 + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		},
+		[1] = {
+			.start = IRQ_SYSMMU_FIMC3,
+			.end   = IRQ_SYSMMU_FIMC3,
+			.flags = IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_JPEG] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_JPEG,
+			.end	= S5PV310_PA_SYSMMU_JPEG + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_JPEG,
+			.end	= IRQ_SYSMMU_JPEG,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMD0] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_FIMD0,
+			.end	= S5PV310_PA_SYSMMU_FIMD0 + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_FIMD0,
+			.end	= IRQ_SYSMMU_FIMD0,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_FIMD1] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_FIMD1,
+			.end	= S5PV310_PA_SYSMMU_FIMD1 + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_FIMD1,
+			.end	= IRQ_SYSMMU_FIMD1,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_PCIe] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_PCIe,
+			.end	= S5PV310_PA_SYSMMU_PCIe + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_PCIE,
+			.end	= IRQ_SYSMMU_PCIE,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_G2D] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_G2D,
+			.end	= S5PV310_PA_SYSMMU_G2D + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_2D,
+			.end	= IRQ_SYSMMU_2D,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_ROTATOR] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_ROTATOR,
+			.end	= S5PV310_PA_SYSMMU_ROTATOR + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_ROTATOR,
+			.end	= IRQ_SYSMMU_ROTATOR,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_MDMA2] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MDMA2,
+			.end	= S5PV310_PA_SYSMMU_MDMA2 + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MDMA1,
+			.end	= IRQ_SYSMMU_MDMA1,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_TV] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_TV,
+			.end	= S5PV310_PA_SYSMMU_TV + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_TV,
+			.end	= IRQ_SYSMMU_TV,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_MFC_L] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MFC_L,
+			.end	= S5PV310_PA_SYSMMU_MFC_L + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MFC_L,
+			.end	= IRQ_SYSMMU_MFC_L,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+	[S5P_SYSMMU_MFC_R] = {
+		[0] = {
+			.start	= S5PV310_PA_SYSMMU_MFC_R,
+			.end	= S5PV310_PA_SYSMMU_MFC_R + SZ_4K - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+		[1] = {
+			.start	= IRQ_SYSMMU_MFC_R,
+			.end	= IRQ_SYSMMU_MFC_R,
+			.flags	= IORESOURCE_IRQ,
+		},
+	},
+};
+
+static u64 s5p_sysmmu_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv310_device_sysmmu[] = {
+	[S5P_SYSMMU_MDMA] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MDMA,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MDMA]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MDMA],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_SSS] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_SSS,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_SSS]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_SSS],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC0] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC0,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC0]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC0],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC1] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC1,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC1]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC1],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC2] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC2,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC2]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC2],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMC3] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMC3,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMC3]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMC3],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_JPEG] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_JPEG,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_JPEG]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_JPEG],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMD0] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMD0,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMD0]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMD0],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_FIMD1] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_FIMD1,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_FIMD1]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_FIMD1],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_PCIe] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_PCIe,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_PCIe]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_PCIe],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_G2D] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_G2D,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_G2D]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_G2D],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_ROTATOR] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_ROTATOR,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_ROTATOR]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_ROTATOR],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_MDMA2] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MDMA2,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MDMA2]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MDMA2],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_TV] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_TV,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_TV]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_TV],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_MFC_L] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MFC_L,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MFC_L]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MFC_L],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+	[S5P_SYSMMU_MFC_R] = {
+		.name		= "s5p-sysmmu",
+		.id		= S5P_SYSMMU_MFC_R,
+		.num_resources	= ARRAY_SIZE(
+					s5p_sysmmu_resource[S5P_SYSMMU_MFC_R]),
+		.resource	= s5p_sysmmu_resource[S5P_SYSMMU_MFC_R],
+		.dev		= {
+			.dma_mask		= &s5p_sysmmu_dma_mask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+		},
+	},
+};
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h
index 0e99968..f6b99c6 100644
--- a/arch/arm/mach-s5pv310/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv310/include/mach/irqs.h
@@ -55,23 +55,24 @@
 #define COMBINER_GROUP(x)	((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
 #define COMBINER_IRQ(x, y)	(COMBINER_GROUP(x) + y)
 
-#define IRQ_SYSMMU_MDMA0_0	COMBINER_IRQ(4, 0)
-#define IRQ_SYSMMU_SSS_0	COMBINER_IRQ(4, 1)
-#define IRQ_SYSMMU_FIMC0_0	COMBINER_IRQ(4, 2)
-#define IRQ_SYSMMU_FIMC1_0	COMBINER_IRQ(4, 3)
-#define IRQ_SYSMMU_FIMC2_0	COMBINER_IRQ(4, 4)
-#define IRQ_SYSMMU_FIMC3_0	COMBINER_IRQ(4, 5)
-#define IRQ_SYSMMU_JPEG_0	COMBINER_IRQ(4, 6)
-#define IRQ_SYSMMU_2D_0		COMBINER_IRQ(4, 7)
-
-#define IRQ_SYSMMU_ROTATOR_0	COMBINER_IRQ(5, 0)
-#define IRQ_SYSMMU_MDMA1_0	COMBINER_IRQ(5, 1)
-#define IRQ_SYSMMU_LCD0_M0_0	COMBINER_IRQ(5, 2)
-#define IRQ_SYSMMU_LCD1_M1_0	COMBINER_IRQ(5, 3)
-#define IRQ_SYSMMU_TV_M0_0	COMBINER_IRQ(5, 4)
-#define IRQ_SYSMMU_MFC_M0_0	COMBINER_IRQ(5, 5)
-#define IRQ_SYSMMU_MFC_M1_0	COMBINER_IRQ(5, 6)
-#define IRQ_SYSMMU_PCIE_0	COMBINER_IRQ(5, 7)
+#define IRQ_SYSMMU_MDMA0	COMBINER_IRQ(4, 0)
+#define IRQ_SYSMMU_SSS		COMBINER_IRQ(4, 1)
+#define IRQ_SYSMMU_FIMC0	COMBINER_IRQ(4, 2)
+#define IRQ_SYSMMU_FIMC1	COMBINER_IRQ(4, 3)
+#define IRQ_SYSMMU_FIMC2	COMBINER_IRQ(4, 4)
+#define IRQ_SYSMMU_FIMC3	COMBINER_IRQ(4, 5)
+#define IRQ_SYSMMU_JPEG		COMBINER_IRQ(4, 6)
+#define IRQ_SYSMMU_2D		COMBINER_IRQ(4, 7)
+
+#define IRQ_SYSMMU_ROTATOR	COMBINER_IRQ(5, 0)
+#define IRQ_SYSMMU_MDMA1	COMBINER_IRQ(5, 1)
+#define IRQ_SYSMMU_FIMD0	COMBINER_IRQ(5, 2)
+#define IRQ_SYSMMU_FIMD1	COMBINER_IRQ(5, 3)
+#define IRQ_SYSMMU_TV		COMBINER_IRQ(5, 4)
+#define IRQ_SYSMMU_MFC_L	COMBINER_IRQ(5, 5)
+#define IRQ_SYSMMU_MFC_R	COMBINER_IRQ(5, 6)
+#define IRQ_SYSMMU_PCIE		COMBINER_IRQ(5, 7)
+
 
 #define IRQ_PDMA0		COMBINER_IRQ(21, 0)
 #define IRQ_PDMA1		COMBINER_IRQ(21, 1)
@@ -147,4 +148,5 @@
 
 #define NR_IRQS			(S5P_IRQ_EINT_BASE + 32)
 
+
 #endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
index 341571a..9ef5f0c 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
@@ -67,6 +67,8 @@
 #define S5P_CLKDIV_STAT_TOP		S5P_CLKREG(0x0C610)
 
 #define S5P_CLKGATE_IP_CAM		S5P_CLKREG(0x0C920)
+#define S5P_CLKGATE_IP_MFC		S5P_CLKREG(0x0C928)
+#define S5P_CLKGATE_IP_TV		S5P_CLKREG(0x0C924)
 #define S5P_CLKGATE_IP_IMAGE		S5P_CLKREG(0x0C930)
 #define S5P_CLKGATE_IP_LCD0		S5P_CLKREG(0x0C934)
 #define S5P_CLKGATE_IP_LCD1		S5P_CLKREG(0x0C938)
@@ -78,6 +80,7 @@
 #define S5P_CLKSRC_DMC			S5P_CLKREG(0x10200)
 #define S5P_CLKDIV_DMC0			S5P_CLKREG(0x10500)
 #define S5P_CLKDIV_STAT_DMC0		S5P_CLKREG(0x10600)
+#define S5P_CLKGATE_IP_DMC		S5P_CLKREG(0x10900)
 
 #define S5P_APLL_LOCK			S5P_CLKREG(0x14000)
 #define S5P_MPLL_LOCK			S5P_CLKREG(0x14004)
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h b/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
index 0b28e81..dd2a954 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
@@ -13,12 +13,21 @@
 #ifndef __ASM_ARCH_REGS_SYSMMU_H
 #define __ASM_ARCH_REGS_SYSMMU_H __FILE__
 
-#define S5P_MMU_CTRL			0x000
-#define S5P_MMU_CFG			0x004
-#define S5P_MMU_STATUS			0x008
-#define S5P_MMU_FLUSH			0x00C
-#define S5P_PT_BASE_ADDR		0x014
-#define S5P_INT_STATUS			0x018
-#define S5P_PAGE_FAULT_ADDR		0x024
+#define S5P_MMU_CTRL		(0x000)
+#define S5P_MMU_CFG		(0x004)
+#define S5P_MMU_STATUS		(0x008)
+#define S5P_MMU_FLUSH		(0x00C)
+#define S5P_MMU_FLUSH_ENTRY	(0x010)
+#define S5P_PT_BASE_ADDR	(0x014)
+#define S5P_INT_STATUS		(0x018)
+#define S5P_INT_CLEAR		(0x01C)
+#define S5P_INT_MASK		(0x020)
+#define S5P_PAGE_FAULT_ADDR	(0x024)
+#define S5P_AW_FAULT_ADDR	(0x028)
+#define S5P_AR_FAULT_ADDR	(0x02C)
+#define S5P_DEFAULT_SLAVE_ADDR	(0x030)
+#define S5P_MMU_VERSION		(0x034)
+#define S5P_TLB_READ            (0x038)
+#define S5P_TLB_DATA            (0x03C)
 
 #endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/sysmmu.h b/arch/arm/mach-s5pv310/include/mach/sysmmu.h
deleted file mode 100644
index 598fc5c..0000000
--- a/arch/arm/mach-s5pv310/include/mach/sysmmu.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/sysmmu.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * Samsung sysmmu driver for S5PV310
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARM_ARCH_SYSMMU_H
-#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
-
-#define S5PV310_SYSMMU_TOTAL_IPNUM	16
-#define S5P_SYSMMU_TOTAL_IPNUM		S5PV310_SYSMMU_TOTAL_IPNUM
-
-enum s5pv310_sysmmu_ips {
-	SYSMMU_MDMA,
-	SYSMMU_SSS,
-	SYSMMU_FIMC0,
-	SYSMMU_FIMC1,
-	SYSMMU_FIMC2,
-	SYSMMU_FIMC3,
-	SYSMMU_JPEG,
-	SYSMMU_FIMD0,
-	SYSMMU_FIMD1,
-	SYSMMU_PCIe,
-	SYSMMU_G2D,
-	SYSMMU_ROTATOR,
-	SYSMMU_MDMA2,
-	SYSMMU_TV,
-	SYSMMU_MFC_L,
-	SYSMMU_MFC_R,
-};
-
-static char *sysmmu_ips_name[S5PV310_SYSMMU_TOTAL_IPNUM] = {
-	"SYSMMU_MDMA"	,
-	"SYSMMU_SSS"	,
-	"SYSMMU_FIMC0"	,
-	"SYSMMU_FIMC1"	,
-	"SYSMMU_FIMC2"	,
-	"SYSMMU_FIMC3"	,
-	"SYSMMU_JPEG"	,
-	"SYSMMU_FIMD0"	,
-	"SYSMMU_FIMD1"	,
-	"SYSMMU_PCIe"	,
-	"SYSMMU_G2D"	,
-	"SYSMMU_ROTATOR",
-	"SYSMMU_MDMA2"	,
-	"SYSMMU_TV"	,
-	"SYSMMU_MFC_L"	,
-	"SYSMMU_MFC_R"	,
-};
-
-typedef enum s5pv310_sysmmu_ips sysmmu_ips;
-
-struct sysmmu_tt_info {
-	unsigned long *pgd;
-	unsigned long pgd_paddr;
-	unsigned long *pte;
-};
-
-struct sysmmu_controller {
-	const char		*name;
-
-	/* channels registers */
-	void __iomem		*regs;
-
-	/* channel irq */
-	unsigned int		irq;
-
-	sysmmu_ips		ips;
-
-	/* Translation Table Info. */
-	struct sysmmu_tt_info	*tt_info;
-
-	struct resource		*mem;
-	struct device		*dev;
-
-	/* SysMMU controller enable - true : enable */
-	bool			enable;
-};
-
-/**
- * s5p_sysmmu_enable() - enable system mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function enable system mmu to transfer address
- * from virtual address to physical address
- */
-int s5p_sysmmu_enable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_disable() - disable sysmmu mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function disable system mmu to transfer address
- * from virtual address to physical address
- */
-int s5p_sysmmu_disable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
- * @ips: The ip connected system mmu.
- * @pgd: The page table base address.
- *
- * This function set page table base address
- * When system mmu transfer address from virtaul address to physical address,
- * system mmu refer address information from page table
- */
-int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
- * @ips: The ip connected system mmu.
- *
- * This function flush all TLB entry in system mmu
- */
-int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
-#endif /* __ASM_ARM_ARCH_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 0db2a7a..4166964 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -37,14 +37,6 @@ config S5P_GPIO_INT
 	help
 	  Common code for the GPIO interrupts (other than external interrupts.)
 
-comment "System MMU"
-
-config S5P_SYSTEM_MMU
-	bool "S5P SYSTEM MMU"
-	depends on ARCH_S5PV310
-	help
-	  Say Y here if you want to enable System MMU
-
 config S5P_DEV_FIMC0
 	bool
 	help
@@ -79,3 +71,12 @@ config S5P_DEV_CSIS1
 	bool
 	help
 	  Compile in platform device definitions for MIPI-CSIS channel 1
+
+comment "System MMU"
+
+config S5P_SYSTEM_MMU
+	bool "S5P SYSTEM MMU"
+	depends on ARCH_S5PV310
+	help
+	  Say Y here if you want to enable System MMU
+
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
new file mode 100644
index 0000000..9051af4
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/sysmmu.h
@@ -0,0 +1,127 @@
+/*
+ * sysmmu.h
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@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.
+ */
+#ifndef __S5P_SYSMMU_H__
+#define __S5P_SYSMMU_H__
+
+struct device;
+
+/**
+ * enum s5p_sysmmu_cmd - sysmmu control commands
+ * @S5P_SYSMMU_ENABLE_SHARED:	enable sysmmu, share page tables with ARM CPU
+ * @S5P_SYSMMU_ENABLE_PRIVATE:	enable sysmmu, use private page tables
+ * @S5P_SYSMMU_DISABLE:		disable sysmmu
+ * @S5P_SYSMMU_TLB_INVALIDATE:	invalidate sysmmu TLB contents
+ */
+enum s5p_sysmmu_cmd {
+	S5P_SYSMMU_ENABLE_SHARED,
+	S5P_SYSMMU_ENABLE_PRIVATE,
+	S5P_SYSMMU_DISABLE,
+	S5P_SYSMMU_TLB_INVALIDATE,
+};
+
+/**
+ * enum s5p_sysmmu_ip - integrated peripherals identifiers
+ * @S5P_SYSMMU_MDMA:	MDMA
+ * @S5P_SYSMMU_SSS:	SSS
+ * @S5P_SYSMMU_FIMC0:	FIMC0
+ * @S5P_SYSMMU_FIMC1:	FIMC1
+ * @S5P_SYSMMU_FIMC2:	FIMC2
+ * @S5P_SYSMMU_FIMC3:	FIMC3
+ * @S5P_SYSMMU_JPEG:	JPEG
+ * @S5P_SYSMMU_FIMD0:	FIMD0
+ * @S5P_SYSMMU_FIMD1:	FIMD1
+ * @S5P_SYSMMU_PCIe:	PCIe
+ * @S5P_SYSMMU_G2D:	G2D
+ * @S5P_SYSMMU_ROTATOR:	ROTATOR
+ * @S5P_SYSMMU_MDMA2:	MDMA2
+ * @S5P_SYSMMU_TV:	TV
+ * @S5P_SYSMMU_MFC_L:	MFC_L
+ * @S5P_SYSMMU_MFC_R:	MFC_R
+ */
+enum s5p_sysmmu_ip {
+	S5P_SYSMMU_MDMA,
+	S5P_SYSMMU_SSS,
+	S5P_SYSMMU_FIMC0,
+	S5P_SYSMMU_FIMC1,
+	S5P_SYSMMU_FIMC2,
+	S5P_SYSMMU_FIMC3,
+	S5P_SYSMMU_JPEG,
+	S5P_SYSMMU_FIMD0,
+	S5P_SYSMMU_FIMD1,
+	S5P_SYSMMU_PCIe,
+	S5P_SYSMMU_G2D,
+	S5P_SYSMMU_ROTATOR,
+	S5P_SYSMMU_MDMA2,
+	S5P_SYSMMU_TV,
+	S5P_SYSMMU_MFC_L,
+	S5P_SYSMMU_MFC_R,
+};
+
+/**
+ * s5p_sysmmu_get() - get sysmmu handle for a device
+ * @dev:	device which needs to use its sysmmu
+ * @ip:		integrated peripheral identifier of the device
+ */
+void *s5p_sysmmu_get(struct device *dev, enum s5p_sysmmu_ip ip);
+
+/**
+ * s5p_sysmmu_put() - release sysmmu handle for a device
+ * @dev_id:	sysmmu handle obtained from s5p_sysmmu_get()
+ */
+void s5p_sysmmu_put(void *dev_id);
+
+/**
+ * s5p_sysmmu_control() - control a sysmmu
+ * @dev_id:	sysmmu handle obtained from s5p_sysmmu_get()
+ * @cmd:	command to perform
+ */
+int s5p_sysmmu_control(void *dev_id, enum s5p_sysmmu_cmd cmd);
+
+/**
+ * s5p_sysmmu_map_area() - map an area of device's virtual memory,
+ 			underlying memory is described by struct pages
+ * @dev_id:		sysmmu handle obtained from s5p_sysmmu_get()
+ * @varea_start:	beginning virtual address of the mapped area,
+ *			must be page aligned
+ * @num_pages:		number of pages to map starting from varea_start
+ * @pages:		an array of struct page pointers representing
+ *			the physical pages which will be mapped
+ */
+int s5p_sysmmu_map_area(void *dev_id, unsigned long varea_start,
+			unsigned long num_pages, struct page **pages);
+
+/**
+ * s5p_sysmmu_map_phys_area() - map an area of device's virtual memory,
+ *			underlying memory is a physically contiguous block
+ * @dev_id:		sysmmu handle obtained from s5p_sysmmu_get()
+ * @varea_start:	beginning virtual address of the mapped area,
+ *			must be page aligned
+ * @phys_area_start:	beginning physical adddress of the underlying memory
+ * @num_pages:		number of pages to map starting from phys_area_start
+ */
+int s5p_sysmmu_map_phys_area(void *dev_id, unsigned long varea_start,
+			     unsigned long phys_area_start,
+			     unsigned long num_pages);
+
+/**
+ * s5p_sysmmu_unmap_area() - unmap an area of device's virtual memory
+ * @dev_id:		sysmmu handle obtained from s5p_sysmmu_get()
+ * @varea_start:	beginning virtual address of the mapped area,
+ *			must be page aligned and correspond to the address
+ * 			used while mapping
+ * @num_pages:		number of pages to unmap starting from phys_area_start,
+ *			must correspond to the number used while mapping
+ */
+void s5p_sysmmu_unmap_area(void *dev_id, unsigned long varea_start,
+			   unsigned long num_pages);
+
+#endif /* __S5P_SYSMMU_H__ */
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
dissimilarity index 85%
index ffe8a48..45adbf4 100644
--- a/arch/arm/plat-s5p/sysmmu.c
+++ b/arch/arm/plat-s5p/sysmmu.c
@@ -1,326 +1,662 @@
-/* linux/arch/arm/plat-s5p/sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <mach/map.h>
-#include <mach/regs-sysmmu.h>
-#include <mach/sysmmu.h>
-
-struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
-
-void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
-{
-	unsigned int reg_mmu_ctrl;
-	unsigned int reg_mmu_status;
-	unsigned int reg_pt_base_addr;
-	unsigned int reg_int_status;
-	unsigned int reg_page_ft_addr;
-
-	reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
-	reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
-	reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
-	reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
-
-	printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
-	printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
-	printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
-	printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
-
-	switch (reg_int_status & 0xFF) {
-	case 0x1:
-		printk(KERN_INFO "%s: Page fault\n", __func__);
-		printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
-		break;
-	case 0x2:
-		printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
-		break;
-	case 0x4:
-		printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
-		break;
-	case 0x8:
-		printk(KERN_INFO "%s: Bus error\n", __func__);
-		break;
-	case 0x10:
-		printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
-		break;
-	case 0x20:
-		printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
-		break;
-	case 0x40:
-		printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
-		break;
-	case 0x80:
-		printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
-		break;
-	}
-}
-
-static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
-{
-	unsigned int i;
-	unsigned int reg_int_status;
-	struct sysmmu_controller *sysmmuconp;
-
-	for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
-		sysmmuconp = &s5p_sysmmu_cntlrs[i];
-
-		if (sysmmuconp->enable == true) {
-			reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
-
-			if (reg_int_status & 0xFF)
-				s5p_sysmmu_register(sysmmuconp);
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
-{
-	struct sysmmu_controller *sysmmuconp = NULL;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	/* Set sysmmu page table base address */
-	__raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
-
-	if (s5p_sysmmu_tlb_invalidate(ips) != 0)
-		printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
-
-	return 0;
-}
-
-static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
-{
-	unsigned int pg;
-	struct sysmmu_controller *sysmmuconp;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	__asm__("mrc	p15, 0, %0, c2, c0, 0"	\
-		: "=r" (pg) : : "cc");		\
-		pg &= ~0x3fff;
-
-	printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
-
-	/* Set sysmmu page table base address */
-	__raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
-
-	return 0;
-}
-
-int s5p_sysmmu_enable(sysmmu_ips ips)
-{
-	unsigned int reg;
-
-	struct sysmmu_controller *sysmmuconp;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	s5p_sysmmu_set_tablebase(ips);
-
-	/* replacement policy : LRU */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
-	reg |= 0x1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
-
-	/* Enable interrupt, Enable MMU */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg |= (0x1 << 2) | (0x1 << 0);
-
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	sysmmuconp->enable = true;
-
-	return 0;
-}
-
-int s5p_sysmmu_disable(sysmmu_ips ips)
-{
-	unsigned int reg;
-
-	struct sysmmu_controller *sysmmuconp = NULL;
-
-	if (ips > S5P_SYSMMU_TOTAL_IPNUM)
-		printk(KERN_ERR "failed to get ips parameter\n");
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
-
-	/* replacement policy : LRU */
-	reg |= 0x1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
-
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-
-	/* Disable MMU */
-	reg &= ~0x1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	sysmmuconp->enable = false;
-
-	return 0;
-}
-
-int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
-	unsigned int reg;
-	struct sysmmu_controller *sysmmuconp = NULL;
-
-	sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
-	if (sysmmuconp == NULL) {
-		printk(KERN_ERR "failed to get ip's sysmmu info\n");
-		return 1;
-	}
-
-	/* set Block MMU for flush TLB */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg |= 0x1 << 1;
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	/* flush all TLB entry */
-	__raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH);
-
-	/* set Un-block MMU after flush TLB */
-	reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
-	reg &= ~(0x1 << 1);
-	__raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
-	return 0;
-}
-
-static int s5p_sysmmu_probe(struct platform_device *pdev)
-{
-	int i;
-	int ret;
-	struct resource *res;
-	struct sysmmu_controller *sysmmuconp;
-	sysmmu_ips ips;
-
-	for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
-		sysmmuconp = &s5p_sysmmu_cntlrs[i];
-		if (sysmmuconp == NULL) {
-			printk(KERN_ERR "failed to get ip's sysmmu info\n");
-			ret = -ENOENT;
-			goto err_res;
-		}
-
-		sysmmuconp->name = sysmmu_ips_name[i];
-
-		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res) {
-			printk(KERN_ERR "failed to get sysmmu resource\n");
-			ret = -ENODEV;
-			goto err_res;
-		}
-
-		sysmmuconp->mem = request_mem_region(res->start,
-				((res->end) - (res->start)) + 1, pdev->name);
-		if (!sysmmuconp->mem) {
-			pr_err("failed to request sysmmu memory region\n");
-			ret = -EBUSY;
-			goto err_res;
-		}
-
-		sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1);
-		if (!sysmmuconp->regs) {
-			pr_err("failed to sysmmu ioremap\n");
-			ret = -ENXIO;
-			goto err_reg;
-		}
-
-		sysmmuconp->irq = platform_get_irq(pdev, i);
-		if (sysmmuconp->irq <= 0) {
-			pr_err("failed to get sysmmu irq resource\n");
-			ret = -ENOENT;
-			goto err_map;
-		}
-
-		ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp);
-		if (ret) {
-			pr_err("failed to request irq\n");
-			ret = -ENOENT;
-			goto err_map;
-		}
-
-		ips = (sysmmu_ips)i;
-
-		sysmmuconp->ips = ips;
-	}
-
-	return 0;
-
-err_reg:
-	release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
-err_map:
-	iounmap(sysmmuconp->regs);
-err_res:
-	return ret;
-}
-
-static int s5p_sysmmu_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-int s5p_sysmmu_runtime_suspend(struct device *dev)
-{
-	return 0;
-}
-
-int s5p_sysmmu_runtime_resume(struct device *dev)
-{
-	return 0;
-}
-
-const struct dev_pm_ops s5p_sysmmu_pm_ops = {
-	.runtime_suspend	= s5p_sysmmu_runtime_suspend,
-	.runtime_resume		= s5p_sysmmu_runtime_resume,
-};
-
-static struct platform_driver s5p_sysmmu_driver = {
-	.probe		= s5p_sysmmu_probe,
-	.remove		= s5p_sysmmu_remove,
-	.driver		= {
-		.owner		= THIS_MODULE,
-		.name		= "s5p-sysmmu",
-		.pm		= &s5p_sysmmu_pm_ops,
-	}
-};
-
-static int __init s5p_sysmmu_init(void)
-{
-	return platform_driver_register(&s5p_sysmmu_driver);
-}
-arch_initcall(s5p_sysmmu_init);
+/* linux/arch/arm/plat-s5p/sysmmu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+
+#include <asm/memory.h>
+
+#include <plat/irqs.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/sysmmu.h>
+
+#include <mach/map.h>
+#include <mach/regs-sysmmu.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define sysmmu_debug(level, fmt, arg...)				 \
+	do {								 \
+		if (debug >= level)					 \
+			printk(KERN_DEBUG "[%s] " fmt, __func__, ## arg);\
+	} while (0)
+
+struct s5p_sysmmu_info {
+	struct mutex		mutex;
+	struct resource		*ioarea;
+	void __iomem		*regs;
+	unsigned int		irq;
+	struct clk		*clk;
+	bool			enabled;
+	bool			page_tables_allocated;
+	enum s5p_sysmmu_ip	ip;
+	enum s5p_sysmmu_cmd	mode;
+
+	unsigned long		flpt;
+	unsigned long		flpt_vaddr;
+	/* one table entry per 4 entries of the first level page table */
+	unsigned long		*vaddr;
+	/* one table entry per 4 entries of the first level page table */
+	u16			*refcount;
+
+	struct device		*dev;
+
+	struct list_head	entry;
+};
+
+static LIST_HEAD(sysmmu_list);
+static DEFINE_SPINLOCK(sysmmu_list_slock);
+
+void *s5p_sysmmu_get(struct device *dev, enum s5p_sysmmu_ip ip)
+{
+	struct s5p_sysmmu_info *ret;
+	unsigned long flags;
+
+	sysmmu_debug(3, "for %s\n", dev_name(dev));
+
+	spin_lock_irqsave(&sysmmu_list_slock, flags);
+	list_for_each_entry(ret, &sysmmu_list, entry) {
+		if (ret->ip == ip) {
+			try_module_get(THIS_MODULE);
+			spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+			return ret;
+		}
+	}
+	spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_get);
+
+void s5p_sysmmu_put(void *dev_id)
+{
+	module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_put);
+
+static void s5p_sysmmu_configure(struct s5p_sysmmu_info *sysmmu,
+				 unsigned long pg)
+{
+	unsigned int reg;
+
+	writel(pg, sysmmu->regs + S5P_PT_BASE_ADDR);
+
+	reg = readl(sysmmu->regs + S5P_MMU_CFG);
+	reg |= (0x1<<0);		/* replacement policy : LRU */
+	writel(reg, sysmmu->regs + S5P_MMU_CFG);
+
+	reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+	reg |= ((0x1<<2)|(0x1<<0));	/* Enable interrupt, Enable MMU */
+	writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+
+	sysmmu_debug(3, "CFG:0x%x\n", readl(sysmmu->regs + S5P_MMU_CFG));
+	sysmmu_debug(3, "CTRL:0x%x\n", readl(sysmmu->regs + S5P_MMU_CTRL));
+	sysmmu_debug(3, "STATUS:0x%x\n", readl(sysmmu->regs + S5P_MMU_STATUS));
+
+	sysmmu->enabled = true;
+}
+
+static int s5p_sysmmu_control_locked(struct s5p_sysmmu_info *sysmmu,
+				     enum s5p_sysmmu_cmd cmd)
+{
+	unsigned int pg, reg;
+
+	sysmmu_debug(3, "%d\n", cmd);
+
+	sysmmu->mode = cmd;
+
+	switch (cmd) {
+	case S5P_SYSMMU_ENABLE_SHARED:
+		/*
+		 * coprocessor 15 == mmu;
+		 * copy system page tables base from there
+		 */
+		__asm__("mrc p15, 0, %0, c2, c0, 0" : "=r" (pg) : : "cc");
+		pg &= ~0x3fff;
+
+		s5p_sysmmu_configure(sysmmu, pg);
+
+		return 0;
+	break;
+
+	case S5P_SYSMMU_ENABLE_PRIVATE:
+		pm_runtime_get_sync(sysmmu->dev);
+		if (!sysmmu->page_tables_allocated) {
+			/*
+			 * first-level page table holds
+			 * 4k second-level descriptors == 16kB == 4 pages
+			 */
+			sysmmu->flpt_vaddr = (unsigned long)dma_alloc_coherent(
+				sysmmu->dev,
+				4 * PAGE_SIZE,
+				(dma_addr_t *)&sysmmu->flpt,
+				GFP_KERNEL | __GFP_ZERO);
+			if (!sysmmu->flpt_vaddr)
+				return -ENOMEM;
+
+			sysmmu->refcount = kzalloc(1024 * sizeof(u16),
+						   GFP_KERNEL);
+			if (!sysmmu->refcount) {
+				dma_free_coherent(sysmmu->dev, 4 * PAGE_SIZE,
+					(dma_addr_t *)sysmmu->flpt_vaddr,
+					sysmmu->flpt);
+				return -ENOMEM;
+			}
+
+			sysmmu->vaddr = kzalloc(1024 * sizeof(unsigned long),
+						GFP_KERNEL);
+			if (!sysmmu->vaddr) {
+				kfree(sysmmu->refcount);
+				dma_free_coherent(sysmmu->dev, 4 * PAGE_SIZE,
+					(void *)sysmmu->flpt_vaddr,
+					sysmmu->flpt);
+				return -ENOMEM;
+			}
+			sysmmu->page_tables_allocated = true;
+		}
+		s5p_sysmmu_configure(sysmmu, sysmmu->flpt);
+
+		return 0;
+	break;
+
+	case S5P_SYSMMU_DISABLE:
+		reg = readl(sysmmu->regs + S5P_MMU_CFG);
+		reg |= (0x1<<0);		/* replacement policy : LRU */
+		writel(reg, sysmmu->regs + S5P_MMU_CFG);
+
+		reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+		reg &= ~(0x1);			/* Disable MMU */
+		writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+		sysmmu->enabled = false;
+ 		pm_runtime_put_sync(sysmmu->dev);
+		return 0;
+	break;
+
+	case S5P_SYSMMU_TLB_INVALIDATE:
+		reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+		reg |= (0x1<<1);		/* Block MMU */
+		writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+
+		writel(0x1, sysmmu->regs + S5P_MMU_FLUSH);
+						/* Flush_entry */
+
+		reg = readl(sysmmu->regs + S5P_MMU_CTRL);
+		reg &= ~(0x1<<1);		/* Un-block MMU */
+		writel(reg, sysmmu->regs + S5P_MMU_CTRL);
+		return 0;
+	break;
+
+	default:
+		;
+	}
+	return -EINVAL;
+}
+
+int s5p_sysmmu_control(void *dev_id, enum s5p_sysmmu_cmd cmd)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	int ret;
+
+	mutex_lock(&sysmmu->mutex);
+	ret = s5p_sysmmu_control_locked(sysmmu, cmd);
+	mutex_unlock(&sysmmu->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_control);
+
+#define dereference_vaddr(vaddr) (*((unsigned long *)(vaddr)))
+
+#define make_flpt_entry(slpt, k) \
+	((((slpt) + (k) * 256 * 4) & ~0x3FF) | 0x1)
+#define make_slpt_phys_entry(phys) (((phys) & ~0xFFF) | 0x2)
+
+#define flpt_offset(vaddr) (((vaddr) >> 18) & 0x3FFC)
+#define slpt_offset(slpt, vaddr) \
+	(((slpt) & (0x3 << 10)) + (((vaddr) >> 10) & 0x3FC))
+
+#define slpt_number(vaddr) (((vaddr) >> 22) & 0x3FF)
+
+#define get_slpt(flpt_entry_vaddr) \
+	(dereference_vaddr(flpt_entry_vaddr) & ~0x3FF)
+#define get_slpt_four(flpt_entry_vaddr) \
+	(dereference_vaddr(flpt_entry_vaddr) & ~0xFFF)
+
+#define invalidate_slpt_entry(slpt_entry_vaddr) \
+	(dereference_vaddr(slpt_entry_vaddr) &= ~0x3)
+
+/*
+ * vaddr:
+ * X X X X X X X X X X X X  X X X X X X X X  X X X X X X X X X X 0 0
+ * 31--------------------20 19------------12 11--------------------0
+ *     index into flpt       idx into slpt      offset within page
+ */
+static int s5p_sysmmu_map_page(struct s5p_sysmmu_info *sysmmu,
+	   		       unsigned long vaddr, unsigned long paddr)
+{
+	unsigned long flpt_entry_vaddr, slpt_entry_vaddr, slpt, slpt_vaddr;
+	int four_entry = slpt_number(vaddr);
+
+	flpt_entry_vaddr = sysmmu->flpt_vaddr + flpt_offset(vaddr);
+	if (0 == dereference_vaddr(flpt_entry_vaddr)) {
+		int k;
+		unsigned long flpt_four = flpt_entry_vaddr & ~0xF;
+
+		slpt_vaddr = (unsigned long)dma_alloc_coherent(
+			sysmmu->dev,
+			PAGE_SIZE,
+			(dma_addr_t *)&slpt,
+			GFP_KERNEL | __GFP_ZERO);
+		if (!slpt_vaddr)
+			return -1;
+
+		sysmmu->vaddr[four_entry] = slpt_vaddr;
+
+		for (k = 0; k < 4; ++k)
+			dereference_vaddr(flpt_four + 4 * k) =
+						make_flpt_entry(slpt, k);
+
+		sysmmu_debug(3, "4-entry:%d\n", four_entry);
+	}
+	slpt = get_slpt(flpt_entry_vaddr);
+	slpt_entry_vaddr = sysmmu->vaddr[four_entry] + slpt_offset(slpt, vaddr);
+	dereference_vaddr(slpt_entry_vaddr) = make_slpt_phys_entry(paddr);
+	sysmmu->refcount[four_entry]++;
+
+	return 0;
+}
+
+static void s5p_unmap_page(struct s5p_sysmmu_info *sysmmu, unsigned long vaddr)
+{
+	unsigned long flpt_entry_vaddr, slpt_entry_vaddr, slpt;
+	int four_entry = slpt_number(vaddr);
+
+	flpt_entry_vaddr = sysmmu->flpt_vaddr + flpt_offset(vaddr);
+	if (--sysmmu->refcount[four_entry]) {
+		slpt = get_slpt(flpt_entry_vaddr);
+		slpt_entry_vaddr = sysmmu->vaddr[four_entry] +
+				slpt_offset(slpt, vaddr);
+		invalidate_slpt_entry(slpt_entry_vaddr);
+	} else {
+		dma_free_coherent(sysmmu->dev, PAGE_SIZE,
+			(void *)sysmmu->vaddr[four_entry],
+			get_slpt_four(flpt_entry_vaddr));
+
+		memset((void *)(flpt_entry_vaddr & ~0xF), 0, 16);
+
+		sysmmu->vaddr[four_entry] = 0;
+	}
+}
+
+int s5p_sysmmu_map_area(void *dev_id, unsigned long varea_start,
+			unsigned long num_pages, struct page **pages)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	int i, ret;
+
+	sysmmu_debug(3, "varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	mutex_lock(&sysmmu->mutex);
+	for (i = 0; i < num_pages; varea_start += PAGE_SIZE, ++i) {
+		ret = s5p_sysmmu_map_page(sysmmu,
+				     varea_start, page_to_phys(pages[i]));
+		if (ret < 0)
+			goto slpt_pg_alloc_fail;
+	}
+
+	mutex_unlock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "MAPPING DONE for varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start - num_pages * PAGE_SIZE, num_pages);
+
+	return 0;
+
+slpt_pg_alloc_fail:
+	while (--i >= 0) {
+		varea_start -= PAGE_SIZE;
+		s5p_unmap_page(sysmmu, varea_start);
+	}
+	s5p_sysmmu_control_locked(sysmmu, S5P_SYSMMU_TLB_INVALIDATE);
+	mutex_unlock(&sysmmu->mutex);
+	return -1;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_map_area);
+
+int s5p_sysmmu_map_phys_area(void *dev_id, unsigned long varea_start,
+			unsigned long phys_area_start, unsigned long num_pages)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	int i;
+
+	sysmmu_debug(3, "varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	mutex_lock(&sysmmu->mutex);
+	for (i = 0; i < num_pages;
+		varea_start += PAGE_SIZE, phys_area_start += PAGE_SIZE, ++i)
+		if (s5p_sysmmu_map_page(sysmmu, varea_start, phys_area_start) < 0)
+			goto slpt_pg_alloc_fail;
+
+	mutex_unlock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "MAPPING DONE for varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start - num_pages * PAGE_SIZE, num_pages);
+
+	return 0;
+
+slpt_pg_alloc_fail:
+	while (--i >= 0) {
+		varea_start -= PAGE_SIZE;
+		s5p_unmap_page(sysmmu, varea_start);
+	}
+	s5p_sysmmu_control_locked(sysmmu, S5P_SYSMMU_TLB_INVALIDATE);
+	mutex_unlock(&sysmmu->mutex);
+	return -1;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_map_phys_area);
+
+void s5p_sysmmu_unmap_area(void *dev_id, unsigned long varea_start,
+			   unsigned long num_pages)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	unsigned long vaddr = varea_start;
+	int i;
+
+	mutex_lock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	for (i = 0; i < num_pages; vaddr += PAGE_SIZE, ++i)
+		s5p_unmap_page(sysmmu, vaddr);
+
+	s5p_sysmmu_control_locked(sysmmu, S5P_SYSMMU_TLB_INVALIDATE);
+	mutex_unlock(&sysmmu->mutex);
+
+	sysmmu_debug(3, "UNMAPPING DONE for varea_start:0x%lx, num_pages:%ld\n",
+		     varea_start, num_pages);
+
+	return;
+}
+EXPORT_SYMBOL_GPL(s5p_sysmmu_unmap_area);
+
+static void s5p_sysmmu_pg_fault(struct s5p_sysmmu_info *sysmmu)
+{
+	void __iomem *regbase = sysmmu->regs;
+	unsigned long fault;
+
+	fault = readl(regbase + S5P_PAGE_FAULT_ADDR);
+	sysmmu_debug(3, "Page fault occured for virtual address 0x%08lx\n",
+		     fault);
+}
+
+static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
+{
+	struct s5p_sysmmu_info *sysmmu = dev_id;
+	unsigned int reg_INT_STATUS;
+
+	if (false == sysmmu->enabled)
+		return IRQ_HANDLED;
+
+	reg_INT_STATUS = readl(sysmmu->regs + S5P_INT_STATUS);
+	if (reg_INT_STATUS & 0xFF) {
+		switch (reg_INT_STATUS & 0xFF) {
+		case 0x1:
+			/* page fault */
+			sysmmu_debug(3, "irq:pg fault\n");
+			s5p_sysmmu_pg_fault(sysmmu);
+			break;
+		case 0x2:
+			/* AR multi-hit fault */
+			sysmmu_debug(3, "irq:ar multi hit\n");
+			break;
+		case 0x4:
+			/* AW multi-hit fault */
+			sysmmu_debug(3, "irq:aw multi hit\n");
+			break;
+		case 0x8:
+			/* bus error */
+			sysmmu_debug(3, "irq:bus error\n");
+			break;
+		case 0x10:
+			/* AR security protection fault */
+			sysmmu_debug(3, "irq:ar security protection fault\n");
+			break;
+		case 0x20:
+			/* AR access protection fault */
+			sysmmu_debug(3, "irq:ar access protection fault\n");
+			break;
+		case 0x40:
+			/* AW security protection fault */
+			sysmmu_debug(3, "irq:aw security protection fault\n");
+			break;
+		case 0x80:
+			/* AW access protection fault */
+			sysmmu_debug(3, "irq:aw access protection fault\n");
+			break;
+		}
+		writel(reg_INT_STATUS, sysmmu->regs + S5P_INT_CLEAR);
+	}
+	return IRQ_HANDLED;
+}
+
+static int s5p_sysmmu_probe(struct platform_device *pdev)
+{
+	struct s5p_sysmmu_info *sysmmu;
+	struct resource *res;
+	int ret;
+	unsigned long flags;
+
+	sysmmu = kzalloc(sizeof(struct s5p_sysmmu_info), GFP_KERNEL);
+	if (!sysmmu) {
+		dev_err(&pdev->dev, "no memory for state\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (NULL == res) {
+		dev_err(&pdev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err_s5p_sysmmu_info_allocated;
+	}
+
+	sysmmu->ioarea = request_mem_region(res->start, resource_size(res),
+					 pdev->name);
+
+	if (NULL == sysmmu->ioarea) {
+		dev_err(&pdev->dev, "cannot request IO\n");
+		ret = -ENXIO;
+		goto err_s5p_sysmmu_info_allocated;
+	}
+
+	sysmmu->regs = ioremap(res->start, resource_size(res));
+
+	if (NULL == sysmmu->regs) {
+		dev_err(&pdev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_ioarea_requested;
+	}
+
+	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+		sysmmu->regs, sysmmu->ioarea, res);
+
+	sysmmu->irq = ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "cannot find IRQ\n");
+		goto err_iomap_done;
+	}
+
+	ret = request_irq(sysmmu->irq, s5p_sysmmu_irq, 0,
+			  dev_name(&pdev->dev), sysmmu);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot claim IRQ %d\n", sysmmu->irq);
+		goto err_iomap_done;
+	}
+
+	sysmmu->clk = clk_get(&pdev->dev, "sysmmu");
+	if (IS_ERR_OR_NULL(sysmmu->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		ret = -ENOENT;
+		goto err_request_irq_done;
+	}
+	dev_dbg(&pdev->dev, "clock source %p\n", sysmmu->clk);
+	clk_enable(sysmmu->clk);
+
+	sysmmu->ip = pdev->id;
+
+	spin_lock_irqsave(&sysmmu_list_slock, flags);
+	list_add(&sysmmu->entry, &sysmmu_list);
+	spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+
+	sysmmu->dev = &pdev->dev;
+
+	mutex_init(&sysmmu->mutex);
+
+	platform_set_drvdata(pdev, sysmmu);
+
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	dev_info(&pdev->dev, "Samsung S5P SYSMMU (IOMMU)\n");
+	return 0;
+
+err_request_irq_done:
+	free_irq(sysmmu->irq, sysmmu);
+
+err_iomap_done:
+	iounmap(sysmmu->regs);
+
+err_ioarea_requested:
+	release_resource(sysmmu->ioarea);
+	kfree(sysmmu->ioarea);
+
+err_s5p_sysmmu_info_allocated:
+	kfree(sysmmu);
+	return ret;
+}
+
+static int s5p_sysmmu_remove(struct platform_device *pdev)
+{
+	struct s5p_sysmmu_info *sysmmu = platform_get_drvdata(pdev);
+	unsigned long flags;
+	int i = 1024;
+
+ 	pm_runtime_disable(sysmmu->dev);
+
+	if ((S5P_SYSMMU_ENABLE_PRIVATE == sysmmu->mode)) {
+		while (i >= 0) {
+			if (sysmmu->refcount[i]) {
+				unsigned long flpt_entry;
+				flpt_entry = dereference_vaddr(
+					sysmmu->flpt_vaddr + 4 * 4 * i);
+				dma_free_coherent(sysmmu->dev,
+					PAGE_SIZE,
+					(void *)sysmmu->vaddr[i],
+					flpt_entry & ~0xFFF);
+			}
+			--i;
+		}
+
+		if (sysmmu->flpt) {
+			dma_free_coherent(sysmmu->dev, 4 * PAGE_SIZE,
+				(void *)sysmmu->flpt_vaddr, sysmmu->flpt);
+		}
+		kfree(sysmmu->refcount);
+		kfree(sysmmu->vaddr);
+	}
+
+	spin_lock_irqsave(&sysmmu_list_slock, flags);
+	list_del(&sysmmu->entry);
+	spin_unlock_irqrestore(&sysmmu_list_slock, flags);
+
+	clk_disable(sysmmu->clk);
+	clk_put(sysmmu->clk);
+
+	free_irq(sysmmu->irq, sysmmu);
+
+	iounmap(sysmmu->regs);
+
+	release_resource(sysmmu->ioarea);
+	kfree(sysmmu->ioarea);
+
+	kfree(sysmmu);
+
+	return 0;
+}
+
+static int s5p_sysmmu_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int s5p_sysmmu_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static int s5p_sysmmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+static int s5p_sysmmu_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops s5p_sysmmu_pm_ops = {
+	.runtime_suspend = s5p_sysmmu_runtime_suspend,
+	.runtime_resume	 = s5p_sysmmu_runtime_resume,
+};
+
+static struct platform_driver s5p_sysmmu_driver = {
+	.probe = s5p_sysmmu_probe,
+	.remove = s5p_sysmmu_remove,
+	.suspend = s5p_sysmmu_suspend,
+	.resume = s5p_sysmmu_resume,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "s5p-sysmmu",
+		.pm = &s5p_sysmmu_pm_ops,
+	},
+};
+
+static int __init s5p_sysmmu_register(void)
+{
+	return platform_driver_register(&s5p_sysmmu_driver);
+}
+
+static void __exit s5p_sysmmu_unregister(void)
+{
+	platform_driver_unregister(&s5p_sysmmu_driver);
+}
+
+module_init(s5p_sysmmu_register);
+module_exit(s5p_sysmmu_unregister);
+
+MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_DESCRIPTION("Samsung System MMU (IOMMU) driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index b0123f3..9f42dee 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -138,7 +138,7 @@ extern struct platform_device s5p_device_fimc3;
 extern struct platform_device s5p_device_mipi_csis0;
 extern struct platform_device s5p_device_mipi_csis1;
 
-extern struct platform_device s5pv310_device_sysmmu;
+extern struct platform_device s5pv310_device_sysmmu[];
 
 /* s3c2440 specific devices */
 
-- 
1.7.1.569.g6f426

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update
  2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
                   ` (6 preceding siblings ...)
  2011-03-04  9:01 ` [PATCH 7/7] ARM: S5PC210: enable FIMC on Universal_C210 Marek Szyprowski
@ 2011-03-08  7:28 ` Kukjin Kim
  2011-03-08  9:34   ` Marek Szyprowski
  7 siblings, 1 reply; 29+ messages in thread
From: Kukjin Kim @ 2011-03-08  7:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

There are comments for your System MMU driver below.

It's good that System MMU has functionality of mapping but System MMU have
to use other mapping of virtual memory allocator.

And would be better to change sysmmu_list to use array of defined in
s5p_sysmmu_ip enumeration, so that can get enhancement of memory space
usage, speed, and readability of codes.

TLB replacement policy does not need to use LRU. Of course, current System
MMU also needs it. I think, the round robin is enough, because to access
memory has no temporal locality and to make LRU need to access to System
MMU register one more. The reset value is round robin.

In the setting of SHARED page table in s5p_sysmmu_control_locked, get the
page table base address of ARM core from cp15 register now. But current->mm-
>pgd is better for more compatibility.

When it make page table with PRIVATE page table methods, the size of the
structure to manage the second page table is quite big. It is much better
rather that to make slab with cache size of 1KB.
Besides, the page mapping implementation is not safe in your System MMU
driver. Because only first one confirms primary page table entry, when it
assigns four second page tables consecutively at a time.

The System MMU driver cannot apply runtime pm by oneself with calling
pm_runtime_put_sync(). The reason is because a device with System MMU can
on/off power. I think just clock gating is enough. However, I can't find
clock enable/disable in your driver.

By PRIVATE page table method, each system MMU comes to have a page table
only for oneself. In this case, the problem is that each MFC System MMU L
and R having another page table.

In your System MMU driver, the page size is always 4KB crucially. This says
TLB thrashing and produces a result to lose a TLB hit rate. It is a big
problem with the device such as rotator which does not do sequential access
especially.

And the IRQ handler just outputs only a message. It should be implemented
in call back function to be able to handle from each device driver.

When it sets System MMU in SHARED page table, kernel virtual memory is
broken by a method such as s5p_sysmmu_map_area() :(

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.


Marek Szyprowski wrote:
> 
> Hello,
> 
> This patch series introduces new type of videbuf2 memory allocator -
> vb2-s5p-iommu. This allocator can be used only on Samsung SoCs that have
> IOMMU module. Currently only Samsung EXYNOS4 (former S5PV310) platform
> has SYSMMU modules. The allocator is then used by s5p-fimc driver. To
> make it possible some additional changes are required. Mainly platform
> support for s5p-fimc for EXYNOS4 machines need to be defined. The
> proposed solution has been tested on Universal C210 board (Samsung
> S5PC210/EXYNOS4 based).
> 
> We decided to use driver private address space mode of the iommu driver.
> This way each vb2-s5p-iommu client gets it's own address space for
> memory buffers. This reduces kernel virtual memory fragmentation as well
> as solves some non-trivial page table updates issues. The drawback is
> the fact that the interface for s5p-sysmmu has been changed.
> 
> This IOMMU allocator has no dependences on other subsystems besides
> Samsung platfrom core. We also ported s5p-mfc and s5p-tv drivers to this
> allocator, they will be posted in separate patch series. This will
> enable to get them working on EXYNOS4 (S5PV310) platform. Support for
> S5PV210/S5PC110 platform still depends on CMA allocator that needs more
> discussion on memory management mailing list and development. The
> patches with updated s5p-mfc and s5p-tv drivers will follow.
> 
> To get FIMC module working on EXYNOS4/UniversalC210 board we also added
> support for power domains and power gating.
> 
> This patch series contains a collection of patches for various platform
> subsystems. Here is a detailed list:
> 
> [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC
> - adds basic platform resources for FIMC modules (for s5p-fimc driver)
> 
> [PATCH 2/7] ARM: S5PV310: power domains: fixes and code cleanup
> - adds support for block gating in Samsung power domain driver and
>   performs some cleanup
> 
> [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
> - a complete rewrite of sysmmu driver for Samsung platform:
> - the new version introduces device private page tables (address space)
>   mode
> - simplified the resource management (no more horrible single platform
>   device with 32 resources is needed)
> - some other API chages required by upcoming videobuf2 allocator
> 
> [PATCH 4/7] v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator
> - introduces new memory allocator for videobuf2, it uses s5p-sysmmu
>   iommu driver, memory for video buffers is acuired by alloc_page() kernel
>   function
> 
> [PATCH 5/7] s5p-fimc: add pm_runtime support
> - adds support for pm_runtime in s5p-fimc driver
> 
> [PATCH 6/7] s5p-fimc: Add support for vb2-s5p-iommu allocator
> - adds support for the newly introduces videbuf2-s5p-iommu allocator
>   on EXYNOS4 platform
> 
> [PATCH 7/7] ARM: S5PC210: enable FIMC on Universal_C210
> - adds all required machine definitions to get FIMC modules working
>   on Universal C210 boards
> 
> 
> The patch series is based on git://linuxtv.org/media_tree.git tree,
> staging/for_v2.6.39 branch with the following Samsung platform patches:
> 1. [PATCH] ARM: Samsung: change suspend/resume code to depend on
> CONFIG_SUSPEND
> http://www.mail-archive.com/linux-samsung-
soc at vger.kernel.org/msg04025.html
> 2. [PATCH v2] ARM: S5PC210: add support for i2c PMICs on Universal_C210
board
> http://www.mail-archive.com/linux-samsung-
soc at vger.kernel.org/msg04029.html
> 
> This series has not been rebased onto the latest changes (S5PV310
> renamed to EXYNOS4) in
> git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git,
> for-next branch. We will rebase them soon, but first we want to get
> feedback and comments on the s5p-iommu videobuf2 allocator idea.
> 
> Best regards
> --
> Marek Szyprowski
> Samsung Poland R&D Center
> 
> 
> Complete patch summary:
> 
> Andrzej Pietrasiewicz (2):
>   ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
>   v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator
> 
> Marek Szyprowski (3):
>   s5p-fimc: add pm_runtime support
>   s5p-fimc: Add support for vb2-s5p-iommu allocator
>   ARM: S5PC210: enable FIMC on Universal_C210
> 
> Sylwester Nawrocki (1):
>   ARM: S5PV310: Add platform definitions for FIMC
> 
> Tomasz Stanislawski (1):
>   ARM: S5PV310: power domains: fixes and code cleanup
> 
>  arch/arm/mach-s5pv310/Kconfig                    |    6 +
>  arch/arm/mach-s5pv310/clock.c                    |   91 ++
>  arch/arm/mach-s5pv310/cpu.c                      |    7 +
>  arch/arm/mach-s5pv310/dev-pd.c                   |   93 ++-
>  arch/arm/mach-s5pv310/dev-sysmmu.c               |  582 +++++++++----
>  arch/arm/mach-s5pv310/include/mach/irqs.h        |   40 +-
>  arch/arm/mach-s5pv310/include/mach/map.h         |    8 +
>  arch/arm/mach-s5pv310/include/mach/regs-clock.h  |   12 +
>  arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h |   23 +-
>  arch/arm/mach-s5pv310/include/mach/sysmmu.h      |  122 ---
>  arch/arm/mach-s5pv310/mach-universal_c210.c      |   20 +
>  arch/arm/plat-s5p/Kconfig                        |   22 +-
>  arch/arm/plat-s5p/Makefile                       |    1 +
>  arch/arm/plat-s5p/dev-fimc3.c                    |   43 +
>  arch/arm/plat-s5p/include/plat/sysmmu.h          |  127 +++
>  arch/arm/plat-s5p/sysmmu.c                       |  988 +++++++++++++++--
---
> --
>  arch/arm/plat-samsung/include/plat/devs.h        |    3 +-
>  arch/arm/plat-samsung/include/plat/fimc-core.h   |    5 +
>  arch/arm/plat-samsung/include/plat/pd.h          |    1 +
>  drivers/media/video/Kconfig                      |   11 +-
>  drivers/media/video/Makefile                     |    1 +
>  drivers/media/video/s5p-fimc/fimc-capture.c      |    9 +-
>  drivers/media/video/s5p-fimc/fimc-core.c         |   36 +-
>  drivers/media/video/s5p-fimc/fimc-mem.h          |   87 ++
>  drivers/media/video/videobuf2-s5p-iommu.c        |  444 ++++++++++
>  include/media/videobuf2-s5p-iommu.h              |   50 ++
>  26 files changed, 2129 insertions(+), 703 deletions(-)
>  rewrite arch/arm/mach-s5pv310/dev-sysmmu.c (86%)
>  delete mode 100644 arch/arm/mach-s5pv310/include/mach/sysmmu.h
>  create mode 100644 arch/arm/plat-s5p/dev-fimc3.c
>  create mode 100644 arch/arm/plat-s5p/include/plat/sysmmu.h
>  rewrite arch/arm/plat-s5p/sysmmu.c (85%)
>  create mode 100644 drivers/media/video/s5p-fimc/fimc-mem.h
>  create mode 100644 drivers/media/video/videobuf2-s5p-iommu.c
>  create mode 100644 include/media/videobuf2-s5p-iommu.h
> 
> --
> 1.7.1.569.g6f426

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update
  2011-03-08  7:28 ` [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Kukjin Kim
@ 2011-03-08  9:34   ` Marek Szyprowski
  2011-03-08 10:05     ` InKi Dae
  0 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-08  9:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Tuesday, March 08, 2011 8:29 AM Kukjin Kim wrote:

> Hello,
> 
> There are comments for your System MMU driver below.

Please take into account that this was an initial version of our SYSMMU
driver to start the discussion, so there were a few minor problems left.
Thanks for pointing them out btw. :)

 
> It's good that System MMU has functionality of mapping but System MMU have
> to use other mapping of virtual memory allocator.

Could you elaborate on this? I'm not sure I understand right your problem.

SYSMMU driver is a low-level driver for the SYSMMU module. The driver should
provide all the basic functionality that is (or might be) hardware dependent.
Creating a mapping is one of such elementary functionalities. Sysmmu client
(let it be videobuf2-s5p-iommu, vcmm, maybe even other driver directly)
should not need to know the format of page descriptors or the way they are
arranged in the memory. The sysmmu should provide low level functions to create
and remove a mapping. Managing a virtual space is something that MIGHT be client
dependent and should be left to the client. 

This design allows for different approaches to coexist. Videobuf2-s5p-iommu
client will manage the virtual space with gen_alloc framework, while vcmm will
use its own methods.

It would be great if one decide to unify iommu interfaces across the kernel,
but this will be a long road. We need to start from something simple (platform
private) and working first.
 
> And would be better to change sysmmu_list to use array of defined in
> s5p_sysmmu_ip enumeration, so that can get enhancement of memory space
> usage, speed, and readability of codes.

Yes, the list can be simplified to an array, but this is really a minor issue.

> TLB replacement policy does not need to use LRU. Of course, current System
> MMU also needs it. I think, the round robin is enough, because to access
> memory has no temporal locality and to make LRU need to access to System
> MMU register one more. The reset value is round robin.

Well, the best possibility is to allow sysmmu clients to decide which policy
should be used. For some devices (I'm thinking of MFC) LRU policy might give
a little speedup.

> In the setting of SHARED page table in s5p_sysmmu_control_locked, get the
> page table base address of ARM core from cp15 register now. But current->mm-
> >pgd is better for more compatibility.

Right, this way the pgd table pointer can be acquired in a more system friendly
way.

> When it make page table with PRIVATE page table methods, the size of the
> structure to manage the second page table is quite big. It is much better
> rather that to make slab with cache size of 1KB.

Yes, our initial driver uses directly 4KB pages to manage 4 consecutive second
page tables. However usually the allocations of client devices will be few but
quite large each. So most of pages used to hold second level page tables will
be effectively reused. 

You are right however that the approach with a slab with 1KB units will
result in code that is cleaner and easier to understand.

> Besides, the page mapping implementation is not safe in your System MMU
> driver. Because only first one confirms primary page table entry, when it
> assigns four second page tables consecutively at a time.

That's a direct result of the 4-second-level-at-once method of allocating
second level pages, but this can be cleaned by using 1KB with slab.

> The System MMU driver cannot apply runtime pm by oneself with calling
> pm_runtime_put_sync(). The reason is because a device with System MMU can
> on/off power. I think just clock gating is enough. However, I can't find
> clock enable/disable in your driver.

Clock is enabled in probe() and disabled in remove(). pm_runtime_get/put_sync()
only increases/decreases use count of a respective power domain, so the actual
device driver also has to call pm_runtime_get/put. Calling pm_runtime_put_sync()
will not shut down the power if the sysmmu client driver has called
pm_runtime_get() without pm_runtime_put(). I see no problems here. Could you 
elaborate your issue?

> 
> By PRIVATE page table method, each system MMU comes to have a page table
> only for oneself. In this case, the problem is that each MFC System MMU L
> and R having another page table.

Yes, true. This is consequence of the MFC hardware design and the fact that
it has 2 AXI master interfaces and 2 SYSMMU controllers. Each of them have to
be configured separately. Each of them has a separate virtual driver's address
space. Such configuration is used by the MFC driver posted in v7 patch series.

> In your System MMU driver, the page size is always 4KB crucially. This says
> TLB thrashing and produces a result to lose a TLB hit rate. It is a big
> problem with the device such as rotator which does not do sequential access
> especially.

The page size is set to 4KB, because Linux kernel uses 4KB pages by default.
Once support for other page size is available in the kernel, then sysmmu can be
extended also.

> And the IRQ handler just outputs only a message. It should be implemented
> in call back function to be able to handle from each device driver.

This was only for debugging purpose, but you are right that the sysmmu API in 
this area need to be extended.

> When it sets System MMU in SHARED page table, kernel virtual memory is
> broken by a method such as s5p_sysmmu_map_area()

Yes, there should be a check added to prevent messing with ARM pgd in SHARED 
mode.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update
  2011-03-08  9:34   ` Marek Szyprowski
@ 2011-03-08 10:05     ` InKi Dae
  0 siblings, 0 replies; 29+ messages in thread
From: InKi Dae @ 2011-03-08 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Mr. Kukjin.


2011/3/8 Marek Szyprowski <m.szyprowski@samsung.com>:
> Hello,
>
> On Tuesday, March 08, 2011 8:29 AM Kukjin Kim wrote:
>
>> Hello,
>>
>> There are comments for your System MMU driver below.
>
> Please take into account that this was an initial version of our SYSMMU
> driver to start the discussion, so there were a few minor problems left.
> Thanks for pointing them out btw. :)
>
>
>> It's good that System MMU has functionality of mapping but System MMU have
>> to use other mapping of virtual memory allocator.
>
you mean that other page sizes such as large, small page and so on
should be supported in mapping also? otherwise use 64k not 4k page?

> Could you elaborate on this? I'm not sure I understand right your problem.
>
> SYSMMU driver is a low-level driver for the SYSMMU module. The driver should
> provide all the basic functionality that is (or might be) hardware dependent.
> Creating a mapping is one of such elementary functionalities. Sysmmu client
> (let it be videobuf2-s5p-iommu, vcmm, maybe even other driver directly)
> should not need to know the format of page descriptors or the way they are
> arranged in the memory. The sysmmu should provide low level functions to create
> and remove a mapping. Managing a virtual space is something that MIGHT be client
> dependent and should be left to the client.
>
> This design allows for different approaches to coexist. Videobuf2-s5p-iommu
> client will manage the virtual space with gen_alloc framework, while vcmm will
> use its own methods.
>
> It would be great if one decide to unify iommu interfaces across the kernel,
> but this will be a long road. We need to start from something simple (platform
> private) and working first.
>
>> And would be better to change sysmmu_list to use array of defined in
>> s5p_sysmmu_ip enumeration, so that can get enhancement of memory space
>> usage, speed, and readability of codes.
>
> Yes, the list can be simplified to an array, but this is really a minor issue.
>
>> TLB replacement policy does not need to use LRU. Of course, current System
>> MMU also needs it. I think, the round robin is enough, because to access
>> memory has no temporal locality and to make LRU need to access to System
>> MMU register one more. The reset value is round robin.
>
> Well, the best possibility is to allow sysmmu clients to decide which policy
> should be used. For some devices (I'm thinking of MFC) LRU policy might give
> a little speedup.
>
>> In the setting of SHARED page table in s5p_sysmmu_control_locked, get the
>> page table base address of ARM core from cp15 register now. But current->mm-
>> >pgd is better for more compatibility.
>
> Right, this way the pgd table pointer can be acquired in a more system friendly
> way.
>
>> When it make page table with PRIVATE page table methods, the size of the
>> structure to manage the second page table is quite big. It is much better
>> rather that to make slab with cache size of 1KB.
>
> Yes, our initial driver uses directly 4KB pages to manage 4 consecutive second
> page tables. However usually the allocations of client devices will be few but
> quite large each. So most of pages used to hold second level page tables will
> be effectively reused.
>
> You are right however that the approach with a slab with 1KB units will
> result in code that is cleaner and easier to understand.
>
>> Besides, the page mapping implementation is not safe in your System MMU
>> driver. Because only first one confirms primary page table entry, when it
>> assigns four second page tables consecutively at a time.
>
> That's a direct result of the 4-second-level-at-once method of allocating
> second level pages, but this can be cleaned by using 1KB with slab.
>
>> The System MMU driver cannot apply runtime pm by oneself with calling
>> pm_runtime_put_sync(). The reason is because a device with System MMU can
>> on/off power. I think just clock gating is enough. However, I can't find
>> clock enable/disable in your driver.
>
> Clock is enabled in probe() and disabled in remove(). pm_runtime_get/put_sync()
> only increases/decreases use count of a respective power domain, so the actual
> device driver also has to call pm_runtime_get/put. Calling pm_runtime_put_sync()
> will not shut down the power if the sysmmu client driver has called
> pm_runtime_get() without pm_runtime_put(). I see no problems here. Could you
> elaborate your issue?
>
>>
>> By PRIVATE page table method, each system MMU comes to have a page table
>> only for oneself. In this case, the problem is that each MFC System MMU L
>> and R having another page table.
>
> Yes, true. This is consequence of the MFC hardware design and the fact that
> it has 2 AXI master interfaces and 2 SYSMMU controllers. Each of them have to
> be configured separately. Each of them has a separate virtual driver's address
> space. Such configuration is used by the MFC driver posted in v7 patch series.
>
>> In your System MMU driver, the page size is always 4KB crucially. This says
>> TLB thrashing and produces a result to lose a TLB hit rate. It is a big
>> problem with the device such as rotator which does not do sequential access
>> especially.
>
> The page size is set to 4KB, because Linux kernel uses 4KB pages by default.
> Once support for other page size is available in the kernel, then sysmmu can be
> extended also.
>
>> And the IRQ handler just outputs only a message. It should be implemented
>> in call back function to be able to handle from each device driver.
>
> This was only for debugging purpose, but you are right that the sysmmu API in
> this area need to be extended.
>
>> When it sets System MMU in SHARED page table, kernel virtual memory is
>> broken by a method such as s5p_sysmmu_map_area()
>
> Yes, there should be a check added to prevent messing with ARM pgd in SHARED
> mode.
>
> Best regards
> --
> Marek Szyprowski
> Samsung Poland R&D Center
>
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-04 16:04   ` Marek Szyprowski
@ 2011-03-10 14:52     ` Arnd Bergmann
  2011-03-11  9:04       ` Marek Szyprowski
  0 siblings, 1 reply; 29+ messages in thread
From: Arnd Bergmann @ 2011-03-10 14:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 04 March 2011, Marek Szyprowski wrote:
> From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
> 
> This patch performs a complete rewrite of sysmmu driver for Samsung platform:
> - the new version introduces an api to construct device private page
>   tables and enables to use device private address space mode
> - simplified the resource management: no more single platform
>   device with 32 resources is needed, better fits into linux driver model,
>   each sysmmu instance has it's own resource definition
> - added support for sysmmu clocks
> - some other minor API chages required by upcoming videobuf2 allocator
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Please explain why create a new IOMMU API when we already have two
generic ones (include/linux/iommu.h and include/linux/dma-mapping.h).

Is there something that cannot be done with the common code?
The first approach should be to extend the existing APIs to
do what you need.

	Arnd

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-10 14:52     ` Arnd Bergmann
@ 2011-03-11  9:04       ` Marek Szyprowski
  2011-03-11 11:50         ` Arnd Bergmann
  0 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-11  9:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Thursday, March 10, 2011 3:52 PM Arnd Bergmann wrote:

> On Friday 04 March 2011, Marek Szyprowski wrote:
> > From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
> >
> > This patch performs a complete rewrite of sysmmu driver for Samsung platform:
> > - the new version introduces an api to construct device private page
> >   tables and enables to use device private address space mode
> > - simplified the resource management: no more single platform
> >   device with 32 resources is needed, better fits into linux driver model,
> >   each sysmmu instance has it's own resource definition
> > - added support for sysmmu clocks
> > - some other minor API chages required by upcoming videobuf2 allocator
> >
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> 
> Please explain why create a new IOMMU API when we already have two
> generic ones (include/linux/iommu.h and include/linux/dma-mapping.h).
> 
> Is there something that cannot be done with the common code?
> The first approach should be to extend the existing APIs to
> do what you need.

We followed the style of iommu API for other mainline ARM platforms (both OMAP and MSM
also have custom API for their iommu modules). I've briefly checked include/linux/iommu.h
API and I've noticed that it has been designed mainly for KVM support. There is also
include/linux/intel-iommu.h interface, but I it is very specific to intel gfx chips.

Is there any example how include/linux/dma-mapping.h interface can be used for iommu
mappings?

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11  9:04       ` Marek Szyprowski
@ 2011-03-11 11:50         ` Arnd Bergmann
  2011-03-11 12:35           ` Marek Szyprowski
  0 siblings, 1 reply; 29+ messages in thread
From: Arnd Bergmann @ 2011-03-11 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 11 March 2011, Marek Szyprowski wrote:
> 
> We followed the style of iommu API for other mainline ARM platforms (both OMAP and MSM
> also have custom API for their iommu modules). I've briefly checked include/linux/iommu.h
> API and I've noticed that it has been designed mainly for KVM support. There is also
> include/linux/intel-iommu.h interface, but I it is very specific to intel gfx chips.

The MSM code actually uses the generic iommu.h code, using register_iommu, so
the drivers can use the regular iommu_map.

I believe the omap code predates the iommu API, and should really be changed
to use that. At least it was added before I started reviewing the code.

The iommu API is not really meant to be KVM specific, it's just that the
in-tree users are basically limited to KVM at the moment. Another user that
is coming up soon is the vmio device driver that can be used to transparently
pass devices to user space. The idea behind the IOMMU API is that you can
map arbitrary bus addresses to physical memory addresses, but it does not
deal with allocating the bus addresses or providing buffer management such
as cache flushes.

> Is there any example how include/linux/dma-mapping.h interface can be used for iommu
> mappings?

The dma-mapping API is the normal interface that you should use for IOMMUs
that sit between DMA devices and kernel memory. The idea is that you
completely abstract the concept of an IOMMU so the device driver uses
the same code for talking to a device with an IOMMU and another device with
a linear mapping or an swiotlb bounce buffer.

This means that the user of the dma-mapping API does not get to choose the
bus addresses, but instead you use the API to get a bus address for a
chunk of memory, and then you can pass that address to a device.

See arch/powerpc/kernel/iommu.c and arch/x86/kernel/amd_iommu.c for common
examples of how this is implemented. The latter one actually implements
both the iommu_ops for iommu.h and dma_map_ops for dma-mapping.h.

	Arnd

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 11:50         ` Arnd Bergmann
@ 2011-03-11 12:35           ` Marek Szyprowski
  2011-03-11 14:07             ` Arnd Bergmann
  0 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-11 12:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Friday, March 11, 2011 12:51 PM Arnd Bergmann wrote:

> On Friday 11 March 2011, Marek Szyprowski wrote:
> >
> > We followed the style of iommu API for other mainline ARM platforms (both OMAP and MSM
> > also have custom API for their iommu modules). I've briefly checked include/linux/iommu.h
> > API and I've noticed that it has been designed mainly for KVM support. There is also
> > include/linux/intel-iommu.h interface, but I it is very specific to intel gfx chips.
> 
> The MSM code actually uses the generic iommu.h code, using register_iommu, so
> the drivers can use the regular iommu_map.
> 
> I believe the omap code predates the iommu API, and should really be changed
> to use that. At least it was added before I started reviewing the code.
> 
> The iommu API is not really meant to be KVM specific, it's just that the
> in-tree users are basically limited to KVM at the moment. Another user that
> is coming up soon is the vmio device driver that can be used to transparently
> pass devices to user space. The idea behind the IOMMU API is that you can
> map arbitrary bus addresses to physical memory addresses, but it does not
> deal with allocating the bus addresses or providing buffer management such
> as cache flushes.

Yea, I've noticed this and this basically what we expect from iommu driver. 
However the iommu.h API requires a separate call to map each single memory page.
This is quite ineffective approach and imho the API need to be extended to allow
mapping of the arbitrary set of pages.

> > Is there any example how include/linux/dma-mapping.h interface can be used for iommu
> > mappings?
> 
> The dma-mapping API is the normal interface that you should use for IOMMUs
> that sit between DMA devices and kernel memory. The idea is that you
> completely abstract the concept of an IOMMU so the device driver uses
> the same code for talking to a device with an IOMMU and another device with
> a linear mapping or an swiotlb bounce buffer.
> 
> This means that the user of the dma-mapping API does not get to choose the
> bus addresses, but instead you use the API to get a bus address for a
> chunk of memory, and then you can pass that address to a device.
> 
> See arch/powerpc/kernel/iommu.c and arch/x86/kernel/amd_iommu.c for common
> examples of how this is implemented. The latter one actually implements
> both the iommu_ops for iommu.h and dma_map_ops for dma-mapping.h.

Thanks for your comments! We will check how is it suitable for our case.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 12:35           ` Marek Szyprowski
@ 2011-03-11 14:07             ` Arnd Bergmann
  2011-03-11 14:51               ` Marek Szyprowski
  0 siblings, 1 reply; 29+ messages in thread
From: Arnd Bergmann @ 2011-03-11 14:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 11 March 2011, Marek Szyprowski wrote:
> > The iommu API is not really meant to be KVM specific, it's just that the
> > in-tree users are basically limited to KVM at the moment. Another user that
> > is coming up soon is the vmio device driver that can be used to transparently
> > pass devices to user space. The idea behind the IOMMU API is that you can
> > map arbitrary bus addresses to physical memory addresses, but it does not
> > deal with allocating the bus addresses or providing buffer management such
> > as cache flushes.
> 
> Yea, I've noticed this and this basically what we expect from iommu driver. 
> However the iommu.h API requires a separate call to map each single memory page.
> This is quite ineffective approach and imho the API need to be extended to allow
> mapping of the arbitrary set of pages.

We can always discuss extensions to the existing infrastructure, adding
an interface for mapping an array of page pointers in the iommu API
sounds like a good idea.

I also think that we should not really have separate iommu and dma-mapping
interfaces, but rather have a portable way to define an iommu so that it
can be used through the dma-mapping interfaces. I'm not asking you to
do that as a prerequisite to merging your driver, but it may be good to
keep in mind that the current situation is still lacking and that any
suggestion for improving this as part of your work to support the
samsung IOMMU is welcome.

Note that the ARM implementation of the dma-mapping.h interface currently
does not support IOMMUs, but that could be changed by wrapping it
using the include/asm-generic/dma-mapping-common.h infrastructure.

	Arnd

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 14:07             ` Arnd Bergmann
@ 2011-03-11 14:51               ` Marek Szyprowski
  2011-03-11 15:15                 ` Arnd Bergmann
  0 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Friday, March 11, 2011 3:08 PM Arnd Bergmann wrote:

> On Friday 11 March 2011, Marek Szyprowski wrote:
> > > The iommu API is not really meant to be KVM specific, it's just that the
> > > in-tree users are basically limited to KVM at the moment. Another user that
> > > is coming up soon is the vmio device driver that can be used to transparently
> > > pass devices to user space. The idea behind the IOMMU API is that you can
> > > map arbitrary bus addresses to physical memory addresses, but it does not
> > > deal with allocating the bus addresses or providing buffer management such
> > > as cache flushes.
> >
> > Yea, I've noticed this and this basically what we expect from iommu driver.
> > However the iommu.h API requires a separate call to map each single memory page.
> > This is quite ineffective approach and imho the API need to be extended to allow
> > mapping of the arbitrary set of pages.
> 
> We can always discuss extensions to the existing infrastructure, adding
> an interface for mapping an array of page pointers in the iommu API
> sounds like a good idea.

We will investigate this API further. From the first sight it looks it won't take
much work to port/rewrite our driver to fit into iommu.h API.

> I also think that we should not really have separate iommu and dma-mapping
> interfaces, but rather have a portable way to define an iommu so that it
> can be used through the dma-mapping interfaces. I'm not asking you to
> do that as a prerequisite to merging your driver, but it may be good to
> keep in mind that the current situation is still lacking and that any
> suggestion for improving this as part of your work to support the
> samsung IOMMU is welcome.

Well creating a portable iommu framework and merging it with dma-mapping interface
looks like a much harder (and time consuming) task. There is definitely a need for
it. I hope that it can be developed incrementally starting from the current iommu.h
and dma-mapping.h interfaces. Please note that there might be some subtle differences
in the hardware that such framework must be aware. The first obvious one is the
hardware design. Some platform has central iommu unit, other (like Samsung Exynos4)
has a separate iommu unit per each device driver (this is still a simplification,
because a video codec device has 2 memory interfaces and 2 iommu units). Currently
I probably have not enough knowledge to predict the other possible issues that need
to be taken into account in the portable and generic iommu/dma-mapping frame-work.

> Note that the ARM implementation of the dma-mapping.h interface currently
> does not support IOMMUs, but that could be changed by wrapping it
> using the include/asm-generic/dma-mapping-common.h infrastructure.

ARM dma-mapping framework also requires some additional research for better DMA
support (there are still issues with multiple mappings to be resolved).

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 14:51               ` Marek Szyprowski
@ 2011-03-11 15:15                 ` Arnd Bergmann
  2011-03-11 15:39                   ` Marek Szyprowski
  0 siblings, 1 reply; 29+ messages in thread
From: Arnd Bergmann @ 2011-03-11 15:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 11 March 2011, Marek Szyprowski wrote:
> On Friday, March 11, 2011 3:08 PM Arnd Bergmann wrote:
> 
> > On Friday 11 March 2011, Marek Szyprowski wrote:
> > > > The iommu API is not really meant to be KVM specific, it's just that the
> > > > in-tree users are basically limited to KVM at the moment. Another user that
> > > > is coming up soon is the vmio device driver that can be used to transparently
> > > > pass devices to user space. The idea behind the IOMMU API is that you can
> > > > map arbitrary bus addresses to physical memory addresses, but it does not
> > > > deal with allocating the bus addresses or providing buffer management such
> > > > as cache flushes.
> > >
> > > Yea, I've noticed this and this basically what we expect from iommu driver.
> > > However the iommu.h API requires a separate call to map each single memory page.
> > > This is quite ineffective approach and imho the API need to be extended to allow
> > > mapping of the arbitrary set of pages.
> > 
> > We can always discuss extensions to the existing infrastructure, adding
> > an interface for mapping an array of page pointers in the iommu API
> > sounds like a good idea.
> 
> We will investigate this API further. From the first sight it looks it won't take
> much work to port/rewrite our driver to fit into iommu.h API.

Ok, sounds good.

> > I also think that we should not really have separate iommu and dma-mapping
> > interfaces, but rather have a portable way to define an iommu so that it
> > can be used through the dma-mapping interfaces. I'm not asking you to
> > do that as a prerequisite to merging your driver, but it may be good to
> > keep in mind that the current situation is still lacking and that any
> > suggestion for improving this as part of your work to support the
> > samsung IOMMU is welcome.
> 
> Well creating a portable iommu framework and merging it with dma-mapping interface
> looks like a much harder (and time consuming) task. There is definitely a need for
> it. I hope that it can be developed incrementally starting from the current iommu.h
> and dma-mapping.h interfaces.

Yes, that is the idea. Maybe we should add it to the list things that the
Linaro kernel working group can target for the November release?

> Please note that there might be some subtle differences
> in the hardware that such framework must be aware. The first obvious one is the
> hardware design. Some platform has central iommu unit, other (like Samsung Exynos4)
> has a separate iommu unit per each device driver (this is still a simplification,
> because a video codec device has 2 memory interfaces and 2 iommu units). Currently
> I probably have not enough knowledge to predict the other possible issues that need
> to be taken into account in the portable and generic iommu/dma-mapping frame-work.

The dma-mapping API can deal well with one IOMMU per device, but would
need some tricks to work with one device that has two separate IOMMUs.

I'm not very familar with the iommu API, but in the common KVM scenario,
you need one IOMMU per device, so it should handle that just fine as well.

> > Note that the ARM implementation of the dma-mapping.h interface currently
> > does not support IOMMUs, but that could be changed by wrapping it
> > using the include/asm-generic/dma-mapping-common.h infrastructure.
> 
> ARM dma-mapping framework also requires some additional research for better DMA
> support (there are still issues with multiple mappings to be resolved).

You mean mapping the same memory into multiple devices, or a different problem?

	Arnd

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 15:15                 ` Arnd Bergmann
@ 2011-03-11 15:39                   ` Marek Szyprowski
  2011-03-11 16:00                     ` Arnd Bergmann
  0 siblings, 1 reply; 29+ messages in thread
From: Marek Szyprowski @ 2011-03-11 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Friday, March 11, 2011 4:15 PM Arnd Bergmann wrote:

> On Friday 11 March 2011, Marek Szyprowski wrote:
> > On Friday, March 11, 2011 3:08 PM Arnd Bergmann wrote:
> >
> > > On Friday 11 March 2011, Marek Szyprowski wrote:
> > > > > The iommu API is not really meant to be KVM specific, it's just that the
> > > > > in-tree users are basically limited to KVM at the moment. Another user that
> > > > > is coming up soon is the vmio device driver that can be used to transparently
> > > > > pass devices to user space. The idea behind the IOMMU API is that you can
> > > > > map arbitrary bus addresses to physical memory addresses, but it does not
> > > > > deal with allocating the bus addresses or providing buffer management such
> > > > > as cache flushes.
> > > >
> > > > Yea, I've noticed this and this basically what we expect from iommu driver.
> > > > However the iommu.h API requires a separate call to map each single memory page.
> > > > This is quite ineffective approach and imho the API need to be extended to allow
> > > > mapping of the arbitrary set of pages.
> > >
> > > We can always discuss extensions to the existing infrastructure, adding
> > > an interface for mapping an array of page pointers in the iommu API
> > > sounds like a good idea.
> >
> > We will investigate this API further. From the first sight it looks it won't take
> > much work to port/rewrite our driver to fit into iommu.h API.
> 
> Ok, sounds good.
> 
> > > I also think that we should not really have separate iommu and dma-mapping
> > > interfaces, but rather have a portable way to define an iommu so that it
> > > can be used through the dma-mapping interfaces. I'm not asking you to
> > > do that as a prerequisite to merging your driver, but it may be good to
> > > keep in mind that the current situation is still lacking and that any
> > > suggestion for improving this as part of your work to support the
> > > samsung IOMMU is welcome.
> >
> > Well creating a portable iommu framework and merging it with dma-mapping interface
> > looks like a much harder (and time consuming) task. There is definitely a need for
> > it. I hope that it can be developed incrementally starting from the current iommu.h
> > and dma-mapping.h interfaces.
> 
> Yes, that is the idea. Maybe we should add it to the list things that the
> Linaro kernel working group can target for the November release?
> 
> > Please note that there might be some subtle differences
> > in the hardware that such framework must be aware. The first obvious one is the
> > hardware design. Some platform has central iommu unit, other (like Samsung Exynos4)
> > has a separate iommu unit per each device driver (this is still a simplification,
> > because a video codec device has 2 memory interfaces and 2 iommu units). Currently
> > I probably have not enough knowledge to predict the other possible issues that need
> > to be taken into account in the portable and generic iommu/dma-mapping frame-work.
> 
> The dma-mapping API can deal well with one IOMMU per device, but would
> need some tricks to work with one device that has two separate IOMMUs.

We need to investigate the internals of dma-mapping API first. Right now I know too
little in this area.
 
> I'm not very familar with the iommu API, but in the common KVM scenario,
> you need one IOMMU per device, so it should handle that just fine as well.

Well, afair there are also systems with one central iommu module, which is shared 
between devices. I have no idea how such model will fit into the dma-mapping API.
 
> > > Note that the ARM implementation of the dma-mapping.h interface currently
> > > does not support IOMMUs, but that could be changed by wrapping it
> > > using the include/asm-generic/dma-mapping-common.h infrastructure.
> >
> > ARM dma-mapping framework also requires some additional research for better DMA
> > support (there are still issues with multiple mappings to be resolved).
> 
> You mean mapping the same memory into multiple devices, or a different problem?

Mapping the same memory area multiple times with different cache settings is not
legal on ARMv7+ systems. Currently the problems might caused by the low-memory
kernel linear mapping and second mapping created for example by dma_alloc_coherent()
function.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 15:39                   ` Marek Szyprowski
@ 2011-03-11 16:00                     ` Arnd Bergmann
  2011-03-14 12:37                       ` KyongHo Cho
  0 siblings, 1 reply; 29+ messages in thread
From: Arnd Bergmann @ 2011-03-11 16:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 11 March 2011, Marek Szyprowski wrote:
> > > > does not support IOMMUs, but that could be changed by wrapping it
> > > > using the include/asm-generic/dma-mapping-common.h infrastructure.
> > >
> > > ARM dma-mapping framework also requires some additional research for better DMA
> > > support (there are still issues with multiple mappings to be resolved).
> > 
> > You mean mapping the same memory into multiple devices, or a different problem?
> 
> Mapping the same memory area multiple times with different cache settings is not
> legal on ARMv7+ systems. Currently the problems might caused by the low-memory
> kernel linear mapping and second mapping created for example by dma_alloc_coherent()
> function.

Yes, I know this problem, but I don't think the case you describe is a serious
limitation (there are more interesting cases, though): dma_map_single() etc
will create additional *bus* addresses for a physical address, not additional
virtual addresses.

dma_alloc_coherent should allocate memory that is not also mapped cached,
which is what I thought we do correctly.

	Arnd

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC
  2011-03-04  9:01 ` [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC Marek Szyprowski
@ 2011-03-12  0:27   ` Kukjin Kim
  0 siblings, 0 replies; 29+ messages in thread
From: Kukjin Kim @ 2011-03-12  0:27 UTC (permalink / raw)
  To: linux-arm-kernel

Marek Szyprowski wrote:
> 
> From: Sylwester Nawrocki <s.nawrocki@samsung.com>
> 
> Add support for fourth FIMC platform device definition and define
> resources for FIMC modules on S5PV310 machines.
> 
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  arch/arm/mach-s5pv310/cpu.c                    |    7 ++++
>  arch/arm/mach-s5pv310/include/mach/irqs.h      |    4 ++
>  arch/arm/mach-s5pv310/include/mach/map.h       |    8 ++++
>  arch/arm/plat-s5p/Kconfig                      |    5 +++
>  arch/arm/plat-s5p/Makefile                     |    1 +
>  arch/arm/plat-s5p/dev-fimc3.c                  |   43
> ++++++++++++++++++++++++
>  arch/arm/plat-samsung/include/plat/devs.h      |    1 +
>  arch/arm/plat-samsung/include/plat/fimc-core.h |    5 +++
>  8 files changed, 74 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-s5p/dev-fimc3.c
> 
> diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c
> index 0db0fb6..0bdb0b0 100644
> --- a/arch/arm/mach-s5pv310/cpu.c
> +++ b/arch/arm/mach-s5pv310/cpu.c
> @@ -21,6 +21,8 @@
>  #include <plat/clock.h>
>  #include <plat/s5pv310.h>
>  #include <plat/sdhci.h>
> +#include <plat/devs.h>
> +#include <plat/fimc-core.h>
> 
>  #include <mach/regs-irq.h>
> 
> @@ -114,6 +116,11 @@ void __init s5pv310_map_io(void)
>  	s5pv310_default_sdhci1();
>  	s5pv310_default_sdhci2();
>  	s5pv310_default_sdhci3();
> +
> +	s3c_fimc_setname(0, "s5pv310-fimc");
> +	s3c_fimc_setname(1, "s5pv310-fimc");
> +	s3c_fimc_setname(2, "s5pv310-fimc");
> +	s3c_fimc_setname(3, "s5pv310-fimc");
>  }
> 
>  void __init s5pv310_init_clocks(int xtal)
> diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-
> s5pv310/include/mach/irqs.h
> index 536b0b5..0e99968 100644
> --- a/arch/arm/mach-s5pv310/include/mach/irqs.h
> +++ b/arch/arm/mach-s5pv310/include/mach/irqs.h
> @@ -107,6 +107,10 @@
> 
>  #define IRQ_MIPI_CSIS0		COMBINER_IRQ(30, 0)
>  #define IRQ_MIPI_CSIS1		COMBINER_IRQ(30, 1)
> +#define IRQ_FIMC0		COMBINER_IRQ(32, 0)
> +#define IRQ_FIMC1		COMBINER_IRQ(32, 1)
> +#define IRQ_FIMC2		COMBINER_IRQ(33, 0)
> +#define IRQ_FIMC3		COMBINER_IRQ(33, 1)
> 
>  #define IRQ_ONENAND_AUDI	COMBINER_IRQ(34, 0)
> 
> diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-
> s5pv310/include/mach/map.h
> index 901657f..0db3a47 100644
> --- a/arch/arm/mach-s5pv310/include/mach/map.h
> +++ b/arch/arm/mach-s5pv310/include/mach/map.h
> @@ -25,6 +25,10 @@
> 
>  #define S5PV310_PA_SYSRAM		0x02025000
> 
> +#define S5PV310_PA_FIMC0		0x11800000
> +#define S5PV310_PA_FIMC1		0x11810000
> +#define S5PV310_PA_FIMC2		0x11820000
> +#define S5PV310_PA_FIMC3		0x11830000
>  #define S5PV310_PA_I2S0			0x03830000
>  #define S5PV310_PA_I2S1			0xE3100000
>  #define S5PV310_PA_I2S2			0xE2A00000
> @@ -121,6 +125,10 @@
>  #define S5P_PA_CHIPID			S5PV310_PA_CHIPID
>  #define S5P_PA_MIPI_CSIS0		S5PV310_PA_MIPI_CSIS0
>  #define S5P_PA_MIPI_CSIS1		S5PV310_PA_MIPI_CSIS1
> +#define S5P_PA_FIMC0			S5PV310_PA_FIMC0
> +#define S5P_PA_FIMC1			S5PV310_PA_FIMC1
> +#define S5P_PA_FIMC2			S5PV310_PA_FIMC2
> +#define S5P_PA_FIMC3			S5PV310_PA_FIMC3
>  #define S5P_PA_ONENAND			S5PC210_PA_ONENAND
>  #define S5P_PA_ONENAND_DMA		S5PC210_PA_ONENAND_DMA
>  #define S5P_PA_SDRAM			S5PV310_PA_SDRAM
> diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
> index 557f8c5..0db2a7a 100644
> --- a/arch/arm/plat-s5p/Kconfig
> +++ b/arch/arm/plat-s5p/Kconfig
> @@ -60,6 +60,11 @@ config S5P_DEV_FIMC2
>  	help
>  	  Compile in platform device definitions for FIMC controller 2
> 
> +config S5P_DEV_FIMC3
> +	bool
> +	help
> +	  Compile in platform device definitions for FIMC controller 3
> +
>  config S5P_DEV_ONENAND
>  	bool
>  	help
> diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
> index ce5a0a7..cfcd1db 100644
> --- a/arch/arm/plat-s5p/Makefile
> +++ b/arch/arm/plat-s5p/Makefile
> @@ -28,6 +28,7 @@ obj-$(CONFIG_SUSPEND)		+= irq-pm.o
>  obj-$(CONFIG_S5P_DEV_FIMC0)	+= dev-fimc0.o
>  obj-$(CONFIG_S5P_DEV_FIMC1)	+= dev-fimc1.o
>  obj-$(CONFIG_S5P_DEV_FIMC2)	+= dev-fimc2.o
> +obj-$(CONFIG_S5P_DEV_FIMC3)	+= dev-fimc3.o
>  obj-$(CONFIG_S5P_DEV_ONENAND)	+= dev-onenand.o
>  obj-$(CONFIG_S5P_DEV_CSIS0)	+= dev-csis0.o
>  obj-$(CONFIG_S5P_DEV_CSIS1)	+= dev-csis1.o
> diff --git a/arch/arm/plat-s5p/dev-fimc3.c b/arch/arm/plat-s5p/dev-fimc3.c
> new file mode 100644
> index 0000000..ef31bec
> --- /dev/null
> +++ b/arch/arm/plat-s5p/dev-fimc3.c
> @@ -0,0 +1,43 @@
> +/* linux/arch/arm/plat-s5p/dev-fimc3.c
> + *
> + * Copyright (c) 2010 Samsung Electronics
> + *
> + * Base S5P FIMC3 resource and device definitions
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/ioport.h>
> +#include <mach/map.h>
> +
> +static struct resource s5p_fimc3_resource[] = {
> +	[0] = {
> +		.start	= S5P_PA_FIMC3,
> +		.end	= S5P_PA_FIMC3 + SZ_4K - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	[1] = {
> +		.start	= IRQ_FIMC3,
> +		.end	= IRQ_FIMC3,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static u64 s5p_fimc3_dma_mask = DMA_BIT_MASK(32);
> +
> +struct platform_device s5p_device_fimc3 = {
> +	.name		= "s5p-fimc",
> +	.id		= 3,
> +	.num_resources	= ARRAY_SIZE(s5p_fimc3_resource),
> +	.resource	= s5p_fimc3_resource,
> +	.dev		= {
> +		.dma_mask		= &s5p_fimc3_dma_mask,
> +		.coherent_dma_mask	= DMA_BIT_MASK(32),
> +	},
> +};
> diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-
> samsung/include/plat/devs.h
> index b4d208b..b0123f3 100644
> --- a/arch/arm/plat-samsung/include/plat/devs.h
> +++ b/arch/arm/plat-samsung/include/plat/devs.h
> @@ -133,6 +133,7 @@ extern struct platform_device samsung_device_keypad;
>  extern struct platform_device s5p_device_fimc0;
>  extern struct platform_device s5p_device_fimc1;
>  extern struct platform_device s5p_device_fimc2;
> +extern struct platform_device s5p_device_fimc3;
> 
>  extern struct platform_device s5p_device_mipi_csis0;
>  extern struct platform_device s5p_device_mipi_csis1;
> diff --git a/arch/arm/plat-samsung/include/plat/fimc-core.h
b/arch/arm/plat-
> samsung/include/plat/fimc-core.h
> index 81a3bfe..945a99d 100644
> --- a/arch/arm/plat-samsung/include/plat/fimc-core.h
> +++ b/arch/arm/plat-samsung/include/plat/fimc-core.h
> @@ -38,6 +38,11 @@ static inline void s3c_fimc_setname(int id, char *name)
>  		s5p_device_fimc2.name = name;
>  		break;
>  #endif
> +#ifdef CONFIG_S5P_DEV_FIMC3
> +	case 3:
> +		s5p_device_fimc3.name = name;
> +		break;
> +#endif
>  	}
>  }
> 
> --

Ok, applied this based on my for-next.
Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-11 16:00                     ` Arnd Bergmann
@ 2011-03-14 12:37                       ` KyongHo Cho
  2011-03-14 12:46                         ` Russell King - ARM Linux
  2011-03-14 13:32                         ` Arnd Bergmann
  0 siblings, 2 replies; 29+ messages in thread
From: KyongHo Cho @ 2011-03-14 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

2011/3/12 Arnd Bergmann <arnd@arndb.de>:
> On Friday 11 March 2011, Marek Szyprowski wrote:
>> > > > does not support IOMMUs, but that could be changed by wrapping it
>> > > > using the include/asm-generic/dma-mapping-common.h infrastructure.
>> > >
>> > > ARM dma-mapping framework also requires some additional research for better DMA
>> > > support (there are still issues with multiple mappings to be resolved).
>> >
>> > You mean mapping the same memory into multiple devices, or a different problem?
>>
>> Mapping the same memory area multiple times with different cache settings is not
>> legal on ARMv7+ systems. Currently the problems might caused by the low-memory
>> kernel linear mapping and second mapping created for example by dma_alloc_coherent()
>> function.
>
> Yes, I know this problem, but I don't think the case you describe is a serious
> limitation (there are more interesting cases, though): dma_map_single() etc
> will create additional *bus* addresses for a physical address, not additional
> virtual addresses.
>
> dma_alloc_coherent should allocate memory that is not also mapped cached,
> which is what I thought we do correctly.

I have also noticed that dma_map_single/page/sg() can map physical
memory into an arbitrary device address region.
But it is not enough solution for various kinds of IOMMUs.
As Kukjin Kim addressed, we need to support larger page size than 4KB
because we can reduce TLB miss when we have larger page size.

Our IOMMU(system mmu) supports all page size of ARM architecture
including 16MB, 1MB, 64KB and 4KB.
Since the largest size supported by buddy system of 32-bit architecture is 4MB,
our system support all page sizes except 16MB.
We proved that larger page size is helpful for DMA performance
significantly (more than 10%, approximately).
Big page size is not a problem for peripheral devices
because their address space is not suffer from external fragmentation.

Thanks to Arnd, I never knew about include/linux/iommu.h

Similar to dma-mappings.h, however, It is not enough for our
requirements even though it allows private data to be stored in
iommu_domain for platform-specific requirements.

I think we can consider another solution for the various requirements.
I think one of the most possible solutions is VCMM.
Or we can enhance include/linux/iommu.h with reference of VCMM.

You can find the most recent VCMM submitted at
http://marc.info/?l=linux-kernel&m=129255948319341&w=2

It looks somewhat complex but includes most of required features for
various IOMMUs
which will not be easily solved by include/linux/iommu.h

You can find VCMM core in
http://git.kernel.org/?p=linux/kernel/git/kki_ap/linux-2.6-samsung.git;a=blob;f=mm/vcm.c;h=9fff0106ec0078fad1488308305c8486adbed9c0;hb=refs/heads/2.6.36-samsung

and platform specific implementation of VCMM in
http://git.kernel.org/?p=linux/kernel/git/kki_ap/linux-2.6-samsung.git;a=blob;f=arch/arm/plat-s5p/s5p-vcm.c;h=7498c800aef8b01082e1b1c3ea0f66cefe3c85a1;hb=refs/heads/2.6.36-samsung

Cho KyongHo.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-14 12:37                       ` KyongHo Cho
@ 2011-03-14 12:46                         ` Russell King - ARM Linux
  2011-03-15  1:45                           ` InKi Dae
  2011-03-14 13:32                         ` Arnd Bergmann
  1 sibling, 1 reply; 29+ messages in thread
From: Russell King - ARM Linux @ 2011-03-14 12:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Mar 14, 2011 at 09:37:51PM +0900, KyongHo Cho wrote:
> I have also noticed that dma_map_single/page/sg() can map physical
> memory into an arbitrary device address region.
> But it is not enough solution for various kinds of IOMMUs.
> As Kukjin Kim addressed, we need to support larger page size than 4KB
> because we can reduce TLB miss when we have larger page size.
> 
> Our IOMMU(system mmu) supports all page size of ARM architecture
> including 16MB, 1MB, 64KB and 4KB.
> Since the largest size supported by buddy system of 32-bit architecture is 4MB,
> our system support all page sizes except 16MB.
> We proved that larger page size is helpful for DMA performance
> significantly (more than 10%, approximately).
> Big page size is not a problem for peripheral devices
> because their address space is not suffer from external fragmentation.

1. dma_map_single() et.al. is used for mapping *system* *RAM* for devices
   using whatever is necessary.  It must not be used for trying to setup
   arbitary other mappings.

2. It doesn't matter where the memory for dma_map_single() et.al. comes
   from provided the virtual address is a valid system RAM address or
   the struct page * is a valid struct page in the memory map (iow, you
   can't create this yourself.)

3. In the case of an IOMMU, the DMA API does not limit you to only using
   4K pages to setup the IOMMU mappings.  You can use whatever you like
   provided the hardware can cope with it.  You can coalesce several
   existing entries together provided you track what you're doing and can
   undo what's been done when the mapping is no longer required.

So really there's no reason not to use 64K, 1M and 16M IOMMU entries if
that's the size of buffer which has been passed to the DMA API.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-14 12:37                       ` KyongHo Cho
  2011-03-14 12:46                         ` Russell King - ARM Linux
@ 2011-03-14 13:32                         ` Arnd Bergmann
  1 sibling, 0 replies; 29+ messages in thread
From: Arnd Bergmann @ 2011-03-14 13:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 14 March 2011, KyongHo Cho wrote:
> I think we can consider another solution for the various requirements.
> I think one of the most possible solutions is VCMM.
> Or we can enhance include/linux/iommu.h with reference of VCMM.

I think extending or changing the existing interface would be much
preferred. It's always better to limit the number of interfaces
that do the same thing, and we already have more duplication than
we want with the two dma-mapping.h and iommu.h interfaces.

Note that any aspect of the existing interface can be changed if
necessary, as long as there is a way to migrate all the existing
users. Since the iommu API is not exported to user space, there
is no requirement to keep it stable.

	Arnd

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-14 12:46                         ` Russell King - ARM Linux
@ 2011-03-15  1:45                           ` InKi Dae
  2011-03-15  8:35                             ` Russell King - ARM Linux
  0 siblings, 1 reply; 29+ messages in thread
From: InKi Dae @ 2011-03-15  1:45 UTC (permalink / raw)
  To: linux-arm-kernel

2011/3/14 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Mon, Mar 14, 2011 at 09:37:51PM +0900, KyongHo Cho wrote:
>> I have also noticed that dma_map_single/page/sg() can map physical
>> memory into an arbitrary device address region.
>> But it is not enough solution for various kinds of IOMMUs.
>> As Kukjin Kim addressed, we need to support larger page size than 4KB
>> because we can reduce TLB miss when we have larger page size.
>>
>> Our IOMMU(system mmu) supports all page size of ARM architecture
>> including 16MB, 1MB, 64KB and 4KB.
>> Since the largest size supported by buddy system of 32-bit architecture is 4MB,
>> our system support all page sizes except 16MB.
>> We proved that larger page size is helpful for DMA performance
>> significantly (more than 10%, approximately).
>> Big page size is not a problem for peripheral devices
>> because their address space is not suffer from external fragmentation.
>
> 1. dma_map_single() et.al. is used for mapping *system* *RAM* for devices
> ? using whatever is necessary. ?It must not be used for trying to setup
> ? arbitary other mappings.
>
> 2. It doesn't matter where the memory for dma_map_single() et.al. comes
> ? from provided the virtual address is a valid system RAM address or
> ? the struct page * is a valid struct page in the memory map (iow, you
> ? can't create this yourself.)

You mean that we cannot have arbitrary virtual address mapping for
iommu based device?
actually, we have memory mapping to arbitrary device virtual address
space, not kernel virtual address space.

>
> 3. In the case of an IOMMU, the DMA API does not limit you to only using
> ? 4K pages to setup the IOMMU mappings. ?You can use whatever you like
> ? provided the hardware can cope with it. ?You can coalesce several
> ? existing entries together provided you track what you're doing and can
> ? undo what's been done when the mapping is no longer required.
>
> So really there's no reason not to use 64K, 1M and 16M IOMMU entries if
> that's the size of buffer which has been passed to the DMA API.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-15  1:45                           ` InKi Dae
@ 2011-03-15  8:35                             ` Russell King - ARM Linux
  2011-03-15  9:34                               ` daeinki
  0 siblings, 1 reply; 29+ messages in thread
From: Russell King - ARM Linux @ 2011-03-15  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 15, 2011 at 10:45:50AM +0900, InKi Dae wrote:
> 2011/3/14 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> > On Mon, Mar 14, 2011 at 09:37:51PM +0900, KyongHo Cho wrote:
> >> I have also noticed that dma_map_single/page/sg() can map physical
> >> memory into an arbitrary device address region.
> >> But it is not enough solution for various kinds of IOMMUs.
> >> As Kukjin Kim addressed, we need to support larger page size than 4KB
> >> because we can reduce TLB miss when we have larger page size.
> >>
> >> Our IOMMU(system mmu) supports all page size of ARM architecture
> >> including 16MB, 1MB, 64KB and 4KB.
> >> Since the largest size supported by buddy system of 32-bit architecture is 4MB,
> >> our system support all page sizes except 16MB.
> >> We proved that larger page size is helpful for DMA performance
> >> significantly (more than 10%, approximately).
> >> Big page size is not a problem for peripheral devices
> >> because their address space is not suffer from external fragmentation.
> >
> > 1. dma_map_single() et.al. is used for mapping *system* *RAM* for devices
> > ? using whatever is necessary. ?It must not be used for trying to setup
> > ? arbitary other mappings.
> >
> > 2. It doesn't matter where the memory for dma_map_single() et.al. comes
> > ? from provided the virtual address is a valid system RAM address or
> > ? the struct page * is a valid struct page in the memory map (iow, you
> > ? can't create this yourself.)
> 
> You mean that we cannot have arbitrary virtual address mapping for
> iommu based device?

No.  I mean exactly what I said - I'm talking about the DMA API in the
above two points.  The implication is that you can not create arbitary
mappings of non-system RAM with the DMA API.

> actually, we have memory mapping to arbitrary device virtual address
> space, not kernel virtual address space.
> 
> >
> > 3. In the case of an IOMMU, the DMA API does not limit you to only using
> > ? 4K pages to setup the IOMMU mappings. ?You can use whatever you like
> > ? provided the hardware can cope with it. ?You can coalesce several
> > ? existing entries together provided you track what you're doing and can
> > ? undo what's been done when the mapping is no longer required.
> >
> > So really there's no reason not to use 64K, 1M and 16M IOMMU entries if
> > that's the size of buffer which has been passed to the DMA API.
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-15  8:35                             ` Russell King - ARM Linux
@ 2011-03-15  9:34                               ` daeinki
  2011-03-15  9:53                                 ` Russell King - ARM Linux
  0 siblings, 1 reply; 29+ messages in thread
From: daeinki @ 2011-03-15  9:34 UTC (permalink / raw)
  To: linux-arm-kernel

Russell King - ARM Linux ? ?:
> On Tue, Mar 15, 2011 at 10:45:50AM +0900, InKi Dae wrote:
>> 2011/3/14 Russell King - ARM Linux <linux@arm.linux.org.uk>:
>>> On Mon, Mar 14, 2011 at 09:37:51PM +0900, KyongHo Cho wrote:
>>>> I have also noticed that dma_map_single/page/sg() can map physical
>>>> memory into an arbitrary device address region.
>>>> But it is not enough solution for various kinds of IOMMUs.
>>>> As Kukjin Kim addressed, we need to support larger page size than 4KB
>>>> because we can reduce TLB miss when we have larger page size.
>>>>
>>>> Our IOMMU(system mmu) supports all page size of ARM architecture
>>>> including 16MB, 1MB, 64KB and 4KB.
>>>> Since the largest size supported by buddy system of 32-bit architecture is 4MB,
>>>> our system support all page sizes except 16MB.
>>>> We proved that larger page size is helpful for DMA performance
>>>> significantly (more than 10%, approximately).
>>>> Big page size is not a problem for peripheral devices
>>>> because their address space is not suffer from external fragmentation.
>>> 1. dma_map_single() et.al. is used for mapping *system* *RAM* for devices
>>>   using whatever is necessary.  It must not be used for trying to setup
>>>   arbitary other mappings.
>>>
>>> 2. It doesn't matter where the memory for dma_map_single() et.al. comes
>>>   from provided the virtual address is a valid system RAM address or
>>>   the struct page * is a valid struct page in the memory map (iow, you
>>>   can't create this yourself.)
>> You mean that we cannot have arbitrary virtual address mapping for
>> iommu based device?
> 
> No.  I mean exactly what I said - I'm talking about the DMA API in the
> above two points.  The implication is that you can not create arbitary
> mappings of non-system RAM with the DMA API.
> 
sorry but I couldn't understand exactly what you said. could you give me 
your answer one more time?
does non-system RAM mean reserved memory regions? if not, is it 
arbitrary virtual address space that isn't kernel or user virtual 
address space and is the space for iommu based deivce?


>> actually, we have memory mapping to arbitrary device virtual address
>> space, not kernel virtual address space.
>>
>>> 3. In the case of an IOMMU, the DMA API does not limit you to only using
>>>   4K pages to setup the IOMMU mappings.  You can use whatever you like
>>>   provided the hardware can cope with it.  You can coalesce several
>>>   existing entries together provided you track what you're doing and can
>>>   undo what's been done when the mapping is no longer required.
>>>
>>> So really there's no reason not to use 64K, 1M and 16M IOMMU entries if
>>> that's the size of buffer which has been passed to the DMA API.
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver
  2011-03-15  9:34                               ` daeinki
@ 2011-03-15  9:53                                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 29+ messages in thread
From: Russell King - ARM Linux @ 2011-03-15  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 15, 2011 at 06:34:42PM +0900, daeinki wrote:
> Russell King - ARM Linux ? ?:
>> On Tue, Mar 15, 2011 at 10:45:50AM +0900, InKi Dae wrote:
>>> 2011/3/14 Russell King - ARM Linux <linux@arm.linux.org.uk>:
>>>> On Mon, Mar 14, 2011 at 09:37:51PM +0900, KyongHo Cho wrote:
>>>>> I have also noticed that dma_map_single/page/sg() can map physical
>>>>> memory into an arbitrary device address region.
>>>>> But it is not enough solution for various kinds of IOMMUs.
>>>>> As Kukjin Kim addressed, we need to support larger page size than 4KB
>>>>> because we can reduce TLB miss when we have larger page size.
>>>>>
>>>>> Our IOMMU(system mmu) supports all page size of ARM architecture
>>>>> including 16MB, 1MB, 64KB and 4KB.
>>>>> Since the largest size supported by buddy system of 32-bit architecture is 4MB,
>>>>> our system support all page sizes except 16MB.
>>>>> We proved that larger page size is helpful for DMA performance
>>>>> significantly (more than 10%, approximately).
>>>>> Big page size is not a problem for peripheral devices
>>>>> because their address space is not suffer from external fragmentation.
>>>> 1. dma_map_single() et.al. is used for mapping *system* *RAM* for devices
>>>>   using whatever is necessary.  It must not be used for trying to setup
>>>>   arbitary other mappings.
>>>>
>>>> 2. It doesn't matter where the memory for dma_map_single() et.al. comes
>>>>   from provided the virtual address is a valid system RAM address or
>>>>   the struct page * is a valid struct page in the memory map (iow, you
>>>>   can't create this yourself.)
>>> You mean that we cannot have arbitrary virtual address mapping for
>>> iommu based device?
>>
>> No.  I mean exactly what I said - I'm talking about the DMA API in the
>> above two points.  The implication is that you can not create arbitary
>> mappings of non-system RAM with the DMA API.
>>
> sorry but I couldn't understand exactly what you said. could you give me  
> your answer one more time?
> does non-system RAM mean reserved memory regions? if not, is it  
> arbitrary virtual address space that isn't kernel or user virtual  
> address space and is the space for iommu based deivce?

For dma_map_single(dev, addr, size, dir), basically:

	for (a = addr; a < addr + size; a += PAGE_SIZE)
		BUG_ON(!virt_addr_valid(a));

For dma_map_page(dev, page, offset, size, dir), 'page' must be something
obtained from one of the page-based kernel allocators (so either refering
to a page in the *existing* lowmem or highmem memory) _and_ you must not
use offset/size to then point@something outside that.

So, if you take something out of the kernel's knowledge of what is memory,
you can't then use the DMA API with it.

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2011-03-15  9:53 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-04  9:01 [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Marek Szyprowski
2011-03-04  9:01 ` [PATCH 1/7] ARM: S5PV310: Add platform definitions for FIMC Marek Szyprowski
2011-03-12  0:27   ` Kukjin Kim
2011-03-04  9:01 ` [PATCH 2/7] ARM: S5PV310: power domains: fixes and code cleanup Marek Szyprowski
2011-03-04  9:01 ` [PATCH 3/7] ARM: Samsung: update/rewrite Samsung SYSMMU (IOMMU) driver Marek Szyprowski
2011-03-04 16:04   ` Marek Szyprowski
2011-03-10 14:52     ` Arnd Bergmann
2011-03-11  9:04       ` Marek Szyprowski
2011-03-11 11:50         ` Arnd Bergmann
2011-03-11 12:35           ` Marek Szyprowski
2011-03-11 14:07             ` Arnd Bergmann
2011-03-11 14:51               ` Marek Szyprowski
2011-03-11 15:15                 ` Arnd Bergmann
2011-03-11 15:39                   ` Marek Szyprowski
2011-03-11 16:00                     ` Arnd Bergmann
2011-03-14 12:37                       ` KyongHo Cho
2011-03-14 12:46                         ` Russell King - ARM Linux
2011-03-15  1:45                           ` InKi Dae
2011-03-15  8:35                             ` Russell King - ARM Linux
2011-03-15  9:34                               ` daeinki
2011-03-15  9:53                                 ` Russell King - ARM Linux
2011-03-14 13:32                         ` Arnd Bergmann
2011-03-04  9:01 ` [PATCH 4/7] v4l: videobuf2: add Samsung SYSMMU (IOMMU) based allocator Marek Szyprowski
2011-03-04  9:01 ` [PATCH 5/7] s5p-fimc: add pm_runtime support Marek Szyprowski
2011-03-04  9:01 ` [PATCH 6/7] s5p-fimc: Add support for vb2-s5p-iommu allocator Marek Szyprowski
2011-03-04  9:01 ` [PATCH 7/7] ARM: S5PC210: enable FIMC on Universal_C210 Marek Szyprowski
2011-03-08  7:28 ` [PATCH/RFC 0/7] Samsung IOMMU videobuf2 allocator and s5p-fimc update Kukjin Kim
2011-03-08  9:34   ` Marek Szyprowski
2011-03-08 10:05     ` InKi Dae

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).