aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKyongHo Cho <pullip.cho@samsung.com>2011-03-06 18:56:48 -0500
committerKukjin Kim <kgene.kim@samsung.com>2011-03-15 08:37:25 -0400
commitb34f003f271d477f61a980d280afc77929047440 (patch)
tree475069c7d6760669ad79eb1d2cc07dd981cdf143 /arch
parent721bbd4a06e83995ac1679d9cdca19a608fb0122 (diff)
ARM: EXYNOS4: Enhancement of System MMU driver
This patch includes the following enhancements for System MMU: - Enhanced readability - Removal of unused data structures or their members - Simplified function definitions - Corrections of some logical errors - Full compliance with Linux coding style - Simpler way of registering callback functions of System MMU faults Signed-off-by: KyongHo Cho <pullip.cho@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-exynos4/dev-sysmmu.c23
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-sysmmu.h4
-rw-r--r--arch/arm/mach-exynos4/include/mach/sysmmu.h88
-rw-r--r--arch/arm/plat-s5p/include/plat/sysmmu.h95
-rw-r--r--arch/arm/plat-s5p/sysmmu.c368
5 files changed, 299 insertions, 279 deletions
diff --git a/arch/arm/mach-exynos4/dev-sysmmu.c b/arch/arm/mach-exynos4/dev-sysmmu.c
index a10790a614ec..6889c9aa6493 100644
--- a/arch/arm/mach-exynos4/dev-sysmmu.c
+++ b/arch/arm/mach-exynos4/dev-sysmmu.c
@@ -15,6 +15,28 @@
15 15
16#include <mach/map.h> 16#include <mach/map.h>
17#include <mach/irqs.h> 17#include <mach/irqs.h>
18#include <mach/sysmmu.h>
19#include <plat/s5p-clock.h>
20
21/* These names must be equal to the clock names in mach-exynos4/clock.c */
22const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = {
23 "SYSMMU_MDMA" ,
24 "SYSMMU_SSS" ,
25 "SYSMMU_FIMC0" ,
26 "SYSMMU_FIMC1" ,
27 "SYSMMU_FIMC2" ,
28 "SYSMMU_FIMC3" ,
29 "SYSMMU_JPEG" ,
30 "SYSMMU_FIMD0" ,
31 "SYSMMU_FIMD1" ,
32 "SYSMMU_PCIe" ,
33 "SYSMMU_G2D" ,
34 "SYSMMU_ROTATOR",
35 "SYSMMU_MDMA2" ,
36 "SYSMMU_TV" ,
37 "SYSMMU_MFC_L" ,
38 "SYSMMU_MFC_R" ,
39};
18 40
19static struct resource exynos4_sysmmu_resource[] = { 41static struct resource exynos4_sysmmu_resource[] = {
20 [0] = { 42 [0] = {
@@ -185,5 +207,4 @@ struct platform_device exynos4_device_sysmmu = {
185 .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource), 207 .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource),
186 .resource = exynos4_sysmmu_resource, 208 .resource = exynos4_sysmmu_resource,
187}; 209};
188
189EXPORT_SYMBOL(exynos4_device_sysmmu); 210EXPORT_SYMBOL(exynos4_device_sysmmu);
diff --git a/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h b/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
index b6aef863b9d6..68ff6ad08a2b 100644
--- a/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
@@ -19,6 +19,10 @@
19#define S5P_MMU_FLUSH 0x00C 19#define S5P_MMU_FLUSH 0x00C
20#define S5P_PT_BASE_ADDR 0x014 20#define S5P_PT_BASE_ADDR 0x014
21#define S5P_INT_STATUS 0x018 21#define S5P_INT_STATUS 0x018
22#define S5P_INT_CLEAR 0x01C
22#define S5P_PAGE_FAULT_ADDR 0x024 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
23 27
24#endif /* __ASM_ARCH_REGS_SYSMMU_H */ 28#endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-exynos4/include/mach/sysmmu.h b/arch/arm/mach-exynos4/include/mach/sysmmu.h
index 1428adad8379..eff3dc37f3da 100644
--- a/arch/arm/mach-exynos4/include/mach/sysmmu.h
+++ b/arch/arm/mach-exynos4/include/mach/sysmmu.h
@@ -13,9 +13,6 @@
13#ifndef __ASM_ARM_ARCH_SYSMMU_H 13#ifndef __ASM_ARM_ARCH_SYSMMU_H
14#define __ASM_ARM_ARCH_SYSMMU_H __FILE__ 14#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
15 15
16#define EXYNOS4_SYSMMU_TOTAL_IPNUM 16
17#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM
18
19enum exynos4_sysmmu_ips { 16enum exynos4_sysmmu_ips {
20 SYSMMU_MDMA, 17 SYSMMU_MDMA,
21 SYSMMU_SSS, 18 SYSMMU_SSS,
@@ -33,90 +30,13 @@ enum exynos4_sysmmu_ips {
33 SYSMMU_TV, 30 SYSMMU_TV,
34 SYSMMU_MFC_L, 31 SYSMMU_MFC_L,
35 SYSMMU_MFC_R, 32 SYSMMU_MFC_R,
33 EXYNOS4_SYSMMU_TOTAL_IPNUM,
36}; 34};
37 35
38static char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = { 36#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM
39 "SYSMMU_MDMA" ,
40 "SYSMMU_SSS" ,
41 "SYSMMU_FIMC0" ,
42 "SYSMMU_FIMC1" ,
43 "SYSMMU_FIMC2" ,
44 "SYSMMU_FIMC3" ,
45 "SYSMMU_JPEG" ,
46 "SYSMMU_FIMD0" ,
47 "SYSMMU_FIMD1" ,
48 "SYSMMU_PCIe" ,
49 "SYSMMU_G2D" ,
50 "SYSMMU_ROTATOR",
51 "SYSMMU_MDMA2" ,
52 "SYSMMU_TV" ,
53 "SYSMMU_MFC_L" ,
54 "SYSMMU_MFC_R" ,
55};
56
57typedef enum exynos4_sysmmu_ips sysmmu_ips;
58
59struct sysmmu_tt_info {
60 unsigned long *pgd;
61 unsigned long pgd_paddr;
62 unsigned long *pte;
63};
64
65struct sysmmu_controller {
66 const char *name;
67
68 /* channels registers */
69 void __iomem *regs;
70
71 /* channel irq */
72 unsigned int irq;
73
74 sysmmu_ips ips;
75
76 /* Translation Table Info. */
77 struct sysmmu_tt_info *tt_info;
78
79 struct resource *mem;
80 struct device *dev;
81
82 /* SysMMU controller enable - true : enable */
83 bool enable;
84};
85
86/**
87 * s5p_sysmmu_enable() - enable system mmu of ip
88 * @ips: The ip connected system mmu.
89 *
90 * This function enable system mmu to transfer address
91 * from virtual address to physical address
92 */
93int s5p_sysmmu_enable(sysmmu_ips ips);
94 37
95/** 38extern const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM];
96 * s5p_sysmmu_disable() - disable sysmmu mmu of ip
97 * @ips: The ip connected system mmu.
98 *
99 * This function disable system mmu to transfer address
100 * from virtual address to physical address
101 */
102int s5p_sysmmu_disable(sysmmu_ips ips);
103 39
104/** 40typedef enum exynos4_sysmmu_ips sysmmu_ips;
105 * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
106 * @ips: The ip connected system mmu.
107 * @pgd: The page table base address.
108 *
109 * This function set page table base address
110 * When system mmu transfer address from virtaul address to physical address,
111 * system mmu refer address information from page table
112 */
113int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
114 41
115/**
116 * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
117 * @ips: The ip connected system mmu.
118 *
119 * This function flush all TLB entry in system mmu
120 */
121int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
122#endif /* __ASM_ARM_ARCH_SYSMMU_H */ 42#endif /* __ASM_ARM_ARCH_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
new file mode 100644
index 000000000000..bf5283c2a19d
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/sysmmu.h
@@ -0,0 +1,95 @@
1/* linux/arch/arm/plat-s5p/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 __ASM__PLAT_SYSMMU_H
14#define __ASM__PLAT_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/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
index ffe8a48bc3c1..89e024f377bb 100644
--- a/arch/arm/plat-s5p/sysmmu.c
+++ b/arch/arm/plat-s5p/sysmmu.c
@@ -12,280 +12,260 @@
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14 14
15#include <asm/pgtable.h>
16
15#include <mach/map.h> 17#include <mach/map.h>
16#include <mach/regs-sysmmu.h> 18#include <mach/regs-sysmmu.h>
17#include <mach/sysmmu.h> 19#include <plat/sysmmu.h>
20
21#define CTRL_ENABLE 0x5
22#define CTRL_BLOCK 0x7
23#define CTRL_DISABLE 0x0
24
25static struct device *dev;
26
27static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
28 S5P_PAGE_FAULT_ADDR,
29 S5P_AR_FAULT_ADDR,
30 S5P_AW_FAULT_ADDR,
31 S5P_DEFAULT_SLAVE_ADDR,
32 S5P_AR_FAULT_ADDR,
33 S5P_AR_FAULT_ADDR,
34 S5P_AW_FAULT_ADDR,
35 S5P_AW_FAULT_ADDR
36};
18 37
19struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM]; 38static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
39 "PAGE FAULT",
40 "AR MULTI-HIT FAULT",
41 "AW MULTI-HIT FAULT",
42 "BUS ERROR",
43 "AR SECURITY PROTECTION FAULT",
44 "AR ACCESS PROTECTION FAULT",
45 "AW SECURITY PROTECTION FAULT",
46 "AW ACCESS PROTECTION FAULT"
47};
20 48
21void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp) 49static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
50 enum S5P_SYSMMU_INTERRUPT_TYPE itype,
51 unsigned long pgtable_base,
52 unsigned long fault_addr);
53
54/*
55 * If adjacent 2 bits are true, the system MMU is enabled.
56 * The system MMU is disabled, otherwise.
57 */
58static unsigned long sysmmu_states;
59
60static inline void set_sysmmu_active(sysmmu_ips ips)
22{ 61{
23 unsigned int reg_mmu_ctrl; 62 sysmmu_states |= 3 << (ips * 2);
24 unsigned int reg_mmu_status;
25 unsigned int reg_pt_base_addr;
26 unsigned int reg_int_status;
27 unsigned int reg_page_ft_addr;
28
29 reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
30 reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
31 reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
32 reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
33 reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
34
35 printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
36 printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
37 printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
38 printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
39
40 switch (reg_int_status & 0xFF) {
41 case 0x1:
42 printk(KERN_INFO "%s: Page fault\n", __func__);
43 printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
44 break;
45 case 0x2:
46 printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
47 break;
48 case 0x4:
49 printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
50 break;
51 case 0x8:
52 printk(KERN_INFO "%s: Bus error\n", __func__);
53 break;
54 case 0x10:
55 printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
56 break;
57 case 0x20:
58 printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
59 break;
60 case 0x40:
61 printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
62 break;
63 case 0x80:
64 printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
65 break;
66 }
67} 63}
68 64
69static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id) 65static inline void set_sysmmu_inactive(sysmmu_ips ips)
70{ 66{
71 unsigned int i; 67 sysmmu_states &= ~(3 << (ips * 2));
72 unsigned int reg_int_status;
73 struct sysmmu_controller *sysmmuconp;
74
75 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
76 sysmmuconp = &s5p_sysmmu_cntlrs[i];
77
78 if (sysmmuconp->enable == true) {
79 reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
80
81 if (reg_int_status & 0xFF)
82 s5p_sysmmu_register(sysmmuconp);
83 }
84 }
85 return IRQ_HANDLED;
86} 68}
87 69
88int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd) 70static inline int is_sysmmu_active(sysmmu_ips ips)
89{ 71{
90 struct sysmmu_controller *sysmmuconp = NULL; 72 return sysmmu_states & (3 << (ips * 2));
91 73}
92 sysmmuconp = &s5p_sysmmu_cntlrs[ips];
93
94 if (sysmmuconp == NULL) {
95 printk(KERN_ERR "failed to get ip's sysmmu info\n");
96 return 1;
97 }
98
99 /* Set sysmmu page table base address */
100 __raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
101 74
102 if (s5p_sysmmu_tlb_invalidate(ips) != 0) 75static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
103 printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
104 76
105 return 0; 77static inline void sysmmu_block(sysmmu_ips ips)
78{
79 __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
80 dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
106} 81}
107 82
108static int s5p_sysmmu_set_tablebase(sysmmu_ips ips) 83static inline void sysmmu_unblock(sysmmu_ips ips)
109{ 84{
110 unsigned int pg; 85 __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
111 struct sysmmu_controller *sysmmuconp; 86 dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
87}
112 88
113 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 89static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
90{
91 __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
92 dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
93}
114 94
115 if (sysmmuconp == NULL) { 95static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
116 printk(KERN_ERR "failed to get ip's sysmmu info\n"); 96{
117 return 1; 97 if (unlikely(pgd == 0)) {
98 pgd = (unsigned long)ZERO_PAGE(0);
99 __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */
100 } else {
101 __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */
118 } 102 }
119 103
120 __asm__("mrc p15, 0, %0, c2, c0, 0" \ 104 __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
121 : "=r" (pg) : : "cc"); \
122 pg &= ~0x3fff;
123
124 printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
125 105
126 /* Set sysmmu page table base address */ 106 dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
127 __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR); 107 sysmmu_ips_name[ips], pgd);
108 __sysmmu_tlb_invalidate(ips);
109}
128 110
129 return 0; 111void sysmmu_set_fault_handler(sysmmu_ips ips,
112 int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
113 unsigned long pgtable_base,
114 unsigned long fault_addr))
115{
116 BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
117 fault_handlers[ips] = handler;
130} 118}
131 119
132int s5p_sysmmu_enable(sysmmu_ips ips) 120static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
133{ 121{
134 unsigned int reg; 122 /* SYSMMU is in blocked when interrupt occurred. */
123 unsigned long base = 0;
124 sysmmu_ips ips = (sysmmu_ips)dev_id;
125 enum S5P_SYSMMU_INTERRUPT_TYPE itype;
135 126
136 struct sysmmu_controller *sysmmuconp; 127 itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
128 __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
137 129
138 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 130 BUG_ON(!((itype >= 0) && (itype < 8)));
139 131
140 if (sysmmuconp == NULL) { 132 dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
141 printk(KERN_ERR "failed to get ip's sysmmu info\n"); 133 sysmmu_ips_name[ips]);
142 return 1;
143 }
144 134
145 s5p_sysmmu_set_tablebase(ips); 135 if (fault_handlers[ips]) {
136 unsigned long addr;
146 137
147 /* replacement policy : LRU */ 138 base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
148 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG); 139 addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]);
149 reg |= 0x1;
150 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
151 140
152 /* Enable interrupt, Enable MMU */ 141 if (fault_handlers[ips](itype, base, addr)) {
153 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL); 142 __raw_writel(1 << itype,
154 reg |= (0x1 << 2) | (0x1 << 0); 143 sysmmusfrs[ips] + S5P_INT_CLEAR);
144 dev_notice(dev, "%s from %s is resolved."
145 " Retrying translation.\n",
146 sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
147 } else {
148 base = 0;
149 }
150 }
155 151
156 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL); 152 sysmmu_unblock(ips);
157 153
158 sysmmuconp->enable = true; 154 if (!base)
155 dev_notice(dev, "%s from %s is not handled.\n",
156 sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
159 157
160 return 0; 158 return IRQ_HANDLED;
161} 159}
162 160
163int s5p_sysmmu_disable(sysmmu_ips ips) 161void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
164{ 162{
165 unsigned int reg; 163 if (is_sysmmu_active(ips)) {
166 164 sysmmu_block(ips);
167 struct sysmmu_controller *sysmmuconp = NULL; 165 __sysmmu_set_ptbase(ips, pgd);
168 166 sysmmu_unblock(ips);
169 if (ips > S5P_SYSMMU_TOTAL_IPNUM) 167 } else {
170 printk(KERN_ERR "failed to get ips parameter\n"); 168 dev_dbg(dev, "%s is disabled. "
171 169 "Skipping initializing page table base.\n",
172 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 170 sysmmu_ips_name[ips]);
173
174 if (sysmmuconp == NULL) {
175 printk(KERN_ERR "failed to get ip's sysmmu info\n");
176 return 1;
177 } 171 }
178
179 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
180
181 /* replacement policy : LRU */
182 reg |= 0x1;
183 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
184
185 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
186
187 /* Disable MMU */
188 reg &= ~0x1;
189 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
190
191 sysmmuconp->enable = false;
192
193 return 0;
194} 172}
195 173
196int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips) 174void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
197{ 175{
198 unsigned int reg; 176 if (!is_sysmmu_active(ips)) {
199 struct sysmmu_controller *sysmmuconp = NULL; 177 __sysmmu_set_ptbase(ips, pgd);
200 178
201 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 179 __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
202 180
203 if (sysmmuconp == NULL) { 181 set_sysmmu_active(ips);
204 printk(KERN_ERR "failed to get ip's sysmmu info\n"); 182 dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
205 return 1; 183 } else {
184 dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]);
206 } 185 }
186}
207 187
208 /* set Block MMU for flush TLB */ 188void s5p_sysmmu_disable(sysmmu_ips ips)
209 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL); 189{
210 reg |= 0x1 << 1; 190 if (is_sysmmu_active(ips)) {
211 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL); 191 __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
212 192 set_sysmmu_inactive(ips);
213 /* flush all TLB entry */ 193 dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
214 __raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH); 194 } else {
215 195 dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]);
216 /* set Un-block MMU after flush TLB */ 196 }
217 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL); 197}
218 reg &= ~(0x1 << 1);
219 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
220 198
221 return 0; 199void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
200{
201 if (is_sysmmu_active(ips)) {
202 sysmmu_block(ips);
203 __sysmmu_tlb_invalidate(ips);
204 sysmmu_unblock(ips);
205 } else {
206 dev_dbg(dev, "%s is disabled. "
207 "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]);
208 }
222} 209}
223 210
224static int s5p_sysmmu_probe(struct platform_device *pdev) 211static int s5p_sysmmu_probe(struct platform_device *pdev)
225{ 212{
226 int i; 213 int i, ret;
227 int ret; 214 struct resource *res, *mem;
228 struct resource *res;
229 struct sysmmu_controller *sysmmuconp;
230 sysmmu_ips ips;
231 215
232 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) { 216 dev = &pdev->dev;
233 sysmmuconp = &s5p_sysmmu_cntlrs[i];
234 if (sysmmuconp == NULL) {
235 printk(KERN_ERR "failed to get ip's sysmmu info\n");
236 ret = -ENOENT;
237 goto err_res;
238 }
239 217
240 sysmmuconp->name = sysmmu_ips_name[i]; 218 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
219 int irq;
241 220
242 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 221 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
243 if (!res) { 222 if (!res) {
244 printk(KERN_ERR "failed to get sysmmu resource\n"); 223 dev_err(dev, "Failed to get the resource of %s.\n",
224 sysmmu_ips_name[i]);
245 ret = -ENODEV; 225 ret = -ENODEV;
246 goto err_res; 226 goto err_res;
247 } 227 }
248 228
249 sysmmuconp->mem = request_mem_region(res->start, 229 mem = request_mem_region(res->start,
250 ((res->end) - (res->start)) + 1, pdev->name); 230 ((res->end) - (res->start)) + 1, pdev->name);
251 if (!sysmmuconp->mem) { 231 if (!mem) {
252 pr_err("failed to request sysmmu memory region\n"); 232 dev_err(dev, "Failed to request the memory region of %s.\n",
233 sysmmu_ips_name[i]);
253 ret = -EBUSY; 234 ret = -EBUSY;
254 goto err_res; 235 goto err_res;
255 } 236 }
256 237
257 sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1); 238 sysmmusfrs[i] = ioremap(res->start, res->end - res->start + 1);
258 if (!sysmmuconp->regs) { 239 if (!sysmmusfrs[i]) {
259 pr_err("failed to sysmmu ioremap\n"); 240 dev_err(dev, "Failed to ioremap() for %s.\n",
241 sysmmu_ips_name[i]);
260 ret = -ENXIO; 242 ret = -ENXIO;
261 goto err_reg; 243 goto err_reg;
262 } 244 }
263 245
264 sysmmuconp->irq = platform_get_irq(pdev, i); 246 irq = platform_get_irq(pdev, i);
265 if (sysmmuconp->irq <= 0) { 247 if (irq <= 0) {
266 pr_err("failed to get sysmmu irq resource\n"); 248 dev_err(dev, "Failed to get the IRQ resource of %s.\n",
249 sysmmu_ips_name[i]);
267 ret = -ENOENT; 250 ret = -ENOENT;
268 goto err_map; 251 goto err_map;
269 } 252 }
270 253
271 ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp); 254 if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
272 if (ret) { 255 pdev->name, (void *)i)) {
273 pr_err("failed to request irq\n"); 256 dev_err(dev, "Failed to request IRQ for %s.\n",
257 sysmmu_ips_name[i]);
274 ret = -ENOENT; 258 ret = -ENOENT;
275 goto err_map; 259 goto err_map;
276 } 260 }
277
278 ips = (sysmmu_ips)i;
279
280 sysmmuconp->ips = ips;
281 } 261 }
282 262
283 return 0; 263 return 0;
284 264
285err_reg:
286 release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
287err_map: 265err_map:
288 iounmap(sysmmuconp->regs); 266 iounmap(sysmmusfrs[i]);
267err_reg:
268 release_mem_region(mem->start, resource_size(mem));
289err_res: 269err_res:
290 return ret; 270 return ret;
291} 271}