aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKukjin Kim <kgene.kim@samsung.com>2012-05-12 02:31:37 -0400
committerKukjin Kim <kgene.kim@samsung.com>2012-05-12 02:31:37 -0400
commitad28536a898fbdc8c57d64348e310e1bda776963 (patch)
treeb057f2d095797399ce6ef01312359712e4b67b15
parent18c411b7974f47f84c29507bdf3e0573890c0f0e (diff)
parent2a96536e77b43cf1e70ab3ad8b46b98ab52b56c1 (diff)
Merge branch 'next/devel-samsung-iommu' into next/devel-samsung
Conflicts: arch/arm/mach-exynos/Makefile
-rw-r--r--arch/arm/mach-exynos/Kconfig10
-rw-r--r--arch/arm/mach-exynos/Makefile4
-rw-r--r--arch/arm/mach-exynos/clock-exynos4.c79
-rw-r--r--arch/arm/mach-exynos/clock-exynos4.h2
-rw-r--r--arch/arm/mach-exynos/clock-exynos4210.c11
-rw-r--r--arch/arm/mach-exynos/clock-exynos4212.c28
-rw-r--r--arch/arm/mach-exynos/clock-exynos5.c90
-rw-r--r--arch/arm/mach-exynos/dev-sysmmu.c457
-rw-r--r--arch/arm/mach-exynos/include/mach/irqs.h25
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h38
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-clock.h5
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-sysmmu.h28
-rw-r--r--arch/arm/mach-exynos/include/mach/sysmmu.h88
-rw-r--r--arch/arm/mach-exynos/mach-armlex4210.c1
-rw-r--r--arch/arm/mach-exynos/mach-smdkv310.c1
-rw-r--r--arch/arm/plat-s5p/Kconfig8
-rw-r--r--arch/arm/plat-s5p/Makefile1
-rw-r--r--arch/arm/plat-s5p/sysmmu.c313
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/sysmmu.h95
-rw-r--r--drivers/iommu/Kconfig21
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/exynos-iommu.c1076
23 files changed, 1628 insertions, 755 deletions
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 8bc89f27e9da..88898ef5261a 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -90,10 +90,10 @@ config EXYNOS4_SETUP_FIMD0
90 help 90 help
91 Common setup code for FIMD0. 91 Common setup code for FIMD0.
92 92
93config EXYNOS4_DEV_SYSMMU 93config EXYNOS_DEV_SYSMMU
94 bool 94 bool
95 help 95 help
96 Common setup code for SYSTEM MMU in EXYNOS4 96 Common setup code for SYSTEM MMU in EXYNOS platforms
97 97
98config EXYNOS4_DEV_DWMCI 98config EXYNOS4_DEV_DWMCI
99 bool 99 bool
@@ -205,12 +205,12 @@ config MACH_SMDKV310
205 select S3C_DEV_HSMMC2 205 select S3C_DEV_HSMMC2
206 select S3C_DEV_HSMMC3 206 select S3C_DEV_HSMMC3
207 select SAMSUNG_DEV_BACKLIGHT 207 select SAMSUNG_DEV_BACKLIGHT
208 select EXYNOS_DEV_SYSMMU
208 select EXYNOS4_DEV_AHCI 209 select EXYNOS4_DEV_AHCI
209 select SAMSUNG_DEV_KEYPAD 210 select SAMSUNG_DEV_KEYPAD
210 select EXYNOS4_DEV_DMA 211 select EXYNOS4_DEV_DMA
211 select SAMSUNG_DEV_PWM 212 select SAMSUNG_DEV_PWM
212 select EXYNOS4_DEV_USB_OHCI 213 select EXYNOS4_DEV_USB_OHCI
213 select EXYNOS4_DEV_SYSMMU
214 select EXYNOS4_SETUP_FIMD0 214 select EXYNOS4_SETUP_FIMD0
215 select EXYNOS4_SETUP_I2C1 215 select EXYNOS4_SETUP_I2C1
216 select EXYNOS4_SETUP_KEYPAD 216 select EXYNOS4_SETUP_KEYPAD
@@ -229,7 +229,6 @@ config MACH_ARMLEX4210
229 select S3C_DEV_HSMMC3 229 select S3C_DEV_HSMMC3
230 select EXYNOS4_DEV_AHCI 230 select EXYNOS4_DEV_AHCI
231 select EXYNOS4_DEV_DMA 231 select EXYNOS4_DEV_DMA
232 select EXYNOS4_DEV_SYSMMU
233 select EXYNOS4_SETUP_SDHCI 232 select EXYNOS4_SETUP_SDHCI
234 help 233 help
235 Machine support for Samsung ARMLEX4210 based on EXYNOS4210 234 Machine support for Samsung ARMLEX4210 based on EXYNOS4210
@@ -256,6 +255,7 @@ config MACH_UNIVERSAL_C210
256 select S5P_DEV_MFC 255 select S5P_DEV_MFC
257 select S5P_DEV_ONENAND 256 select S5P_DEV_ONENAND
258 select S5P_DEV_TV 257 select S5P_DEV_TV
258 select EXYNOS_DEV_SYSMMU
259 select EXYNOS4_DEV_DMA 259 select EXYNOS4_DEV_DMA
260 select EXYNOS4_SETUP_FIMD0 260 select EXYNOS4_SETUP_FIMD0
261 select EXYNOS4_SETUP_I2C1 261 select EXYNOS4_SETUP_I2C1
@@ -327,6 +327,7 @@ config MACH_ORIGEN
327 select S5P_DEV_USB_EHCI 327 select S5P_DEV_USB_EHCI
328 select SAMSUNG_DEV_BACKLIGHT 328 select SAMSUNG_DEV_BACKLIGHT
329 select SAMSUNG_DEV_PWM 329 select SAMSUNG_DEV_PWM
330 select EXYNOS_DEV_SYSMMU
330 select EXYNOS4_DEV_DMA 331 select EXYNOS4_DEV_DMA
331 select EXYNOS4_DEV_USB_OHCI 332 select EXYNOS4_DEV_USB_OHCI
332 select EXYNOS4_SETUP_FIMD0 333 select EXYNOS4_SETUP_FIMD0
@@ -350,6 +351,7 @@ config MACH_SMDK4212
350 select SAMSUNG_DEV_BACKLIGHT 351 select SAMSUNG_DEV_BACKLIGHT
351 select SAMSUNG_DEV_KEYPAD 352 select SAMSUNG_DEV_KEYPAD
352 select SAMSUNG_DEV_PWM 353 select SAMSUNG_DEV_PWM
354 select EXYNOS_DEV_SYSMMU
353 select EXYNOS4_DEV_DMA 355 select EXYNOS4_DEV_DMA
354 select EXYNOS4_SETUP_I2C1 356 select EXYNOS4_SETUP_I2C1
355 select EXYNOS4_SETUP_I2C3 357 select EXYNOS4_SETUP_I2C3
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index f67e882b9dab..bd7e7654a250 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -50,11 +50,11 @@ obj-$(CONFIG_MACH_EXYNOS5_DT) += mach-exynos5-dt.o
50obj-y += dev-uart.o 50obj-y += dev-uart.o
51obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o 51obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o
52obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o 52obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o
53obj-$(CONFIG_EXYNOS_DEV_DRM) += dev-drm.o
54obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
55obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o 53obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
56obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o 54obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
57obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o 55obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
56obj-$(CONFIG_EXYNOS_DEV_DRM) += dev-drm.o
57obj-$(CONFIG_EXYNOS_DEV_SYSMMU) += dev-sysmmu.o
58 58
59obj-$(CONFIG_ARCH_EXYNOS) += setup-i2c0.o 59obj-$(CONFIG_ARCH_EXYNOS) += setup-i2c0.o
60obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o 60obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
index 6efd1e5919fd..bcb7db453145 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -168,7 +168,7 @@ static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable)
168 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_TV, clk, enable); 168 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_TV, clk, enable);
169} 169}
170 170
171static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable) 171int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable)
172{ 172{
173 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_IMAGE, clk, enable); 173 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_IMAGE, clk, enable);
174} 174}
@@ -198,6 +198,11 @@ static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable)
198 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIR, clk, enable); 198 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIR, clk, enable);
199} 199}
200 200
201int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable)
202{
203 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_DMC, clk, enable);
204}
205
201static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable) 206static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable)
202{ 207{
203 return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable); 208 return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
@@ -678,61 +683,55 @@ static struct clk exynos4_init_clocks_off[] = {
678 .enable = exynos4_clk_ip_peril_ctrl, 683 .enable = exynos4_clk_ip_peril_ctrl,
679 .ctrlbit = (1 << 14), 684 .ctrlbit = (1 << 14),
680 }, { 685 }, {
681 .name = "SYSMMU_MDMA", 686 .name = SYSMMU_CLOCK_NAME,
687 .devname = SYSMMU_CLOCK_DEVNAME(mfc_l, 0),
688 .enable = exynos4_clk_ip_mfc_ctrl,
689 .ctrlbit = (1 << 1),
690 }, {
691 .name = SYSMMU_CLOCK_NAME,
692 .devname = SYSMMU_CLOCK_DEVNAME(mfc_r, 1),
693 .enable = exynos4_clk_ip_mfc_ctrl,
694 .ctrlbit = (1 << 2),
695 }, {
696 .name = SYSMMU_CLOCK_NAME,
697 .devname = SYSMMU_CLOCK_DEVNAME(tv, 2),
698 .enable = exynos4_clk_ip_tv_ctrl,
699 .ctrlbit = (1 << 4),
700 }, {
701 .name = SYSMMU_CLOCK_NAME,
702 .devname = SYSMMU_CLOCK_DEVNAME(jpeg, 3),
703 .enable = exynos4_clk_ip_cam_ctrl,
704 .ctrlbit = (1 << 11),
705 }, {
706 .name = SYSMMU_CLOCK_NAME,
707 .devname = SYSMMU_CLOCK_DEVNAME(rot, 4),
682 .enable = exynos4_clk_ip_image_ctrl, 708 .enable = exynos4_clk_ip_image_ctrl,
683 .ctrlbit = (1 << 5), 709 .ctrlbit = (1 << 4),
684 }, { 710 }, {
685 .name = "SYSMMU_FIMC0", 711 .name = SYSMMU_CLOCK_NAME,
712 .devname = SYSMMU_CLOCK_DEVNAME(fimc0, 5),
686 .enable = exynos4_clk_ip_cam_ctrl, 713 .enable = exynos4_clk_ip_cam_ctrl,
687 .ctrlbit = (1 << 7), 714 .ctrlbit = (1 << 7),
688 }, { 715 }, {
689 .name = "SYSMMU_FIMC1", 716 .name = SYSMMU_CLOCK_NAME,
717 .devname = SYSMMU_CLOCK_DEVNAME(fimc1, 6),
690 .enable = exynos4_clk_ip_cam_ctrl, 718 .enable = exynos4_clk_ip_cam_ctrl,
691 .ctrlbit = (1 << 8), 719 .ctrlbit = (1 << 8),
692 }, { 720 }, {
693 .name = "SYSMMU_FIMC2", 721 .name = SYSMMU_CLOCK_NAME,
722 .devname = SYSMMU_CLOCK_DEVNAME(fimc2, 7),
694 .enable = exynos4_clk_ip_cam_ctrl, 723 .enable = exynos4_clk_ip_cam_ctrl,
695 .ctrlbit = (1 << 9), 724 .ctrlbit = (1 << 9),
696 }, { 725 }, {
697 .name = "SYSMMU_FIMC3", 726 .name = SYSMMU_CLOCK_NAME,
727 .devname = SYSMMU_CLOCK_DEVNAME(fimc3, 8),
698 .enable = exynos4_clk_ip_cam_ctrl, 728 .enable = exynos4_clk_ip_cam_ctrl,
699 .ctrlbit = (1 << 10), 729 .ctrlbit = (1 << 10),
700 }, { 730 }, {
701 .name = "SYSMMU_JPEG", 731 .name = SYSMMU_CLOCK_NAME,
702 .enable = exynos4_clk_ip_cam_ctrl, 732 .devname = SYSMMU_CLOCK_DEVNAME(fimd0, 10),
703 .ctrlbit = (1 << 11),
704 }, {
705 .name = "SYSMMU_FIMD0",
706 .enable = exynos4_clk_ip_lcd0_ctrl, 733 .enable = exynos4_clk_ip_lcd0_ctrl,
707 .ctrlbit = (1 << 4), 734 .ctrlbit = (1 << 4),
708 }, {
709 .name = "SYSMMU_FIMD1",
710 .enable = exynos4_clk_ip_lcd1_ctrl,
711 .ctrlbit = (1 << 4),
712 }, {
713 .name = "SYSMMU_PCIe",
714 .enable = exynos4_clk_ip_fsys_ctrl,
715 .ctrlbit = (1 << 18),
716 }, {
717 .name = "SYSMMU_G2D",
718 .enable = exynos4_clk_ip_image_ctrl,
719 .ctrlbit = (1 << 3),
720 }, {
721 .name = "SYSMMU_ROTATOR",
722 .enable = exynos4_clk_ip_image_ctrl,
723 .ctrlbit = (1 << 4),
724 }, {
725 .name = "SYSMMU_TV",
726 .enable = exynos4_clk_ip_tv_ctrl,
727 .ctrlbit = (1 << 4),
728 }, {
729 .name = "SYSMMU_MFC_L",
730 .enable = exynos4_clk_ip_mfc_ctrl,
731 .ctrlbit = (1 << 1),
732 }, {
733 .name = "SYSMMU_MFC_R",
734 .enable = exynos4_clk_ip_mfc_ctrl,
735 .ctrlbit = (1 << 2),
736 } 735 }
737}; 736};
738 737
diff --git a/arch/arm/mach-exynos/clock-exynos4.h b/arch/arm/mach-exynos/clock-exynos4.h
index cb71c29c14d1..28a119701182 100644
--- a/arch/arm/mach-exynos/clock-exynos4.h
+++ b/arch/arm/mach-exynos/clock-exynos4.h
@@ -26,5 +26,7 @@ extern struct clk *exynos4_clkset_group_list[];
26extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable); 26extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable);
27extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable); 27extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable);
28extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable); 28extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable);
29extern int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable);
30extern int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable);
29 31
30#endif /* __ASM_ARCH_CLOCK_H */ 32#endif /* __ASM_ARCH_CLOCK_H */
diff --git a/arch/arm/mach-exynos/clock-exynos4210.c b/arch/arm/mach-exynos/clock-exynos4210.c
index 3b131e4b6ef5..b8689ff60baf 100644
--- a/arch/arm/mach-exynos/clock-exynos4210.c
+++ b/arch/arm/mach-exynos/clock-exynos4210.c
@@ -26,6 +26,7 @@
26#include <mach/hardware.h> 26#include <mach/hardware.h>
27#include <mach/map.h> 27#include <mach/map.h>
28#include <mach/regs-clock.h> 28#include <mach/regs-clock.h>
29#include <mach/sysmmu.h>
29 30
30#include "common.h" 31#include "common.h"
31#include "clock-exynos4.h" 32#include "clock-exynos4.h"
@@ -94,6 +95,16 @@ static struct clk init_clocks_off[] = {
94 .devname = "exynos4-fb.1", 95 .devname = "exynos4-fb.1",
95 .enable = exynos4_clk_ip_lcd1_ctrl, 96 .enable = exynos4_clk_ip_lcd1_ctrl,
96 .ctrlbit = (1 << 0), 97 .ctrlbit = (1 << 0),
98 }, {
99 .name = SYSMMU_CLOCK_NAME,
100 .devname = SYSMMU_CLOCK_DEVNAME(2d, 14),
101 .enable = exynos4_clk_ip_image_ctrl,
102 .ctrlbit = (1 << 3),
103 }, {
104 .name = SYSMMU_CLOCK_NAME,
105 .devname = SYSMMU_CLOCK_DEVNAME(fimd1, 11),
106 .enable = exynos4_clk_ip_lcd1_ctrl,
107 .ctrlbit = (1 << 4),
97 }, 108 },
98}; 109};
99 110
diff --git a/arch/arm/mach-exynos/clock-exynos4212.c b/arch/arm/mach-exynos/clock-exynos4212.c
index 3ecc01e06f74..98823120570e 100644
--- a/arch/arm/mach-exynos/clock-exynos4212.c
+++ b/arch/arm/mach-exynos/clock-exynos4212.c
@@ -26,6 +26,7 @@
26#include <mach/hardware.h> 26#include <mach/hardware.h>
27#include <mach/map.h> 27#include <mach/map.h>
28#include <mach/regs-clock.h> 28#include <mach/regs-clock.h>
29#include <mach/sysmmu.h>
29 30
30#include "common.h" 31#include "common.h"
31#include "clock-exynos4.h" 32#include "clock-exynos4.h"
@@ -39,6 +40,16 @@ static struct sleep_save exynos4212_clock_save[] = {
39}; 40};
40#endif 41#endif
41 42
43static int exynos4212_clk_ip_isp0_ctrl(struct clk *clk, int enable)
44{
45 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_ISP0, clk, enable);
46}
47
48static int exynos4212_clk_ip_isp1_ctrl(struct clk *clk, int enable)
49{
50 return s5p_gatectrl(EXYNOS4_CLKGATE_IP_ISP1, clk, enable);
51}
52
42static struct clk *clk_src_mpll_user_list[] = { 53static struct clk *clk_src_mpll_user_list[] = {
43 [0] = &clk_fin_mpll, 54 [0] = &clk_fin_mpll,
44 [1] = &exynos4_clk_mout_mpll.clk, 55 [1] = &exynos4_clk_mout_mpll.clk,
@@ -66,7 +77,22 @@ static struct clksrc_clk clksrcs[] = {
66}; 77};
67 78
68static struct clk init_clocks_off[] = { 79static struct clk init_clocks_off[] = {
69 /* nothing here yet */ 80 {
81 .name = SYSMMU_CLOCK_NAME,
82 .devname = SYSMMU_CLOCK_DEVNAME(2d, 14),
83 .enable = exynos4_clk_ip_dmc_ctrl,
84 .ctrlbit = (1 << 24),
85 }, {
86 .name = SYSMMU_CLOCK_NAME,
87 .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
88 .enable = exynos4212_clk_ip_isp0_ctrl,
89 .ctrlbit = (7 << 8),
90 }, {
91 .name = SYSMMU_CLOCK_NAME2,
92 .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
93 .enable = exynos4212_clk_ip_isp1_ctrl,
94 .ctrlbit = (1 << 4),
95 }
70}; 96};
71 97
72#ifdef CONFIG_PM_SLEEP 98#ifdef CONFIG_PM_SLEEP
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
index 5cd7a8b8868c..ad3bec4f1fa6 100644
--- a/arch/arm/mach-exynos/clock-exynos5.c
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -82,6 +82,11 @@ static int exynos5_clksrc_mask_peric0_ctrl(struct clk *clk, int enable)
82 return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable); 82 return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable);
83} 83}
84 84
85static int exynos5_clk_ip_acp_ctrl(struct clk *clk, int enable)
86{
87 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ACP, clk, enable);
88}
89
85static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable) 90static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable)
86{ 91{
87 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable); 92 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable);
@@ -127,6 +132,21 @@ static int exynos5_clk_ip_peris_ctrl(struct clk *clk, int enable)
127 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable); 132 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable);
128} 133}
129 134
135static int exynos5_clk_ip_gscl_ctrl(struct clk *clk, int enable)
136{
137 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GSCL, clk, enable);
138}
139
140static int exynos5_clk_ip_isp0_ctrl(struct clk *clk, int enable)
141{
142 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP0, clk, enable);
143}
144
145static int exynos5_clk_ip_isp1_ctrl(struct clk *clk, int enable)
146{
147 return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP1, clk, enable);
148}
149
130/* Core list of CMU_CPU side */ 150/* Core list of CMU_CPU side */
131 151
132static struct clksrc_clk exynos5_clk_mout_apll = { 152static struct clksrc_clk exynos5_clk_mout_apll = {
@@ -630,6 +650,76 @@ static struct clk exynos5_init_clocks_off[] = {
630 .parent = &exynos5_clk_aclk_66.clk, 650 .parent = &exynos5_clk_aclk_66.clk,
631 .enable = exynos5_clk_ip_peric_ctrl, 651 .enable = exynos5_clk_ip_peric_ctrl,
632 .ctrlbit = (1 << 14), 652 .ctrlbit = (1 << 14),
653 }, {
654 .name = SYSMMU_CLOCK_NAME,
655 .devname = SYSMMU_CLOCK_DEVNAME(mfc_l, 0),
656 .enable = &exynos5_clk_ip_mfc_ctrl,
657 .ctrlbit = (1 << 1),
658 }, {
659 .name = SYSMMU_CLOCK_NAME,
660 .devname = SYSMMU_CLOCK_DEVNAME(mfc_r, 1),
661 .enable = &exynos5_clk_ip_mfc_ctrl,
662 .ctrlbit = (1 << 2),
663 }, {
664 .name = SYSMMU_CLOCK_NAME,
665 .devname = SYSMMU_CLOCK_DEVNAME(tv, 2),
666 .enable = &exynos5_clk_ip_disp1_ctrl,
667 .ctrlbit = (1 << 9)
668 }, {
669 .name = SYSMMU_CLOCK_NAME,
670 .devname = SYSMMU_CLOCK_DEVNAME(jpeg, 3),
671 .enable = &exynos5_clk_ip_gen_ctrl,
672 .ctrlbit = (1 << 7),
673 }, {
674 .name = SYSMMU_CLOCK_NAME,
675 .devname = SYSMMU_CLOCK_DEVNAME(rot, 4),
676 .enable = &exynos5_clk_ip_gen_ctrl,
677 .ctrlbit = (1 << 6)
678 }, {
679 .name = SYSMMU_CLOCK_NAME,
680 .devname = SYSMMU_CLOCK_DEVNAME(gsc0, 5),
681 .enable = &exynos5_clk_ip_gscl_ctrl,
682 .ctrlbit = (1 << 7),
683 }, {
684 .name = SYSMMU_CLOCK_NAME,
685 .devname = SYSMMU_CLOCK_DEVNAME(gsc1, 6),
686 .enable = &exynos5_clk_ip_gscl_ctrl,
687 .ctrlbit = (1 << 8),
688 }, {
689 .name = SYSMMU_CLOCK_NAME,
690 .devname = SYSMMU_CLOCK_DEVNAME(gsc2, 7),
691 .enable = &exynos5_clk_ip_gscl_ctrl,
692 .ctrlbit = (1 << 9),
693 }, {
694 .name = SYSMMU_CLOCK_NAME,
695 .devname = SYSMMU_CLOCK_DEVNAME(gsc3, 8),
696 .enable = &exynos5_clk_ip_gscl_ctrl,
697 .ctrlbit = (1 << 10),
698 }, {
699 .name = SYSMMU_CLOCK_NAME,
700 .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
701 .enable = &exynos5_clk_ip_isp0_ctrl,
702 .ctrlbit = (0x3F << 8),
703 }, {
704 .name = SYSMMU_CLOCK_NAME2,
705 .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
706 .enable = &exynos5_clk_ip_isp1_ctrl,
707 .ctrlbit = (0xF << 4),
708 }, {
709 .name = SYSMMU_CLOCK_NAME,
710 .devname = SYSMMU_CLOCK_DEVNAME(camif0, 12),
711 .enable = &exynos5_clk_ip_gscl_ctrl,
712 .ctrlbit = (1 << 11),
713 }, {
714 .name = SYSMMU_CLOCK_NAME,
715 .devname = SYSMMU_CLOCK_DEVNAME(camif1, 13),
716 .enable = &exynos5_clk_ip_gscl_ctrl,
717 .ctrlbit = (1 << 12),
718 }, {
719 .name = SYSMMU_CLOCK_NAME,
720 .devname = SYSMMU_CLOCK_DEVNAME(2d, 14),
721 .enable = &exynos5_clk_ip_acp_ctrl,
722 .ctrlbit = (1 << 7)
633 } 723 }
634}; 724};
635 725
diff --git a/arch/arm/mach-exynos/dev-sysmmu.c b/arch/arm/mach-exynos/dev-sysmmu.c
index 781563fcb156..c5b1ea301df0 100644
--- a/arch/arm/mach-exynos/dev-sysmmu.c
+++ b/arch/arm/mach-exynos/dev-sysmmu.c
@@ -1,9 +1,9 @@
1/* linux/arch/arm/mach-exynos4/dev-sysmmu.c 1/* linux/arch/arm/mach-exynos/dev-sysmmu.c
2 * 2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd. 3 * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com 4 * http://www.samsung.com
5 * 5 *
6 * EXYNOS4 - System MMU support 6 * EXYNOS - System MMU support
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -12,222 +12,263 @@
12 12
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14#include <linux/dma-mapping.h> 14#include <linux/dma-mapping.h>
15#include <linux/export.h> 15
16#include <plat/cpu.h>
16 17
17#include <mach/map.h> 18#include <mach/map.h>
18#include <mach/irqs.h> 19#include <mach/irqs.h>
19#include <mach/sysmmu.h> 20#include <mach/sysmmu.h>
20#include <plat/s5p-clock.h>
21
22/* These names must be equal to the clock names in mach-exynos4/clock.c */
23const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = {
24 "SYSMMU_MDMA" ,
25 "SYSMMU_SSS" ,
26 "SYSMMU_FIMC0" ,
27 "SYSMMU_FIMC1" ,
28 "SYSMMU_FIMC2" ,
29 "SYSMMU_FIMC3" ,
30 "SYSMMU_JPEG" ,
31 "SYSMMU_FIMD0" ,
32 "SYSMMU_FIMD1" ,
33 "SYSMMU_PCIe" ,
34 "SYSMMU_G2D" ,
35 "SYSMMU_ROTATOR",
36 "SYSMMU_MDMA2" ,
37 "SYSMMU_TV" ,
38 "SYSMMU_MFC_L" ,
39 "SYSMMU_MFC_R" ,
40};
41 21
42static struct resource exynos4_sysmmu_resource[] = { 22static u64 exynos_sysmmu_dma_mask = DMA_BIT_MASK(32);
43 [0] = { 23
44 .start = EXYNOS4_PA_SYSMMU_MDMA, 24#define SYSMMU_PLATFORM_DEVICE(ipname, devid) \
45 .end = EXYNOS4_PA_SYSMMU_MDMA + SZ_64K - 1, 25static struct sysmmu_platform_data platdata_##ipname = { \
46 .flags = IORESOURCE_MEM, 26 .dbgname = #ipname, \
47 }, 27}; \
48 [1] = { 28struct platform_device SYSMMU_PLATDEV(ipname) = \
49 .start = IRQ_SYSMMU_MDMA0_0, 29{ \
50 .end = IRQ_SYSMMU_MDMA0_0, 30 .name = SYSMMU_DEVNAME_BASE, \
51 .flags = IORESOURCE_IRQ, 31 .id = devid, \
52 }, 32 .dev = { \
53 [2] = { 33 .dma_mask = &exynos_sysmmu_dma_mask, \
54 .start = EXYNOS4_PA_SYSMMU_SSS, 34 .coherent_dma_mask = DMA_BIT_MASK(32), \
55 .end = EXYNOS4_PA_SYSMMU_SSS + SZ_64K - 1, 35 .platform_data = &platdata_##ipname, \
56 .flags = IORESOURCE_MEM, 36 }, \
57 }, 37}
58 [3] = { 38
59 .start = IRQ_SYSMMU_SSS_0, 39SYSMMU_PLATFORM_DEVICE(mfc_l, 0);
60 .end = IRQ_SYSMMU_SSS_0, 40SYSMMU_PLATFORM_DEVICE(mfc_r, 1);
61 .flags = IORESOURCE_IRQ, 41SYSMMU_PLATFORM_DEVICE(tv, 2);
62 }, 42SYSMMU_PLATFORM_DEVICE(jpeg, 3);
63 [4] = { 43SYSMMU_PLATFORM_DEVICE(rot, 4);
64 .start = EXYNOS4_PA_SYSMMU_FIMC0, 44SYSMMU_PLATFORM_DEVICE(fimc0, 5); /* fimc* and gsc* exist exclusively */
65 .end = EXYNOS4_PA_SYSMMU_FIMC0 + SZ_64K - 1, 45SYSMMU_PLATFORM_DEVICE(fimc1, 6);
66 .flags = IORESOURCE_MEM, 46SYSMMU_PLATFORM_DEVICE(fimc2, 7);
67 }, 47SYSMMU_PLATFORM_DEVICE(fimc3, 8);
68 [5] = { 48SYSMMU_PLATFORM_DEVICE(gsc0, 5);
69 .start = IRQ_SYSMMU_FIMC0_0, 49SYSMMU_PLATFORM_DEVICE(gsc1, 6);
70 .end = IRQ_SYSMMU_FIMC0_0, 50SYSMMU_PLATFORM_DEVICE(gsc2, 7);
71 .flags = IORESOURCE_IRQ, 51SYSMMU_PLATFORM_DEVICE(gsc3, 8);
72 }, 52SYSMMU_PLATFORM_DEVICE(isp, 9);
73 [6] = { 53SYSMMU_PLATFORM_DEVICE(fimd0, 10);
74 .start = EXYNOS4_PA_SYSMMU_FIMC1, 54SYSMMU_PLATFORM_DEVICE(fimd1, 11);
75 .end = EXYNOS4_PA_SYSMMU_FIMC1 + SZ_64K - 1, 55SYSMMU_PLATFORM_DEVICE(camif0, 12);
76 .flags = IORESOURCE_MEM, 56SYSMMU_PLATFORM_DEVICE(camif1, 13);
77 }, 57SYSMMU_PLATFORM_DEVICE(2d, 14);
78 [7] = { 58
79 .start = IRQ_SYSMMU_FIMC1_0, 59#define SYSMMU_RESOURCE_NAME(core, ipname) sysmmures_##core##_##ipname
80 .end = IRQ_SYSMMU_FIMC1_0, 60
81 .flags = IORESOURCE_IRQ, 61#define SYSMMU_RESOURCE(core, ipname) \
82 }, 62 static struct resource SYSMMU_RESOURCE_NAME(core, ipname)[] __initdata =
83 [8] = { 63
84 .start = EXYNOS4_PA_SYSMMU_FIMC2, 64#define DEFINE_SYSMMU_RESOURCE(core, mem, irq) \
85 .end = EXYNOS4_PA_SYSMMU_FIMC2 + SZ_64K - 1, 65 DEFINE_RES_MEM_NAMED(core##_PA_SYSMMU_##mem, SZ_4K, #mem), \
86 .flags = IORESOURCE_MEM, 66 DEFINE_RES_IRQ_NAMED(core##_IRQ_SYSMMU_##irq##_0, #mem)
87 }, 67
88 [9] = { 68#define SYSMMU_RESOURCE_DEFINE(core, ipname, mem, irq) \
89 .start = IRQ_SYSMMU_FIMC2_0, 69 SYSMMU_RESOURCE(core, ipname) { \
90 .end = IRQ_SYSMMU_FIMC2_0, 70 DEFINE_SYSMMU_RESOURCE(core, mem, irq) \
91 .flags = IORESOURCE_IRQ, 71 }
92 },
93 [10] = {
94 .start = EXYNOS4_PA_SYSMMU_FIMC3,
95 .end = EXYNOS4_PA_SYSMMU_FIMC3 + SZ_64K - 1,
96 .flags = IORESOURCE_MEM,
97 },
98 [11] = {
99 .start = IRQ_SYSMMU_FIMC3_0,
100 .end = IRQ_SYSMMU_FIMC3_0,
101 .flags = IORESOURCE_IRQ,
102 },
103 [12] = {
104 .start = EXYNOS4_PA_SYSMMU_JPEG,
105 .end = EXYNOS4_PA_SYSMMU_JPEG + SZ_64K - 1,
106 .flags = IORESOURCE_MEM,
107 },
108 [13] = {
109 .start = IRQ_SYSMMU_JPEG_0,
110 .end = IRQ_SYSMMU_JPEG_0,
111 .flags = IORESOURCE_IRQ,
112 },
113 [14] = {
114 .start = EXYNOS4_PA_SYSMMU_FIMD0,
115 .end = EXYNOS4_PA_SYSMMU_FIMD0 + SZ_64K - 1,
116 .flags = IORESOURCE_MEM,
117 },
118 [15] = {
119 .start = IRQ_SYSMMU_LCD0_M0_0,
120 .end = IRQ_SYSMMU_LCD0_M0_0,
121 .flags = IORESOURCE_IRQ,
122 },
123 [16] = {
124 .start = EXYNOS4_PA_SYSMMU_FIMD1,
125 .end = EXYNOS4_PA_SYSMMU_FIMD1 + SZ_64K - 1,
126 .flags = IORESOURCE_MEM,
127 },
128 [17] = {
129 .start = IRQ_SYSMMU_LCD1_M1_0,
130 .end = IRQ_SYSMMU_LCD1_M1_0,
131 .flags = IORESOURCE_IRQ,
132 },
133 [18] = {
134 .start = EXYNOS4_PA_SYSMMU_PCIe,
135 .end = EXYNOS4_PA_SYSMMU_PCIe + SZ_64K - 1,
136 .flags = IORESOURCE_MEM,
137 },
138 [19] = {
139 .start = IRQ_SYSMMU_PCIE_0,
140 .end = IRQ_SYSMMU_PCIE_0,
141 .flags = IORESOURCE_IRQ,
142 },
143 [20] = {
144 .start = EXYNOS4_PA_SYSMMU_G2D,
145 .end = EXYNOS4_PA_SYSMMU_G2D + SZ_64K - 1,
146 .flags = IORESOURCE_MEM,
147 },
148 [21] = {
149 .start = IRQ_SYSMMU_2D_0,
150 .end = IRQ_SYSMMU_2D_0,
151 .flags = IORESOURCE_IRQ,
152 },
153 [22] = {
154 .start = EXYNOS4_PA_SYSMMU_ROTATOR,
155 .end = EXYNOS4_PA_SYSMMU_ROTATOR + SZ_64K - 1,
156 .flags = IORESOURCE_MEM,
157 },
158 [23] = {
159 .start = IRQ_SYSMMU_ROTATOR_0,
160 .end = IRQ_SYSMMU_ROTATOR_0,
161 .flags = IORESOURCE_IRQ,
162 },
163 [24] = {
164 .start = EXYNOS4_PA_SYSMMU_MDMA2,
165 .end = EXYNOS4_PA_SYSMMU_MDMA2 + SZ_64K - 1,
166 .flags = IORESOURCE_MEM,
167 },
168 [25] = {
169 .start = IRQ_SYSMMU_MDMA1_0,
170 .end = IRQ_SYSMMU_MDMA1_0,
171 .flags = IORESOURCE_IRQ,
172 },
173 [26] = {
174 .start = EXYNOS4_PA_SYSMMU_TV,
175 .end = EXYNOS4_PA_SYSMMU_TV + SZ_64K - 1,
176 .flags = IORESOURCE_MEM,
177 },
178 [27] = {
179 .start = IRQ_SYSMMU_TV_M0_0,
180 .end = IRQ_SYSMMU_TV_M0_0,
181 .flags = IORESOURCE_IRQ,
182 },
183 [28] = {
184 .start = EXYNOS4_PA_SYSMMU_MFC_L,
185 .end = EXYNOS4_PA_SYSMMU_MFC_L + SZ_64K - 1,
186 .flags = IORESOURCE_MEM,
187 },
188 [29] = {
189 .start = IRQ_SYSMMU_MFC_M0_0,
190 .end = IRQ_SYSMMU_MFC_M0_0,
191 .flags = IORESOURCE_IRQ,
192 },
193 [30] = {
194 .start = EXYNOS4_PA_SYSMMU_MFC_R,
195 .end = EXYNOS4_PA_SYSMMU_MFC_R + SZ_64K - 1,
196 .flags = IORESOURCE_MEM,
197 },
198 [31] = {
199 .start = IRQ_SYSMMU_MFC_M1_0,
200 .end = IRQ_SYSMMU_MFC_M1_0,
201 .flags = IORESOURCE_IRQ,
202 },
203};
204 72
205struct platform_device exynos4_device_sysmmu = { 73struct sysmmu_resource_map {
206 .name = "s5p-sysmmu", 74 struct platform_device *pdev;
207 .id = 32, 75 struct resource *res;
208 .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource), 76 u32 rnum;
209 .resource = exynos4_sysmmu_resource, 77 struct device *pdd;
78 char *clocknames;
210}; 79};
211EXPORT_SYMBOL(exynos4_device_sysmmu);
212 80
213static struct clk *sysmmu_clk[S5P_SYSMMU_TOTAL_IPNUM]; 81#define SYSMMU_RESOURCE_MAPPING(core, ipname, resname) { \
214void sysmmu_clk_init(struct device *dev, sysmmu_ips ips) 82 .pdev = &SYSMMU_PLATDEV(ipname), \
215{ 83 .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
216 sysmmu_clk[ips] = clk_get(dev, sysmmu_ips_name[ips]); 84 .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
217 if (IS_ERR(sysmmu_clk[ips])) 85 .clocknames = SYSMMU_CLOCK_NAME, \
218 sysmmu_clk[ips] = NULL;
219 else
220 clk_put(sysmmu_clk[ips]);
221} 86}
222 87
223void sysmmu_clk_enable(sysmmu_ips ips) 88#define SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata) { \
224{ 89 .pdev = &SYSMMU_PLATDEV(ipname), \
225 if (sysmmu_clk[ips]) 90 .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
226 clk_enable(sysmmu_clk[ips]); 91 .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
92 .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2, \
93}
94
95#ifdef CONFIG_EXYNOS_DEV_PD
96#define SYSMMU_RESOURCE_MAPPING_PD(core, ipname, resname, pd) { \
97 .pdev = &SYSMMU_PLATDEV(ipname), \
98 .res = &SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
99 .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
100 .clocknames = SYSMMU_CLOCK_NAME, \
101 .pdd = &exynos##core##_device_pd[pd].dev, \
102}
103
104#define SYSMMU_RESOURCE_MAPPING_MCPD(core, ipname, resname, pd, pdata) {\
105 .pdev = &SYSMMU_PLATDEV(ipname), \
106 .res = &SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
107 .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
108 .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2, \
109 .pdd = &exynos##core##_device_pd[pd].dev, \
227} 110}
111#else
112#define SYSMMU_RESOURCE_MAPPING_PD(core, ipname, resname, pd) \
113 SYSMMU_RESOURCE_MAPPING(core, ipname, resname)
114#define SYSMMU_RESOURCE_MAPPING_MCPD(core, ipname, resname, pd, pdata) \
115 SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata)
116
117#endif /* CONFIG_EXYNOS_DEV_PD */
118
119#ifdef CONFIG_ARCH_EXYNOS4
120SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc0, FIMC0, FIMC0);
121SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc1, FIMC1, FIMC1);
122SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc2, FIMC2, FIMC2);
123SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc3, FIMC3, FIMC3);
124SYSMMU_RESOURCE_DEFINE(EXYNOS4, jpeg, JPEG, JPEG);
125SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d, G2D, 2D);
126SYSMMU_RESOURCE_DEFINE(EXYNOS4, tv, TV, TV_M0);
127SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d_acp, 2D_ACP, 2D);
128SYSMMU_RESOURCE_DEFINE(EXYNOS4, rot, ROTATOR, ROTATOR);
129SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd0, FIMD0, LCD0_M0);
130SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd1, FIMD1, LCD1_M1);
131SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite0, FIMC_LITE0, FIMC_LITE0);
132SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite1, FIMC_LITE1, FIMC_LITE1);
133SYSMMU_RESOURCE_DEFINE(EXYNOS4, mfc_r, MFC_R, MFC_M0);
134SYSMMU_RESOURCE_DEFINE(EXYNOS4, mfc_l, MFC_L, MFC_M1);
135SYSMMU_RESOURCE(EXYNOS4, isp) {
136 DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_ISP, FIMC_ISP),
137 DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_DRC, FIMC_DRC),
138 DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_FD, FIMC_FD),
139 DEFINE_SYSMMU_RESOURCE(EXYNOS4, ISPCPU, FIMC_CX),
140};
141
142static struct sysmmu_resource_map sysmmu_resmap4[] __initdata = {
143 SYSMMU_RESOURCE_MAPPING_PD(4, fimc0, fimc0, PD_CAM),
144 SYSMMU_RESOURCE_MAPPING_PD(4, fimc1, fimc1, PD_CAM),
145 SYSMMU_RESOURCE_MAPPING_PD(4, fimc2, fimc2, PD_CAM),
146 SYSMMU_RESOURCE_MAPPING_PD(4, fimc3, fimc3, PD_CAM),
147 SYSMMU_RESOURCE_MAPPING_PD(4, tv, tv, PD_TV),
148 SYSMMU_RESOURCE_MAPPING_PD(4, mfc_r, mfc_r, PD_MFC),
149 SYSMMU_RESOURCE_MAPPING_PD(4, mfc_l, mfc_l, PD_MFC),
150 SYSMMU_RESOURCE_MAPPING_PD(4, rot, rot, PD_LCD0),
151 SYSMMU_RESOURCE_MAPPING_PD(4, jpeg, jpeg, PD_CAM),
152 SYSMMU_RESOURCE_MAPPING_PD(4, fimd0, fimd0, PD_LCD0),
153};
154
155static struct sysmmu_resource_map sysmmu_resmap4210[] __initdata = {
156 SYSMMU_RESOURCE_MAPPING_PD(4, 2d, 2d, PD_LCD0),
157 SYSMMU_RESOURCE_MAPPING_PD(4, fimd1, fimd1, PD_LCD1),
158};
159
160static struct sysmmu_resource_map sysmmu_resmap4212[] __initdata = {
161 SYSMMU_RESOURCE_MAPPING(4, 2d, 2d_acp),
162 SYSMMU_RESOURCE_MAPPING_PD(4, camif0, flite0, PD_ISP),
163 SYSMMU_RESOURCE_MAPPING_PD(4, camif1, flite1, PD_ISP),
164 SYSMMU_RESOURCE_MAPPING_PD(4, isp, isp, PD_ISP),
165};
166#endif /* CONFIG_ARCH_EXYNOS4 */
228 167
229void sysmmu_clk_disable(sysmmu_ips ips) 168#ifdef CONFIG_ARCH_EXYNOS5
169SYSMMU_RESOURCE_DEFINE(EXYNOS5, jpeg, JPEG, JPEG);
170SYSMMU_RESOURCE_DEFINE(EXYNOS5, fimd1, FIMD1, FIMD1);
171SYSMMU_RESOURCE_DEFINE(EXYNOS5, 2d, 2D, 2D);
172SYSMMU_RESOURCE_DEFINE(EXYNOS5, rot, ROTATOR, ROTATOR);
173SYSMMU_RESOURCE_DEFINE(EXYNOS5, tv, TV, TV);
174SYSMMU_RESOURCE_DEFINE(EXYNOS5, flite0, LITE0, LITE0);
175SYSMMU_RESOURCE_DEFINE(EXYNOS5, flite1, LITE1, LITE1);
176SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc0, GSC0, GSC0);
177SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc1, GSC1, GSC1);
178SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc2, GSC2, GSC2);
179SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc3, GSC3, GSC3);
180SYSMMU_RESOURCE_DEFINE(EXYNOS5, mfc_r, MFC_R, MFC_R);
181SYSMMU_RESOURCE_DEFINE(EXYNOS5, mfc_l, MFC_L, MFC_L);
182SYSMMU_RESOURCE(EXYNOS5, isp) {
183 DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISP, ISP),
184 DEFINE_SYSMMU_RESOURCE(EXYNOS5, DRC, DRC),
185 DEFINE_SYSMMU_RESOURCE(EXYNOS5, FD, FD),
186 DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISPCPU, MCUISP),
187 DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERC, SCALERCISP),
188 DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERP, SCALERPISP),
189 DEFINE_SYSMMU_RESOURCE(EXYNOS5, ODC, ODC),
190 DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS0, DIS0),
191 DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS1, DIS1),
192 DEFINE_SYSMMU_RESOURCE(EXYNOS5, 3DNR, 3DNR),
193};
194
195static struct sysmmu_resource_map sysmmu_resmap5[] __initdata = {
196 SYSMMU_RESOURCE_MAPPING(5, jpeg, jpeg),
197 SYSMMU_RESOURCE_MAPPING(5, fimd1, fimd1),
198 SYSMMU_RESOURCE_MAPPING(5, 2d, 2d),
199 SYSMMU_RESOURCE_MAPPING(5, rot, rot),
200 SYSMMU_RESOURCE_MAPPING_PD(5, tv, tv, PD_DISP1),
201 SYSMMU_RESOURCE_MAPPING_PD(5, camif0, flite0, PD_GSCL),
202 SYSMMU_RESOURCE_MAPPING_PD(5, camif1, flite1, PD_GSCL),
203 SYSMMU_RESOURCE_MAPPING_PD(5, gsc0, gsc0, PD_GSCL),
204 SYSMMU_RESOURCE_MAPPING_PD(5, gsc1, gsc1, PD_GSCL),
205 SYSMMU_RESOURCE_MAPPING_PD(5, gsc2, gsc2, PD_GSCL),
206 SYSMMU_RESOURCE_MAPPING_PD(5, gsc3, gsc3, PD_GSCL),
207 SYSMMU_RESOURCE_MAPPING_PD(5, mfc_r, mfc_r, PD_MFC),
208 SYSMMU_RESOURCE_MAPPING_PD(5, mfc_l, mfc_l, PD_MFC),
209 SYSMMU_RESOURCE_MAPPING_MCPD(5, isp, isp, PD_ISP, mc_platdata),
210};
211#endif /* CONFIG_ARCH_EXYNOS5 */
212
213static int __init init_sysmmu_platform_device(void)
230{ 214{
231 if (sysmmu_clk[ips]) 215 int i, j;
232 clk_disable(sysmmu_clk[ips]); 216 struct sysmmu_resource_map *resmap[2] = {NULL, NULL};
217 int nmap[2] = {0, 0};
218
219#ifdef CONFIG_ARCH_EXYNOS5
220 if (soc_is_exynos5250()) {
221 resmap[0] = sysmmu_resmap5;
222 nmap[0] = ARRAY_SIZE(sysmmu_resmap5);
223 nmap[1] = 0;
224 }
225#endif
226
227#ifdef CONFIG_ARCH_EXYNOS4
228 if (resmap[0] == NULL) {
229 resmap[0] = sysmmu_resmap4;
230 nmap[0] = ARRAY_SIZE(sysmmu_resmap4);
231 }
232
233 if (soc_is_exynos4210()) {
234 resmap[1] = sysmmu_resmap4210;
235 nmap[1] = ARRAY_SIZE(sysmmu_resmap4210);
236 }
237
238 if (soc_is_exynos4412() || soc_is_exynos4212()) {
239 resmap[1] = sysmmu_resmap4212;
240 nmap[1] = ARRAY_SIZE(sysmmu_resmap4212);
241 }
242#endif
243
244 for (j = 0; j < 2; j++) {
245 for (i = 0; i < nmap[j]; i++) {
246 struct sysmmu_resource_map *map;
247 struct sysmmu_platform_data *platdata;
248
249 map = &resmap[j][i];
250
251 map->pdev->dev.parent = map->pdd;
252
253 platdata = map->pdev->dev.platform_data;
254 platdata->clockname = map->clocknames;
255
256 if (platform_device_add_resources(map->pdev, map->res,
257 map->rnum)) {
258 pr_err("%s: Failed to add device resources for "
259 "%s.%d\n", __func__,
260 map->pdev->name, map->pdev->id);
261 continue;
262 }
263
264 if (platform_device_register(map->pdev)) {
265 pr_err("%s: Failed to register %s.%d\n",
266 __func__, map->pdev->name,
267 map->pdev->id);
268 }
269 }
270 }
271
272 return 0;
233} 273}
274arch_initcall(init_sysmmu_platform_device);
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index 591e78521a9f..116167524051 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -154,6 +154,13 @@
154#define EXYNOS4_IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6) 154#define EXYNOS4_IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6)
155#define EXYNOS4_IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7) 155#define EXYNOS4_IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7)
156 156
157#define EXYNOS4_IRQ_SYSMMU_FIMC_LITE0_0 COMBINER_IRQ(16, 0)
158#define EXYNOS4_IRQ_SYSMMU_FIMC_LITE1_0 COMBINER_IRQ(16, 1)
159#define EXYNOS4_IRQ_SYSMMU_FIMC_ISP_0 COMBINER_IRQ(16, 2)
160#define EXYNOS4_IRQ_SYSMMU_FIMC_DRC_0 COMBINER_IRQ(16, 3)
161#define EXYNOS4_IRQ_SYSMMU_FIMC_FD_0 COMBINER_IRQ(16, 4)
162#define EXYNOS4_IRQ_SYSMMU_FIMC_CX_0 COMBINER_IRQ(16, 5)
163
157#define EXYNOS4_IRQ_FIMD0_FIFO COMBINER_IRQ(11, 0) 164#define EXYNOS4_IRQ_FIMD0_FIFO COMBINER_IRQ(11, 0)
158#define EXYNOS4_IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1) 165#define EXYNOS4_IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1)
159#define EXYNOS4_IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2) 166#define EXYNOS4_IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2)
@@ -220,24 +227,6 @@
220#define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD 227#define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD
221#define IRQ_PMU EXYNOS4_IRQ_PMU 228#define IRQ_PMU EXYNOS4_IRQ_PMU
222 229
223#define IRQ_SYSMMU_MDMA0_0 EXYNOS4_IRQ_SYSMMU_MDMA0_0
224#define IRQ_SYSMMU_SSS_0 EXYNOS4_IRQ_SYSMMU_SSS_0
225#define IRQ_SYSMMU_FIMC0_0 EXYNOS4_IRQ_SYSMMU_FIMC0_0
226#define IRQ_SYSMMU_FIMC1_0 EXYNOS4_IRQ_SYSMMU_FIMC1_0
227#define IRQ_SYSMMU_FIMC2_0 EXYNOS4_IRQ_SYSMMU_FIMC2_0
228#define IRQ_SYSMMU_FIMC3_0 EXYNOS4_IRQ_SYSMMU_FIMC3_0
229#define IRQ_SYSMMU_JPEG_0 EXYNOS4_IRQ_SYSMMU_JPEG_0
230#define IRQ_SYSMMU_2D_0 EXYNOS4_IRQ_SYSMMU_2D_0
231
232#define IRQ_SYSMMU_ROTATOR_0 EXYNOS4_IRQ_SYSMMU_ROTATOR_0
233#define IRQ_SYSMMU_MDMA1_0 EXYNOS4_IRQ_SYSMMU_MDMA1_0
234#define IRQ_SYSMMU_LCD0_M0_0 EXYNOS4_IRQ_SYSMMU_LCD0_M0_0
235#define IRQ_SYSMMU_LCD1_M1_0 EXYNOS4_IRQ_SYSMMU_LCD1_M1_0
236#define IRQ_SYSMMU_TV_M0_0 EXYNOS4_IRQ_SYSMMU_TV_M0_0
237#define IRQ_SYSMMU_MFC_M0_0 EXYNOS4_IRQ_SYSMMU_MFC_M0_0
238#define IRQ_SYSMMU_MFC_M1_0 EXYNOS4_IRQ_SYSMMU_MFC_M1_0
239#define IRQ_SYSMMU_PCIE_0 EXYNOS4_IRQ_SYSMMU_PCIE_0
240
241#define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO 230#define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO
242#define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC 231#define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC
243#define IRQ_FIMD0_SYSTEM EXYNOS4_IRQ_FIMD0_SYSTEM 232#define IRQ_FIMD0_SYSTEM EXYNOS4_IRQ_FIMD0_SYSTEM
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 6e6d11ff352a..0e2292d04550 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -95,6 +95,7 @@
95#define EXYNOS5_PA_PDMA1 0x121B0000 95#define EXYNOS5_PA_PDMA1 0x121B0000
96 96
97#define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000 97#define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000
98#define EXYNOS4_PA_SYSMMU_2D_ACP 0x10A40000
98#define EXYNOS4_PA_SYSMMU_SSS 0x10A50000 99#define EXYNOS4_PA_SYSMMU_SSS 0x10A50000
99#define EXYNOS4_PA_SYSMMU_FIMC0 0x11A20000 100#define EXYNOS4_PA_SYSMMU_FIMC0 0x11A20000
100#define EXYNOS4_PA_SYSMMU_FIMC1 0x11A30000 101#define EXYNOS4_PA_SYSMMU_FIMC1 0x11A30000
@@ -103,6 +104,12 @@
103#define EXYNOS4_PA_SYSMMU_JPEG 0x11A60000 104#define EXYNOS4_PA_SYSMMU_JPEG 0x11A60000
104#define EXYNOS4_PA_SYSMMU_FIMD0 0x11E20000 105#define EXYNOS4_PA_SYSMMU_FIMD0 0x11E20000
105#define EXYNOS4_PA_SYSMMU_FIMD1 0x12220000 106#define EXYNOS4_PA_SYSMMU_FIMD1 0x12220000
107#define EXYNOS4_PA_SYSMMU_FIMC_ISP 0x12260000
108#define EXYNOS4_PA_SYSMMU_FIMC_DRC 0x12270000
109#define EXYNOS4_PA_SYSMMU_FIMC_FD 0x122A0000
110#define EXYNOS4_PA_SYSMMU_ISPCPU 0x122B0000
111#define EXYNOS4_PA_SYSMMU_FIMC_LITE0 0x123B0000
112#define EXYNOS4_PA_SYSMMU_FIMC_LITE1 0x123C0000
106#define EXYNOS4_PA_SYSMMU_PCIe 0x12620000 113#define EXYNOS4_PA_SYSMMU_PCIe 0x12620000
107#define EXYNOS4_PA_SYSMMU_G2D 0x12A20000 114#define EXYNOS4_PA_SYSMMU_G2D 0x12A20000
108#define EXYNOS4_PA_SYSMMU_ROTATOR 0x12A30000 115#define EXYNOS4_PA_SYSMMU_ROTATOR 0x12A30000
@@ -110,6 +117,37 @@
110#define EXYNOS4_PA_SYSMMU_TV 0x12E20000 117#define EXYNOS4_PA_SYSMMU_TV 0x12E20000
111#define EXYNOS4_PA_SYSMMU_MFC_L 0x13620000 118#define EXYNOS4_PA_SYSMMU_MFC_L 0x13620000
112#define EXYNOS4_PA_SYSMMU_MFC_R 0x13630000 119#define EXYNOS4_PA_SYSMMU_MFC_R 0x13630000
120
121#define EXYNOS5_PA_SYSMMU_MDMA1 0x10A40000
122#define EXYNOS5_PA_SYSMMU_SSS 0x10A50000
123#define EXYNOS5_PA_SYSMMU_2D 0x10A60000
124#define EXYNOS5_PA_SYSMMU_MFC_L 0x11200000
125#define EXYNOS5_PA_SYSMMU_MFC_R 0x11210000
126#define EXYNOS5_PA_SYSMMU_ROTATOR 0x11D40000
127#define EXYNOS5_PA_SYSMMU_MDMA2 0x11D50000
128#define EXYNOS5_PA_SYSMMU_JPEG 0x11F20000
129#define EXYNOS5_PA_SYSMMU_IOP 0x12360000
130#define EXYNOS5_PA_SYSMMU_RTIC 0x12370000
131#define EXYNOS5_PA_SYSMMU_GPS 0x12630000
132#define EXYNOS5_PA_SYSMMU_ISP 0x13260000
133#define EXYNOS5_PA_SYSMMU_DRC 0x12370000
134#define EXYNOS5_PA_SYSMMU_SCALERC 0x13280000
135#define EXYNOS5_PA_SYSMMU_SCALERP 0x13290000
136#define EXYNOS5_PA_SYSMMU_FD 0x132A0000
137#define EXYNOS5_PA_SYSMMU_ISPCPU 0x132B0000
138#define EXYNOS5_PA_SYSMMU_ODC 0x132C0000
139#define EXYNOS5_PA_SYSMMU_DIS0 0x132D0000
140#define EXYNOS5_PA_SYSMMU_DIS1 0x132E0000
141#define EXYNOS5_PA_SYSMMU_3DNR 0x132F0000
142#define EXYNOS5_PA_SYSMMU_LITE0 0x13C40000
143#define EXYNOS5_PA_SYSMMU_LITE1 0x13C50000
144#define EXYNOS5_PA_SYSMMU_GSC0 0x13E80000
145#define EXYNOS5_PA_SYSMMU_GSC1 0x13E90000
146#define EXYNOS5_PA_SYSMMU_GSC2 0x13EA0000
147#define EXYNOS5_PA_SYSMMU_GSC3 0x13EB0000
148#define EXYNOS5_PA_SYSMMU_FIMD1 0x14640000
149#define EXYNOS5_PA_SYSMMU_TV 0x14650000
150
113#define EXYNOS4_PA_SPI0 0x13920000 151#define EXYNOS4_PA_SPI0 0x13920000
114#define EXYNOS4_PA_SPI1 0x13930000 152#define EXYNOS4_PA_SPI1 0x13930000
115#define EXYNOS4_PA_SPI2 0x13940000 153#define EXYNOS4_PA_SPI2 0x13940000
diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h
index d9578a58ae7f..dba83e91f0fd 100644
--- a/arch/arm/mach-exynos/include/mach/regs-clock.h
+++ b/arch/arm/mach-exynos/include/mach/regs-clock.h
@@ -135,6 +135,9 @@
135#define EXYNOS4_CLKGATE_SCLKCPU EXYNOS_CLKREG(0x14800) 135#define EXYNOS4_CLKGATE_SCLKCPU EXYNOS_CLKREG(0x14800)
136#define EXYNOS4_CLKGATE_IP_CPU EXYNOS_CLKREG(0x14900) 136#define EXYNOS4_CLKGATE_IP_CPU EXYNOS_CLKREG(0x14900)
137 137
138#define EXYNOS4_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x18800)
139#define EXYNOS4_CLKGATE_IP_ISP1 EXYNOS_CLKREG(0x18804)
140
138#define EXYNOS4_APLL_LOCKTIME (0x1C20) /* 300us */ 141#define EXYNOS4_APLL_LOCKTIME (0x1C20) /* 300us */
139 142
140#define EXYNOS4_APLLCON0_ENABLE_SHIFT (31) 143#define EXYNOS4_APLLCON0_ENABLE_SHIFT (31)
@@ -303,6 +306,8 @@
303#define EXYNOS5_CLKDIV_PERIC0 EXYNOS_CLKREG(0x10558) 306#define EXYNOS5_CLKDIV_PERIC0 EXYNOS_CLKREG(0x10558)
304 307
305#define EXYNOS5_CLKGATE_IP_ACP EXYNOS_CLKREG(0x08800) 308#define EXYNOS5_CLKGATE_IP_ACP EXYNOS_CLKREG(0x08800)
309#define EXYNOS5_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x0C800)
310#define EXYNOS5_CLKGATE_IP_ISP1 EXYNOS_CLKREG(0x0C804)
306#define EXYNOS5_CLKGATE_IP_GSCL EXYNOS_CLKREG(0x10920) 311#define EXYNOS5_CLKGATE_IP_GSCL EXYNOS_CLKREG(0x10920)
307#define EXYNOS5_CLKGATE_IP_DISP1 EXYNOS_CLKREG(0x10928) 312#define EXYNOS5_CLKGATE_IP_DISP1 EXYNOS_CLKREG(0x10928)
308#define EXYNOS5_CLKGATE_IP_MFC EXYNOS_CLKREG(0x1092C) 313#define EXYNOS5_CLKGATE_IP_MFC EXYNOS_CLKREG(0x1092C)
diff --git a/arch/arm/mach-exynos/include/mach/regs-sysmmu.h b/arch/arm/mach-exynos/include/mach/regs-sysmmu.h
deleted file mode 100644
index 68ff6ad08a2b..000000000000
--- a/arch/arm/mach-exynos/include/mach/regs-sysmmu.h
+++ /dev/null
@@ -1,28 +0,0 @@
1/* linux/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 - System MMU register
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef __ASM_ARCH_REGS_SYSMMU_H
14#define __ASM_ARCH_REGS_SYSMMU_H __FILE__
15
16#define S5P_MMU_CTRL 0x000
17#define S5P_MMU_CFG 0x004
18#define S5P_MMU_STATUS 0x008
19#define S5P_MMU_FLUSH 0x00C
20#define S5P_PT_BASE_ADDR 0x014
21#define S5P_INT_STATUS 0x018
22#define S5P_INT_CLEAR 0x01C
23#define S5P_PAGE_FAULT_ADDR 0x024
24#define S5P_AW_FAULT_ADDR 0x028
25#define S5P_AR_FAULT_ADDR 0x02C
26#define S5P_DEFAULT_SLAVE_ADDR 0x030
27
28#endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/sysmmu.h b/arch/arm/mach-exynos/include/mach/sysmmu.h
index 6a5fbb534e82..998daf2add92 100644
--- a/arch/arm/mach-exynos/include/mach/sysmmu.h
+++ b/arch/arm/mach-exynos/include/mach/sysmmu.h
@@ -1,46 +1,66 @@
1/* linux/arch/arm/mach-exynos4/include/mach/sysmmu.h 1/*
2 * 2 * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com 3 * http://www.samsung.com
5 * 4 *
6 * Samsung sysmmu driver for EXYNOS4 5 * EXYNOS - System MMU support
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
11*/ 10 */
12 11
13#ifndef __ASM_ARM_ARCH_SYSMMU_H 12#ifndef _ARM_MACH_EXYNOS_SYSMMU_H_
14#define __ASM_ARM_ARCH_SYSMMU_H __FILE__ 13#define _ARM_MACH_EXYNOS_SYSMMU_H_
15 14
16enum exynos4_sysmmu_ips { 15struct sysmmu_platform_data {
17 SYSMMU_MDMA, 16 char *dbgname;
18 SYSMMU_SSS, 17 /* comma(,) separated list of clock names for clock gating */
19 SYSMMU_FIMC0, 18 char *clockname;
20 SYSMMU_FIMC1,
21 SYSMMU_FIMC2,
22 SYSMMU_FIMC3,
23 SYSMMU_JPEG,
24 SYSMMU_FIMD0,
25 SYSMMU_FIMD1,
26 SYSMMU_PCIe,
27 SYSMMU_G2D,
28 SYSMMU_ROTATOR,
29 SYSMMU_MDMA2,
30 SYSMMU_TV,
31 SYSMMU_MFC_L,
32 SYSMMU_MFC_R,
33 EXYNOS4_SYSMMU_TOTAL_IPNUM,
34}; 19};
35 20
36#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM 21#define SYSMMU_DEVNAME_BASE "exynos-sysmmu"
22
23#define SYSMMU_CLOCK_NAME "sysmmu"
24#define SYSMMU_CLOCK_NAME2 "sysmmu_mc"
25
26#ifdef CONFIG_EXYNOS_DEV_SYSMMU
27#include <linux/device.h>
28struct platform_device;
29
30#define SYSMMU_PLATDEV(ipname) exynos_device_sysmmu_##ipname
31
32extern struct platform_device SYSMMU_PLATDEV(mfc_l);
33extern struct platform_device SYSMMU_PLATDEV(mfc_r);
34extern struct platform_device SYSMMU_PLATDEV(tv);
35extern struct platform_device SYSMMU_PLATDEV(jpeg);
36extern struct platform_device SYSMMU_PLATDEV(rot);
37extern struct platform_device SYSMMU_PLATDEV(fimc0);
38extern struct platform_device SYSMMU_PLATDEV(fimc1);
39extern struct platform_device SYSMMU_PLATDEV(fimc2);
40extern struct platform_device SYSMMU_PLATDEV(fimc3);
41extern struct platform_device SYSMMU_PLATDEV(gsc0);
42extern struct platform_device SYSMMU_PLATDEV(gsc1);
43extern struct platform_device SYSMMU_PLATDEV(gsc2);
44extern struct platform_device SYSMMU_PLATDEV(gsc3);
45extern struct platform_device SYSMMU_PLATDEV(isp);
46extern struct platform_device SYSMMU_PLATDEV(fimd0);
47extern struct platform_device SYSMMU_PLATDEV(fimd1);
48extern struct platform_device SYSMMU_PLATDEV(camif0);
49extern struct platform_device SYSMMU_PLATDEV(camif1);
50extern struct platform_device SYSMMU_PLATDEV(2d);
37 51
38extern const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM]; 52#ifdef CONFIG_IOMMU_API
53static inline void platform_set_sysmmu(
54 struct device *sysmmu, struct device *dev)
55{
56 dev->archdata.iommu = sysmmu;
57}
58#endif
39 59
40typedef enum exynos4_sysmmu_ips sysmmu_ips; 60#else /* !CONFIG_EXYNOS_DEV_SYSMMU */
61#define platform_set_sysmmu(dev, sysmmu) do { } while (0)
62#endif
41 63
42void sysmmu_clk_init(struct device *dev, sysmmu_ips ips); 64#define SYSMMU_CLOCK_DEVNAME(ipname, id) (SYSMMU_DEVNAME_BASE "." #id)
43void sysmmu_clk_enable(sysmmu_ips ips);
44void sysmmu_clk_disable(sysmmu_ips ips);
45 65
46#endif /* __ASM_ARM_ARCH_SYSMMU_H */ 66#endif /* _ARM_MACH_EXYNOS_SYSMMU_H_ */
diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c
index d726fcd3acf9..6ce21484501e 100644
--- a/arch/arm/mach-exynos/mach-armlex4210.c
+++ b/arch/arm/mach-exynos/mach-armlex4210.c
@@ -157,7 +157,6 @@ static struct platform_device *armlex4210_devices[] __initdata = {
157 &s3c_device_hsmmc3, 157 &s3c_device_hsmmc3,
158 &s3c_device_rtc, 158 &s3c_device_rtc,
159 &s3c_device_wdt, 159 &s3c_device_wdt,
160 &exynos4_device_sysmmu,
161 &samsung_asoc_dma, 160 &samsung_asoc_dma,
162 &armlex4210_smsc911x, 161 &armlex4210_smsc911x,
163 &exynos4_device_ahci, 162 &exynos4_device_ahci,
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 83b91fa777c1..495c7e502be1 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -281,7 +281,6 @@ static struct platform_device *smdkv310_devices[] __initdata = {
281 &s5p_device_mfc_l, 281 &s5p_device_mfc_l,
282 &s5p_device_mfc_r, 282 &s5p_device_mfc_r,
283 &exynos4_device_spdif, 283 &exynos4_device_spdif,
284 &exynos4_device_sysmmu,
285 &samsung_asoc_dma, 284 &samsung_asoc_dma,
286 &samsung_asoc_idma, 285 &samsung_asoc_idma,
287 &s5p_device_fimd0, 286 &s5p_device_fimd0,
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 96bea3202304..2c1193c59928 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -50,14 +50,6 @@ config S5P_PM
50 Common code for power management support on S5P and newer SoCs 50 Common code for power management support on S5P and newer SoCs
51 Note: Do not select this for S5P6440 and S5P6450. 51 Note: Do not select this for S5P6440 and S5P6450.
52 52
53comment "System MMU"
54
55config S5P_SYSTEM_MMU
56 bool "S5P SYSTEM MMU"
57 depends on ARCH_EXYNOS4
58 help
59 Say Y here if you want to enable System MMU
60
61config S5P_SLEEP 53config S5P_SLEEP
62 bool 54 bool
63 help 55 help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 4bd824136659..4953d50707be 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -16,7 +16,6 @@ obj-y += clock.o
16obj-y += irq.o 16obj-y += irq.o
17obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o 17obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o
18obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o 18obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o
19obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o
20obj-$(CONFIG_S5P_PM) += pm.o irq-pm.o 19obj-$(CONFIG_S5P_PM) += pm.o irq-pm.o
21obj-$(CONFIG_S5P_SLEEP) += sleep.o 20obj-$(CONFIG_S5P_SLEEP) += sleep.o
22obj-$(CONFIG_S5P_HRT) += s5p-time.o 21obj-$(CONFIG_S5P_HRT) += s5p-time.o
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
deleted file mode 100644
index c8bec9c7655d..000000000000
--- a/arch/arm/plat-s5p/sysmmu.c
+++ /dev/null
@@ -1,313 +0,0 @@
1/* linux/arch/arm/plat-s5p/sysmmu.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/io.h>
12#include <linux/interrupt.h>
13#include <linux/platform_device.h>
14#include <linux/export.h>
15
16#include <asm/pgtable.h>
17
18#include <mach/map.h>
19#include <mach/regs-sysmmu.h>
20#include <plat/sysmmu.h>
21
22#define CTRL_ENABLE 0x5
23#define CTRL_BLOCK 0x7
24#define CTRL_DISABLE 0x0
25
26static struct device *dev;
27
28static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
29 S5P_PAGE_FAULT_ADDR,
30 S5P_AR_FAULT_ADDR,
31 S5P_AW_FAULT_ADDR,
32 S5P_DEFAULT_SLAVE_ADDR,
33 S5P_AR_FAULT_ADDR,
34 S5P_AR_FAULT_ADDR,
35 S5P_AW_FAULT_ADDR,
36 S5P_AW_FAULT_ADDR
37};
38
39static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
40 "PAGE FAULT",
41 "AR MULTI-HIT FAULT",
42 "AW MULTI-HIT FAULT",
43 "BUS ERROR",
44 "AR SECURITY PROTECTION FAULT",
45 "AR ACCESS PROTECTION FAULT",
46 "AW SECURITY PROTECTION FAULT",
47 "AW ACCESS PROTECTION FAULT"
48};
49
50static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
51 enum S5P_SYSMMU_INTERRUPT_TYPE itype,
52 unsigned long pgtable_base,
53 unsigned long fault_addr);
54
55/*
56 * If adjacent 2 bits are true, the system MMU is enabled.
57 * The system MMU is disabled, otherwise.
58 */
59static unsigned long sysmmu_states;
60
61static inline void set_sysmmu_active(sysmmu_ips ips)
62{
63 sysmmu_states |= 3 << (ips * 2);
64}
65
66static inline void set_sysmmu_inactive(sysmmu_ips ips)
67{
68 sysmmu_states &= ~(3 << (ips * 2));
69}
70
71static inline int is_sysmmu_active(sysmmu_ips ips)
72{
73 return sysmmu_states & (3 << (ips * 2));
74}
75
76static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
77
78static inline void sysmmu_block(sysmmu_ips ips)
79{
80 __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
81 dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
82}
83
84static inline void sysmmu_unblock(sysmmu_ips ips)
85{
86 __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
87 dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
88}
89
90static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
91{
92 __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
93 dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
94}
95
96static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
97{
98 if (unlikely(pgd == 0)) {
99 pgd = (unsigned long)ZERO_PAGE(0);
100 __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */
101 } else {
102 __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */
103 }
104
105 __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
106
107 dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
108 sysmmu_ips_name[ips], pgd);
109 __sysmmu_tlb_invalidate(ips);
110}
111
112void sysmmu_set_fault_handler(sysmmu_ips ips,
113 int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
114 unsigned long pgtable_base,
115 unsigned long fault_addr))
116{
117 BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
118 fault_handlers[ips] = handler;
119}
120
121static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
122{
123 /* SYSMMU is in blocked when interrupt occurred. */
124 unsigned long base = 0;
125 sysmmu_ips ips = (sysmmu_ips)dev_id;
126 enum S5P_SYSMMU_INTERRUPT_TYPE itype;
127
128 itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
129 __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
130
131 BUG_ON(!((itype >= 0) && (itype < 8)));
132
133 dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
134 sysmmu_ips_name[ips]);
135
136 if (fault_handlers[ips]) {
137 unsigned long addr;
138
139 base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
140 addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]);
141
142 if (fault_handlers[ips](itype, base, addr)) {
143 __raw_writel(1 << itype,
144 sysmmusfrs[ips] + S5P_INT_CLEAR);
145 dev_notice(dev, "%s from %s is resolved."
146 " Retrying translation.\n",
147 sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
148 } else {
149 base = 0;
150 }
151 }
152
153 sysmmu_unblock(ips);
154
155 if (!base)
156 dev_notice(dev, "%s from %s is not handled.\n",
157 sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
158
159 return IRQ_HANDLED;
160}
161
162void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
163{
164 if (is_sysmmu_active(ips)) {
165 sysmmu_block(ips);
166 __sysmmu_set_ptbase(ips, pgd);
167 sysmmu_unblock(ips);
168 } else {
169 dev_dbg(dev, "%s is disabled. "
170 "Skipping initializing page table base.\n",
171 sysmmu_ips_name[ips]);
172 }
173}
174
175void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
176{
177 if (!is_sysmmu_active(ips)) {
178 sysmmu_clk_enable(ips);
179
180 __sysmmu_set_ptbase(ips, pgd);
181
182 __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
183
184 set_sysmmu_active(ips);
185 dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
186 } else {
187 dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]);
188 }
189}
190
191void s5p_sysmmu_disable(sysmmu_ips ips)
192{
193 if (is_sysmmu_active(ips)) {
194 __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
195 set_sysmmu_inactive(ips);
196 sysmmu_clk_disable(ips);
197 dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
198 } else {
199 dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]);
200 }
201}
202
203void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
204{
205 if (is_sysmmu_active(ips)) {
206 sysmmu_block(ips);
207 __sysmmu_tlb_invalidate(ips);
208 sysmmu_unblock(ips);
209 } else {
210 dev_dbg(dev, "%s is disabled. "
211 "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]);
212 }
213}
214
215static int s5p_sysmmu_probe(struct platform_device *pdev)
216{
217 int i, ret;
218 struct resource *res, *mem;
219
220 dev = &pdev->dev;
221
222 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
223 int irq;
224
225 sysmmu_clk_init(dev, i);
226 sysmmu_clk_disable(i);
227
228 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
229 if (!res) {
230 dev_err(dev, "Failed to get the resource of %s.\n",
231 sysmmu_ips_name[i]);
232 ret = -ENODEV;
233 goto err_res;
234 }
235
236 mem = request_mem_region(res->start, resource_size(res),
237 pdev->name);
238 if (!mem) {
239 dev_err(dev, "Failed to request the memory region of %s.\n",
240 sysmmu_ips_name[i]);
241 ret = -EBUSY;
242 goto err_res;
243 }
244
245 sysmmusfrs[i] = ioremap(res->start, resource_size(res));
246 if (!sysmmusfrs[i]) {
247 dev_err(dev, "Failed to ioremap() for %s.\n",
248 sysmmu_ips_name[i]);
249 ret = -ENXIO;
250 goto err_reg;
251 }
252
253 irq = platform_get_irq(pdev, i);
254 if (irq <= 0) {
255 dev_err(dev, "Failed to get the IRQ resource of %s.\n",
256 sysmmu_ips_name[i]);
257 ret = -ENOENT;
258 goto err_map;
259 }
260
261 if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
262 pdev->name, (void *)i)) {
263 dev_err(dev, "Failed to request IRQ for %s.\n",
264 sysmmu_ips_name[i]);
265 ret = -ENOENT;
266 goto err_map;
267 }
268 }
269
270 return 0;
271
272err_map:
273 iounmap(sysmmusfrs[i]);
274err_reg:
275 release_mem_region(mem->start, resource_size(mem));
276err_res:
277 return ret;
278}
279
280static int s5p_sysmmu_remove(struct platform_device *pdev)
281{
282 return 0;
283}
284int s5p_sysmmu_runtime_suspend(struct device *dev)
285{
286 return 0;
287}
288
289int s5p_sysmmu_runtime_resume(struct device *dev)
290{
291 return 0;
292}
293
294const struct dev_pm_ops s5p_sysmmu_pm_ops = {
295 .runtime_suspend = s5p_sysmmu_runtime_suspend,
296 .runtime_resume = s5p_sysmmu_runtime_resume,
297};
298
299static struct platform_driver s5p_sysmmu_driver = {
300 .probe = s5p_sysmmu_probe,
301 .remove = s5p_sysmmu_remove,
302 .driver = {
303 .owner = THIS_MODULE,
304 .name = "s5p-sysmmu",
305 .pm = &s5p_sysmmu_pm_ops,
306 }
307};
308
309static int __init s5p_sysmmu_init(void)
310{
311 return platform_driver_register(&s5p_sysmmu_driver);
312}
313arch_initcall(s5p_sysmmu_init);
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 62e6251e4b19..61ca2f356c52 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -133,7 +133,6 @@ extern struct platform_device exynos4_device_pcm1;
133extern struct platform_device exynos4_device_pcm2; 133extern struct platform_device exynos4_device_pcm2;
134extern struct platform_device exynos4_device_pd[]; 134extern struct platform_device exynos4_device_pd[];
135extern struct platform_device exynos4_device_spdif; 135extern struct platform_device exynos4_device_spdif;
136extern struct platform_device exynos4_device_sysmmu;
137 136
138extern struct platform_device exynos_device_drm; 137extern struct platform_device exynos_device_drm;
139 138
diff --git a/arch/arm/plat-samsung/include/plat/sysmmu.h b/arch/arm/plat-samsung/include/plat/sysmmu.h
deleted file mode 100644
index 5fe8ee01a5ba..000000000000
--- a/arch/arm/plat-samsung/include/plat/sysmmu.h
+++ /dev/null
@@ -1,95 +0,0 @@
1/* linux/arch/arm/plat-samsung/include/plat/sysmmu.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Samsung System MMU driver for S5P platform
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef __PLAT_SAMSUNG_SYSMMU_H
14#define __PLAT_SAMSUNG_SYSMMU_H __FILE__
15
16enum S5P_SYSMMU_INTERRUPT_TYPE {
17 SYSMMU_PAGEFAULT,
18 SYSMMU_AR_MULTIHIT,
19 SYSMMU_AW_MULTIHIT,
20 SYSMMU_BUSERROR,
21 SYSMMU_AR_SECURITY,
22 SYSMMU_AR_ACCESS,
23 SYSMMU_AW_SECURITY,
24 SYSMMU_AW_PROTECTION, /* 7 */
25 SYSMMU_FAULTS_NUM
26};
27
28#ifdef CONFIG_S5P_SYSTEM_MMU
29
30#include <mach/sysmmu.h>
31
32/**
33 * s5p_sysmmu_enable() - enable system mmu of ip
34 * @ips: The ip connected system mmu.
35 * #pgd: Base physical address of the 1st level page table
36 *
37 * This function enable system mmu to transfer address
38 * from virtual address to physical address
39 */
40void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd);
41
42/**
43 * s5p_sysmmu_disable() - disable sysmmu mmu of ip
44 * @ips: The ip connected system mmu.
45 *
46 * This function disable system mmu to transfer address
47 * from virtual address to physical address
48 */
49void s5p_sysmmu_disable(sysmmu_ips ips);
50
51/**
52 * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
53 * @ips: The ip connected system mmu.
54 * @pgd: The page table base address.
55 *
56 * This function set page table base address
57 * When system mmu transfer address from virtaul address to physical address,
58 * system mmu refer address information from page table
59 */
60void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
61
62/**
63 * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
64 * @ips: The ip connected system mmu.
65 *
66 * This function flush all TLB entry in system mmu
67 */
68void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
69
70/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs
71 * @itype: type of fault.
72 * @pgtable_base: the physical address of page table base. This is 0 if @ips is
73 * SYSMMU_BUSERROR.
74 * @fault_addr: the device (virtual) address that the System MMU tried to
75 * translated. This is 0 if @ips is SYSMMU_BUSERROR.
76 * Called when interrupt occurred by the System MMUs
77 * The device drivers of peripheral devices that has a System MMU can implement
78 * a fault handler to resolve address translation fault by System MMU.
79 * The meanings of return value and parameters are described below.
80
81 * return value: non-zero if the fault is correctly resolved.
82 * zero if the fault is not handled.
83 */
84void s5p_sysmmu_set_fault_handler(sysmmu_ips ips,
85 int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
86 unsigned long pgtable_base,
87 unsigned long fault_addr));
88#else
89#define s5p_sysmmu_enable(ips, pgd) do { } while (0)
90#define s5p_sysmmu_disable(ips) do { } while (0)
91#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0)
92#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0)
93#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0)
94#endif
95#endif /* __ASM_PLAT_SYSMMU_H */
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 3bd9fff5c589..23db79205fd7 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -162,4 +162,25 @@ config TEGRA_IOMMU_SMMU
162 space through the SMMU (System Memory Management Unit) 162 space through the SMMU (System Memory Management Unit)
163 hardware included on Tegra SoCs. 163 hardware included on Tegra SoCs.
164 164
165config EXYNOS_IOMMU
166 bool "Exynos IOMMU Support"
167 depends on ARCH_EXYNOS && EXYNOS_DEV_SYSMMU
168 select IOMMU_API
169 help
170 Support for the IOMMU(System MMU) of Samsung Exynos application
171 processor family. This enables H/W multimedia accellerators to see
172 non-linear physical memory chunks as a linear memory in their
173 address spaces
174
175 If unsure, say N here.
176
177config EXYNOS_IOMMU_DEBUG
178 bool "Debugging log for Exynos IOMMU"
179 depends on EXYNOS_IOMMU
180 help
181 Select this to see the detailed log message that shows what
182 happens in the IOMMU driver
183
184 Say N unless you need kernel log message for IOMMU debugging
185
165endif # IOMMU_SUPPORT 186endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 7ad7a3bc1242..d06dec6a84b4 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
10obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o 10obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
11obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o 11obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
12obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o 12obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
13obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
new file mode 100644
index 000000000000..9a114b9ff170
--- /dev/null
+++ b/drivers/iommu/exynos-iommu.c
@@ -0,0 +1,1076 @@
1/* linux/drivers/iommu/exynos_iommu.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
12#define DEBUG
13#endif
14
15#include <linux/io.h>
16#include <linux/interrupt.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/pm_runtime.h>
20#include <linux/clk.h>
21#include <linux/err.h>
22#include <linux/mm.h>
23#include <linux/iommu.h>
24#include <linux/errno.h>
25#include <linux/list.h>
26#include <linux/memblock.h>
27#include <linux/export.h>
28
29#include <asm/cacheflush.h>
30#include <asm/pgtable.h>
31
32#include <mach/sysmmu.h>
33
34/* We does not consider super section mapping (16MB) */
35#define SECT_ORDER 20
36#define LPAGE_ORDER 16
37#define SPAGE_ORDER 12
38
39#define SECT_SIZE (1 << SECT_ORDER)
40#define LPAGE_SIZE (1 << LPAGE_ORDER)
41#define SPAGE_SIZE (1 << SPAGE_ORDER)
42
43#define SECT_MASK (~(SECT_SIZE - 1))
44#define LPAGE_MASK (~(LPAGE_SIZE - 1))
45#define SPAGE_MASK (~(SPAGE_SIZE - 1))
46
47#define lv1ent_fault(sent) (((*(sent) & 3) == 0) || ((*(sent) & 3) == 3))
48#define lv1ent_page(sent) ((*(sent) & 3) == 1)
49#define lv1ent_section(sent) ((*(sent) & 3) == 2)
50
51#define lv2ent_fault(pent) ((*(pent) & 3) == 0)
52#define lv2ent_small(pent) ((*(pent) & 2) == 2)
53#define lv2ent_large(pent) ((*(pent) & 3) == 1)
54
55#define section_phys(sent) (*(sent) & SECT_MASK)
56#define section_offs(iova) ((iova) & 0xFFFFF)
57#define lpage_phys(pent) (*(pent) & LPAGE_MASK)
58#define lpage_offs(iova) ((iova) & 0xFFFF)
59#define spage_phys(pent) (*(pent) & SPAGE_MASK)
60#define spage_offs(iova) ((iova) & 0xFFF)
61
62#define lv1ent_offset(iova) ((iova) >> SECT_ORDER)
63#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER)
64
65#define NUM_LV1ENTRIES 4096
66#define NUM_LV2ENTRIES 256
67
68#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long))
69
70#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)
71
72#define lv2table_base(sent) (*(sent) & 0xFFFFFC00)
73
74#define mk_lv1ent_sect(pa) ((pa) | 2)
75#define mk_lv1ent_page(pa) ((pa) | 1)
76#define mk_lv2ent_lpage(pa) ((pa) | 1)
77#define mk_lv2ent_spage(pa) ((pa) | 2)
78
79#define CTRL_ENABLE 0x5
80#define CTRL_BLOCK 0x7
81#define CTRL_DISABLE 0x0
82
83#define REG_MMU_CTRL 0x000
84#define REG_MMU_CFG 0x004
85#define REG_MMU_STATUS 0x008
86#define REG_MMU_FLUSH 0x00C
87#define REG_MMU_FLUSH_ENTRY 0x010
88#define REG_PT_BASE_ADDR 0x014
89#define REG_INT_STATUS 0x018
90#define REG_INT_CLEAR 0x01C
91
92#define REG_PAGE_FAULT_ADDR 0x024
93#define REG_AW_FAULT_ADDR 0x028
94#define REG_AR_FAULT_ADDR 0x02C
95#define REG_DEFAULT_SLAVE_ADDR 0x030
96
97#define REG_MMU_VERSION 0x034
98
99#define REG_PB0_SADDR 0x04C
100#define REG_PB0_EADDR 0x050
101#define REG_PB1_SADDR 0x054
102#define REG_PB1_EADDR 0x058
103
104static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
105{
106 return pgtable + lv1ent_offset(iova);
107}
108
109static unsigned long *page_entry(unsigned long *sent, unsigned long iova)
110{
111 return (unsigned long *)__va(lv2table_base(sent)) + lv2ent_offset(iova);
112}
113
114enum exynos_sysmmu_inttype {
115 SYSMMU_PAGEFAULT,
116 SYSMMU_AR_MULTIHIT,
117 SYSMMU_AW_MULTIHIT,
118 SYSMMU_BUSERROR,
119 SYSMMU_AR_SECURITY,
120 SYSMMU_AR_ACCESS,
121 SYSMMU_AW_SECURITY,
122 SYSMMU_AW_PROTECTION, /* 7 */
123 SYSMMU_FAULT_UNKNOWN,
124 SYSMMU_FAULTS_NUM
125};
126
127/*
128 * @itype: type of fault.
129 * @pgtable_base: the physical address of page table base. This is 0 if @itype
130 * is SYSMMU_BUSERROR.
131 * @fault_addr: the device (virtual) address that the System MMU tried to
132 * translated. This is 0 if @itype is SYSMMU_BUSERROR.
133 */
134typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype,
135 unsigned long pgtable_base, unsigned long fault_addr);
136
137static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
138 REG_PAGE_FAULT_ADDR,
139 REG_AR_FAULT_ADDR,
140 REG_AW_FAULT_ADDR,
141 REG_DEFAULT_SLAVE_ADDR,
142 REG_AR_FAULT_ADDR,
143 REG_AR_FAULT_ADDR,
144 REG_AW_FAULT_ADDR,
145 REG_AW_FAULT_ADDR
146};
147
148static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
149 "PAGE FAULT",
150 "AR MULTI-HIT FAULT",
151 "AW MULTI-HIT FAULT",
152 "BUS ERROR",
153 "AR SECURITY PROTECTION FAULT",
154 "AR ACCESS PROTECTION FAULT",
155 "AW SECURITY PROTECTION FAULT",
156 "AW ACCESS PROTECTION FAULT",
157 "UNKNOWN FAULT"
158};
159
160struct exynos_iommu_domain {
161 struct list_head clients; /* list of sysmmu_drvdata.node */
162 unsigned long *pgtable; /* lv1 page table, 16KB */
163 short *lv2entcnt; /* free lv2 entry counter for each section */
164 spinlock_t lock; /* lock for this structure */
165 spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
166};
167
168struct sysmmu_drvdata {
169 struct list_head node; /* entry of exynos_iommu_domain.clients */
170 struct device *sysmmu; /* System MMU's device descriptor */
171 struct device *dev; /* Owner of system MMU */
172 char *dbgname;
173 int nsfrs;
174 void __iomem **sfrbases;
175 struct clk *clk[2];
176 int activations;
177 rwlock_t lock;
178 struct iommu_domain *domain;
179 sysmmu_fault_handler_t fault_handler;
180 unsigned long pgtable;
181};
182
183static bool set_sysmmu_active(struct sysmmu_drvdata *data)
184{
185 /* return true if the System MMU was not active previously
186 and it needs to be initialized */
187 return ++data->activations == 1;
188}
189
190static bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
191{
192 /* return true if the System MMU is needed to be disabled */
193 BUG_ON(data->activations < 1);
194 return --data->activations == 0;
195}
196
197static bool is_sysmmu_active(struct sysmmu_drvdata *data)
198{
199 return data->activations > 0;
200}
201
202static void sysmmu_unblock(void __iomem *sfrbase)
203{
204 __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
205}
206
207static bool sysmmu_block(void __iomem *sfrbase)
208{
209 int i = 120;
210
211 __raw_writel(CTRL_BLOCK, sfrbase + REG_MMU_CTRL);
212 while ((i > 0) && !(__raw_readl(sfrbase + REG_MMU_STATUS) & 1))
213 --i;
214
215 if (!(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) {
216 sysmmu_unblock(sfrbase);
217 return false;
218 }
219
220 return true;
221}
222
223static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
224{
225 __raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
226}
227
228static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
229 unsigned long iova)
230{
231 __raw_writel((iova & SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY);
232}
233
234static void __sysmmu_set_ptbase(void __iomem *sfrbase,
235 unsigned long pgd)
236{
237 __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
238 __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
239
240 __sysmmu_tlb_invalidate(sfrbase);
241}
242
243static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
244 unsigned long size, int idx)
245{
246 __raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8);
247 __raw_writel(size - 1 + base, sfrbase + REG_PB0_EADDR + idx * 8);
248}
249
250void exynos_sysmmu_set_prefbuf(struct device *dev,
251 unsigned long base0, unsigned long size0,
252 unsigned long base1, unsigned long size1)
253{
254 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
255 unsigned long flags;
256 int i;
257
258 BUG_ON((base0 + size0) <= base0);
259 BUG_ON((size1 > 0) && ((base1 + size1) <= base1));
260
261 read_lock_irqsave(&data->lock, flags);
262 if (!is_sysmmu_active(data))
263 goto finish;
264
265 for (i = 0; i < data->nsfrs; i++) {
266 if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
267 if (!sysmmu_block(data->sfrbases[i]))
268 continue;
269
270 if (size1 == 0) {
271 if (size0 <= SZ_128K) {
272 base1 = base0;
273 size1 = size0;
274 } else {
275 size1 = size0 -
276 ALIGN(size0 / 2, SZ_64K);
277 size0 = size0 - size1;
278 base1 = base0 + size0;
279 }
280 }
281
282 __sysmmu_set_prefbuf(
283 data->sfrbases[i], base0, size0, 0);
284 __sysmmu_set_prefbuf(
285 data->sfrbases[i], base1, size1, 1);
286
287 sysmmu_unblock(data->sfrbases[i]);
288 }
289 }
290finish:
291 read_unlock_irqrestore(&data->lock, flags);
292}
293
294static void __set_fault_handler(struct sysmmu_drvdata *data,
295 sysmmu_fault_handler_t handler)
296{
297 unsigned long flags;
298
299 write_lock_irqsave(&data->lock, flags);
300 data->fault_handler = handler;
301 write_unlock_irqrestore(&data->lock, flags);
302}
303
304void exynos_sysmmu_set_fault_handler(struct device *dev,
305 sysmmu_fault_handler_t handler)
306{
307 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
308
309 __set_fault_handler(data, handler);
310}
311
312static int default_fault_handler(enum exynos_sysmmu_inttype itype,
313 unsigned long pgtable_base, unsigned long fault_addr)
314{
315 unsigned long *ent;
316
317 if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
318 itype = SYSMMU_FAULT_UNKNOWN;
319
320 pr_err("%s occured at 0x%lx(Page table base: 0x%lx)\n",
321 sysmmu_fault_name[itype], fault_addr, pgtable_base);
322
323 ent = section_entry(__va(pgtable_base), fault_addr);
324 pr_err("\tLv1 entry: 0x%lx\n", *ent);
325
326 if (lv1ent_page(ent)) {
327 ent = page_entry(ent, fault_addr);
328 pr_err("\t Lv2 entry: 0x%lx\n", *ent);
329 }
330
331 pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
332
333 BUG();
334
335 return 0;
336}
337
338static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
339{
340 /* SYSMMU is in blocked when interrupt occurred. */
341 struct sysmmu_drvdata *data = dev_id;
342 struct resource *irqres;
343 struct platform_device *pdev;
344 enum exynos_sysmmu_inttype itype;
345 unsigned long addr = -1;
346
347 int i, ret = -ENOSYS;
348
349 read_lock(&data->lock);
350
351 WARN_ON(!is_sysmmu_active(data));
352
353 pdev = to_platform_device(data->sysmmu);
354 for (i = 0; i < (pdev->num_resources / 2); i++) {
355 irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i);
356 if (irqres && ((int)irqres->start == irq))
357 break;
358 }
359
360 if (i == pdev->num_resources) {
361 itype = SYSMMU_FAULT_UNKNOWN;
362 } else {
363 itype = (enum exynos_sysmmu_inttype)
364 __ffs(__raw_readl(data->sfrbases[i] + REG_INT_STATUS));
365 if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
366 itype = SYSMMU_FAULT_UNKNOWN;
367 else
368 addr = __raw_readl(
369 data->sfrbases[i] + fault_reg_offset[itype]);
370 }
371
372 if (data->domain)
373 ret = report_iommu_fault(data->domain, data->dev,
374 addr, itype);
375
376 if ((ret == -ENOSYS) && data->fault_handler) {
377 unsigned long base = data->pgtable;
378 if (itype != SYSMMU_FAULT_UNKNOWN)
379 base = __raw_readl(
380 data->sfrbases[i] + REG_PT_BASE_ADDR);
381 ret = data->fault_handler(itype, base, addr);
382 }
383
384 if (!ret && (itype != SYSMMU_FAULT_UNKNOWN))
385 __raw_writel(1 << itype, data->sfrbases[i] + REG_INT_CLEAR);
386 else
387 dev_dbg(data->sysmmu, "(%s) %s is not handled.\n",
388 data->dbgname, sysmmu_fault_name[itype]);
389
390 if (itype != SYSMMU_FAULT_UNKNOWN)
391 sysmmu_unblock(data->sfrbases[i]);
392
393 read_unlock(&data->lock);
394
395 return IRQ_HANDLED;
396}
397
398static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
399{
400 unsigned long flags;
401 bool disabled = false;
402 int i;
403
404 write_lock_irqsave(&data->lock, flags);
405
406 if (!set_sysmmu_inactive(data))
407 goto finish;
408
409 for (i = 0; i < data->nsfrs; i++)
410 __raw_writel(CTRL_DISABLE, data->sfrbases[i] + REG_MMU_CTRL);
411
412 if (data->clk[1])
413 clk_disable(data->clk[1]);
414 if (data->clk[0])
415 clk_disable(data->clk[0]);
416
417 disabled = true;
418 data->pgtable = 0;
419 data->domain = NULL;
420finish:
421 write_unlock_irqrestore(&data->lock, flags);
422
423 if (disabled)
424 dev_dbg(data->sysmmu, "(%s) Disabled\n", data->dbgname);
425 else
426 dev_dbg(data->sysmmu, "(%s) %d times left to be disabled\n",
427 data->dbgname, data->activations);
428
429 return disabled;
430}
431
432/* __exynos_sysmmu_enable: Enables System MMU
433 *
434 * returns -error if an error occurred and System MMU is not enabled,
435 * 0 if the System MMU has been just enabled and 1 if System MMU was already
436 * enabled before.
437 */
438static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data,
439 unsigned long pgtable, struct iommu_domain *domain)
440{
441 int i, ret = 0;
442 unsigned long flags;
443
444 write_lock_irqsave(&data->lock, flags);
445
446 if (!set_sysmmu_active(data)) {
447 if (WARN_ON(pgtable != data->pgtable)) {
448 ret = -EBUSY;
449 set_sysmmu_inactive(data);
450 } else {
451 ret = 1;
452 }
453
454 dev_dbg(data->sysmmu, "(%s) Already enabled\n", data->dbgname);
455 goto finish;
456 }
457
458 if (data->clk[0])
459 clk_enable(data->clk[0]);
460 if (data->clk[1])
461 clk_enable(data->clk[1]);
462
463 data->pgtable = pgtable;
464
465 for (i = 0; i < data->nsfrs; i++) {
466 __sysmmu_set_ptbase(data->sfrbases[i], pgtable);
467
468 if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
469 /* System MMU version is 3.x */
470 __raw_writel((1 << 12) | (2 << 28),
471 data->sfrbases[i] + REG_MMU_CFG);
472 __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 0);
473 __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 1);
474 }
475
476 __raw_writel(CTRL_ENABLE, data->sfrbases[i] + REG_MMU_CTRL);
477 }
478
479 data->domain = domain;
480
481 dev_dbg(data->sysmmu, "(%s) Enabled\n", data->dbgname);
482finish:
483 write_unlock_irqrestore(&data->lock, flags);
484
485 return ret;
486}
487
488int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable)
489{
490 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
491 int ret;
492
493 BUG_ON(!memblock_is_memory(pgtable));
494
495 ret = pm_runtime_get_sync(data->sysmmu);
496 if (ret < 0) {
497 dev_dbg(data->sysmmu, "(%s) Failed to enable\n", data->dbgname);
498 return ret;
499 }
500
501 ret = __exynos_sysmmu_enable(data, pgtable, NULL);
502 if (WARN_ON(ret < 0)) {
503 pm_runtime_put(data->sysmmu);
504 dev_err(data->sysmmu,
505 "(%s) Already enabled with page table %#lx\n",
506 data->dbgname, data->pgtable);
507 } else {
508 data->dev = dev;
509 }
510
511 return ret;
512}
513
514bool exynos_sysmmu_disable(struct device *dev)
515{
516 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
517 bool disabled;
518
519 disabled = __exynos_sysmmu_disable(data);
520 pm_runtime_put(data->sysmmu);
521
522 return disabled;
523}
524
525static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)
526{
527 unsigned long flags;
528 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
529
530 read_lock_irqsave(&data->lock, flags);
531
532 if (is_sysmmu_active(data)) {
533 int i;
534 for (i = 0; i < data->nsfrs; i++) {
535 if (sysmmu_block(data->sfrbases[i])) {
536 __sysmmu_tlb_invalidate_entry(
537 data->sfrbases[i], iova);
538 sysmmu_unblock(data->sfrbases[i]);
539 }
540 }
541 } else {
542 dev_dbg(data->sysmmu,
543 "(%s) Disabled. Skipping invalidating TLB.\n",
544 data->dbgname);
545 }
546
547 read_unlock_irqrestore(&data->lock, flags);
548}
549
550void exynos_sysmmu_tlb_invalidate(struct device *dev)
551{
552 unsigned long flags;
553 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
554
555 read_lock_irqsave(&data->lock, flags);
556
557 if (is_sysmmu_active(data)) {
558 int i;
559 for (i = 0; i < data->nsfrs; i++) {
560 if (sysmmu_block(data->sfrbases[i])) {
561 __sysmmu_tlb_invalidate(data->sfrbases[i]);
562 sysmmu_unblock(data->sfrbases[i]);
563 }
564 }
565 } else {
566 dev_dbg(data->sysmmu,
567 "(%s) Disabled. Skipping invalidating TLB.\n",
568 data->dbgname);
569 }
570
571 read_unlock_irqrestore(&data->lock, flags);
572}
573
574static int exynos_sysmmu_probe(struct platform_device *pdev)
575{
576 int i, ret;
577 struct device *dev;
578 struct sysmmu_drvdata *data;
579
580 dev = &pdev->dev;
581
582 data = kzalloc(sizeof(*data), GFP_KERNEL);
583 if (!data) {
584 dev_dbg(dev, "Not enough memory\n");
585 ret = -ENOMEM;
586 goto err_alloc;
587 }
588
589 ret = dev_set_drvdata(dev, data);
590 if (ret) {
591 dev_dbg(dev, "Unabled to initialize driver data\n");
592 goto err_init;
593 }
594
595 data->nsfrs = pdev->num_resources / 2;
596 data->sfrbases = kmalloc(sizeof(*data->sfrbases) * data->nsfrs,
597 GFP_KERNEL);
598 if (data->sfrbases == NULL) {
599 dev_dbg(dev, "Not enough memory\n");
600 ret = -ENOMEM;
601 goto err_init;
602 }
603
604 for (i = 0; i < data->nsfrs; i++) {
605 struct resource *res;
606 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
607 if (!res) {
608 dev_dbg(dev, "Unable to find IOMEM region\n");
609 ret = -ENOENT;
610 goto err_res;
611 }
612
613 data->sfrbases[i] = ioremap(res->start, resource_size(res));
614 if (!data->sfrbases[i]) {
615 dev_dbg(dev, "Unable to map IOMEM @ PA:%#x\n",
616 res->start);
617 ret = -ENOENT;
618 goto err_res;
619 }
620 }
621
622 for (i = 0; i < data->nsfrs; i++) {
623 ret = platform_get_irq(pdev, i);
624 if (ret <= 0) {
625 dev_dbg(dev, "Unable to find IRQ resource\n");
626 goto err_irq;
627 }
628
629 ret = request_irq(ret, exynos_sysmmu_irq, 0,
630 dev_name(dev), data);
631 if (ret) {
632 dev_dbg(dev, "Unabled to register interrupt handler\n");
633 goto err_irq;
634 }
635 }
636
637 if (dev_get_platdata(dev)) {
638 char *deli, *beg;
639 struct sysmmu_platform_data *platdata = dev_get_platdata(dev);
640
641 beg = platdata->clockname;
642
643 for (deli = beg; (*deli != '\0') && (*deli != ','); deli++)
644 /* NOTHING */;
645
646 if (*deli == '\0')
647 deli = NULL;
648 else
649 *deli = '\0';
650
651 data->clk[0] = clk_get(dev, beg);
652 if (IS_ERR(data->clk[0])) {
653 data->clk[0] = NULL;
654 dev_dbg(dev, "No clock descriptor registered\n");
655 }
656
657 if (data->clk[0] && deli) {
658 *deli = ',';
659 data->clk[1] = clk_get(dev, deli + 1);
660 if (IS_ERR(data->clk[1]))
661 data->clk[1] = NULL;
662 }
663
664 data->dbgname = platdata->dbgname;
665 }
666
667 data->sysmmu = dev;
668 rwlock_init(&data->lock);
669 INIT_LIST_HEAD(&data->node);
670
671 __set_fault_handler(data, &default_fault_handler);
672
673 if (dev->parent)
674 pm_runtime_enable(dev);
675
676 dev_dbg(dev, "(%s) Initialized\n", data->dbgname);
677 return 0;
678err_irq:
679 while (i-- > 0) {
680 int irq;
681
682 irq = platform_get_irq(pdev, i);
683 free_irq(irq, data);
684 }
685err_res:
686 while (data->nsfrs-- > 0)
687 iounmap(data->sfrbases[data->nsfrs]);
688 kfree(data->sfrbases);
689err_init:
690 kfree(data);
691err_alloc:
692 dev_err(dev, "Failed to initialize\n");
693 return ret;
694}
695
696static struct platform_driver exynos_sysmmu_driver = {
697 .probe = exynos_sysmmu_probe,
698 .driver = {
699 .owner = THIS_MODULE,
700 .name = "exynos-sysmmu",
701 }
702};
703
704static inline void pgtable_flush(void *vastart, void *vaend)
705{
706 dmac_flush_range(vastart, vaend);
707 outer_flush_range(virt_to_phys(vastart),
708 virt_to_phys(vaend));
709}
710
711static int exynos_iommu_domain_init(struct iommu_domain *domain)
712{
713 struct exynos_iommu_domain *priv;
714
715 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
716 if (!priv)
717 return -ENOMEM;
718
719 priv->pgtable = (unsigned long *)__get_free_pages(
720 GFP_KERNEL | __GFP_ZERO, 2);
721 if (!priv->pgtable)
722 goto err_pgtable;
723
724 priv->lv2entcnt = (short *)__get_free_pages(
725 GFP_KERNEL | __GFP_ZERO, 1);
726 if (!priv->lv2entcnt)
727 goto err_counter;
728
729 pgtable_flush(priv->pgtable, priv->pgtable + NUM_LV1ENTRIES);
730
731 spin_lock_init(&priv->lock);
732 spin_lock_init(&priv->pgtablelock);
733 INIT_LIST_HEAD(&priv->clients);
734
735 domain->priv = priv;
736 return 0;
737
738err_counter:
739 free_pages((unsigned long)priv->pgtable, 2);
740err_pgtable:
741 kfree(priv);
742 return -ENOMEM;
743}
744
745static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
746{
747 struct exynos_iommu_domain *priv = domain->priv;
748 struct sysmmu_drvdata *data;
749 unsigned long flags;
750 int i;
751
752 WARN_ON(!list_empty(&priv->clients));
753
754 spin_lock_irqsave(&priv->lock, flags);
755
756 list_for_each_entry(data, &priv->clients, node) {
757 while (!exynos_sysmmu_disable(data->dev))
758 ; /* until System MMU is actually disabled */
759 }
760
761 spin_unlock_irqrestore(&priv->lock, flags);
762
763 for (i = 0; i < NUM_LV1ENTRIES; i++)
764 if (lv1ent_page(priv->pgtable + i))
765 kfree(__va(lv2table_base(priv->pgtable + i)));
766
767 free_pages((unsigned long)priv->pgtable, 2);
768 free_pages((unsigned long)priv->lv2entcnt, 1);
769 kfree(domain->priv);
770 domain->priv = NULL;
771}
772
773static int exynos_iommu_attach_device(struct iommu_domain *domain,
774 struct device *dev)
775{
776 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
777 struct exynos_iommu_domain *priv = domain->priv;
778 unsigned long flags;
779 int ret;
780
781 ret = pm_runtime_get_sync(data->sysmmu);
782 if (ret < 0)
783 return ret;
784
785 ret = 0;
786
787 spin_lock_irqsave(&priv->lock, flags);
788
789 ret = __exynos_sysmmu_enable(data, __pa(priv->pgtable), domain);
790
791 if (ret == 0) {
792 /* 'data->node' must not be appeared in priv->clients */
793 BUG_ON(!list_empty(&data->node));
794 data->dev = dev;
795 list_add_tail(&data->node, &priv->clients);
796 }
797
798 spin_unlock_irqrestore(&priv->lock, flags);
799
800 if (ret < 0) {
801 dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n",
802 __func__, __pa(priv->pgtable));
803 pm_runtime_put(data->sysmmu);
804 } else if (ret > 0) {
805 dev_dbg(dev, "%s: IOMMU with pgtable 0x%lx already attached\n",
806 __func__, __pa(priv->pgtable));
807 } else {
808 dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n",
809 __func__, __pa(priv->pgtable));
810 }
811
812 return ret;
813}
814
815static void exynos_iommu_detach_device(struct iommu_domain *domain,
816 struct device *dev)
817{
818 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
819 struct exynos_iommu_domain *priv = domain->priv;
820 struct list_head *pos;
821 unsigned long flags;
822 bool found = false;
823
824 spin_lock_irqsave(&priv->lock, flags);
825
826 list_for_each(pos, &priv->clients) {
827 if (list_entry(pos, struct sysmmu_drvdata, node) == data) {
828 found = true;
829 break;
830 }
831 }
832
833 if (!found)
834 goto finish;
835
836 if (__exynos_sysmmu_disable(data)) {
837 dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n",
838 __func__, __pa(priv->pgtable));
839 list_del(&data->node);
840 INIT_LIST_HEAD(&data->node);
841
842 } else {
843 dev_dbg(dev, "%s: Detaching IOMMU with pgtable %#lx delayed",
844 __func__, __pa(priv->pgtable));
845 }
846
847finish:
848 spin_unlock_irqrestore(&priv->lock, flags);
849
850 if (found)
851 pm_runtime_put(data->sysmmu);
852}
853
854static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova,
855 short *pgcounter)
856{
857 if (lv1ent_fault(sent)) {
858 unsigned long *pent;
859
860 pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
861 BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1));
862 if (!pent)
863 return NULL;
864
865 *sent = mk_lv1ent_page(__pa(pent));
866 *pgcounter = NUM_LV2ENTRIES;
867 pgtable_flush(pent, pent + NUM_LV2ENTRIES);
868 pgtable_flush(sent, sent + 1);
869 }
870
871 return page_entry(sent, iova);
872}
873
874static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt)
875{
876 if (lv1ent_section(sent))
877 return -EADDRINUSE;
878
879 if (lv1ent_page(sent)) {
880 if (*pgcnt != NUM_LV2ENTRIES)
881 return -EADDRINUSE;
882
883 kfree(page_entry(sent, 0));
884
885 *pgcnt = 0;
886 }
887
888 *sent = mk_lv1ent_sect(paddr);
889
890 pgtable_flush(sent, sent + 1);
891
892 return 0;
893}
894
895static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size,
896 short *pgcnt)
897{
898 if (size == SPAGE_SIZE) {
899 if (!lv2ent_fault(pent))
900 return -EADDRINUSE;
901
902 *pent = mk_lv2ent_spage(paddr);
903 pgtable_flush(pent, pent + 1);
904 *pgcnt -= 1;
905 } else { /* size == LPAGE_SIZE */
906 int i;
907 for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) {
908 if (!lv2ent_fault(pent)) {
909 memset(pent, 0, sizeof(*pent) * i);
910 return -EADDRINUSE;
911 }
912
913 *pent = mk_lv2ent_lpage(paddr);
914 }
915 pgtable_flush(pent - SPAGES_PER_LPAGE, pent);
916 *pgcnt -= SPAGES_PER_LPAGE;
917 }
918
919 return 0;
920}
921
922static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova,
923 phys_addr_t paddr, size_t size, int prot)
924{
925 struct exynos_iommu_domain *priv = domain->priv;
926 unsigned long *entry;
927 unsigned long flags;
928 int ret = -ENOMEM;
929
930 BUG_ON(priv->pgtable == NULL);
931
932 spin_lock_irqsave(&priv->pgtablelock, flags);
933
934 entry = section_entry(priv->pgtable, iova);
935
936 if (size == SECT_SIZE) {
937 ret = lv1set_section(entry, paddr,
938 &priv->lv2entcnt[lv1ent_offset(iova)]);
939 } else {
940 unsigned long *pent;
941
942 pent = alloc_lv2entry(entry, iova,
943 &priv->lv2entcnt[lv1ent_offset(iova)]);
944
945 if (!pent)
946 ret = -ENOMEM;
947 else
948 ret = lv2set_page(pent, paddr, size,
949 &priv->lv2entcnt[lv1ent_offset(iova)]);
950 }
951
952 if (ret) {
953 pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n",
954 __func__, iova, size);
955 }
956
957 spin_unlock_irqrestore(&priv->pgtablelock, flags);
958
959 return ret;
960}
961
962static size_t exynos_iommu_unmap(struct iommu_domain *domain,
963 unsigned long iova, size_t size)
964{
965 struct exynos_iommu_domain *priv = domain->priv;
966 struct sysmmu_drvdata *data;
967 unsigned long flags;
968 unsigned long *ent;
969
970 BUG_ON(priv->pgtable == NULL);
971
972 spin_lock_irqsave(&priv->pgtablelock, flags);
973
974 ent = section_entry(priv->pgtable, iova);
975
976 if (lv1ent_section(ent)) {
977 BUG_ON(size < SECT_SIZE);
978
979 *ent = 0;
980 pgtable_flush(ent, ent + 1);
981 size = SECT_SIZE;
982 goto done;
983 }
984
985 if (unlikely(lv1ent_fault(ent))) {
986 if (size > SECT_SIZE)
987 size = SECT_SIZE;
988 goto done;
989 }
990
991 /* lv1ent_page(sent) == true here */
992
993 ent = page_entry(ent, iova);
994
995 if (unlikely(lv2ent_fault(ent))) {
996 size = SPAGE_SIZE;
997 goto done;
998 }
999
1000 if (lv2ent_small(ent)) {
1001 *ent = 0;
1002 size = SPAGE_SIZE;
1003 priv->lv2entcnt[lv1ent_offset(iova)] += 1;
1004 goto done;
1005 }
1006
1007 /* lv1ent_large(ent) == true here */
1008 BUG_ON(size < LPAGE_SIZE);
1009
1010 memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
1011
1012 size = LPAGE_SIZE;
1013 priv->lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE;
1014done:
1015 spin_unlock_irqrestore(&priv->pgtablelock, flags);
1016
1017 spin_lock_irqsave(&priv->lock, flags);
1018 list_for_each_entry(data, &priv->clients, node)
1019 sysmmu_tlb_invalidate_entry(data->dev, iova);
1020 spin_unlock_irqrestore(&priv->lock, flags);
1021
1022
1023 return size;
1024}
1025
1026static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
1027 unsigned long iova)
1028{
1029 struct exynos_iommu_domain *priv = domain->priv;
1030 unsigned long *entry;
1031 unsigned long flags;
1032 phys_addr_t phys = 0;
1033
1034 spin_lock_irqsave(&priv->pgtablelock, flags);
1035
1036 entry = section_entry(priv->pgtable, iova);
1037
1038 if (lv1ent_section(entry)) {
1039 phys = section_phys(entry) + section_offs(iova);
1040 } else if (lv1ent_page(entry)) {
1041 entry = page_entry(entry, iova);
1042
1043 if (lv2ent_large(entry))
1044 phys = lpage_phys(entry) + lpage_offs(iova);
1045 else if (lv2ent_small(entry))
1046 phys = spage_phys(entry) + spage_offs(iova);
1047 }
1048
1049 spin_unlock_irqrestore(&priv->pgtablelock, flags);
1050
1051 return phys;
1052}
1053
1054static struct iommu_ops exynos_iommu_ops = {
1055 .domain_init = &exynos_iommu_domain_init,
1056 .domain_destroy = &exynos_iommu_domain_destroy,
1057 .attach_dev = &exynos_iommu_attach_device,
1058 .detach_dev = &exynos_iommu_detach_device,
1059 .map = &exynos_iommu_map,
1060 .unmap = &exynos_iommu_unmap,
1061 .iova_to_phys = &exynos_iommu_iova_to_phys,
1062 .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
1063};
1064
1065static int __init exynos_iommu_init(void)
1066{
1067 int ret;
1068
1069 ret = platform_driver_register(&exynos_sysmmu_driver);
1070
1071 if (ret == 0)
1072 bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
1073
1074 return ret;
1075}
1076subsys_initcall(exynos_iommu_init);