diff options
author | KyongHo Cho <pullip.cho@samsung.com> | 2012-04-04 12:23:02 -0400 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-04-04 12:23:02 -0400 |
commit | e1f80f57443838f5f420c774744c50c81c178e2c (patch) | |
tree | 44ee19863726f15b1ddfa3d8334935ca3453cd10 /arch/arm/plat-s5p/sysmmu.c | |
parent | dd775ae2549217d3ae09363e3edb305d0fa19928 (diff) |
S5P: SYSMMU: Remove System MMU device driver
This patch removes System MMU device driver from arm/plat-s5p tree
for transition to implement IOMMU driver.
Although controlling System MMU in this removing driver
is similar to the new IOMMU driver in the following patch,
the new one is almost rewrite of this driver and there is no
benefit to moving the driver file from arch/arm/ to drivers/iommu.
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/plat-s5p/sysmmu.c')
-rw-r--r-- | arch/arm/plat-s5p/sysmmu.c | 313 |
1 files changed, 0 insertions, 313 deletions
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 | |||
26 | static struct device *dev; | ||
27 | |||
28 | static 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 | |||
39 | static 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 | |||
50 | static 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 | */ | ||
59 | static unsigned long sysmmu_states; | ||
60 | |||
61 | static inline void set_sysmmu_active(sysmmu_ips ips) | ||
62 | { | ||
63 | sysmmu_states |= 3 << (ips * 2); | ||
64 | } | ||
65 | |||
66 | static inline void set_sysmmu_inactive(sysmmu_ips ips) | ||
67 | { | ||
68 | sysmmu_states &= ~(3 << (ips * 2)); | ||
69 | } | ||
70 | |||
71 | static inline int is_sysmmu_active(sysmmu_ips ips) | ||
72 | { | ||
73 | return sysmmu_states & (3 << (ips * 2)); | ||
74 | } | ||
75 | |||
76 | static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM]; | ||
77 | |||
78 | static 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 | |||
84 | static 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 | |||
90 | static 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 | |||
96 | static 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 | |||
112 | void 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 | |||
121 | static 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 | |||
162 | void 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 | |||
175 | void 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 | |||
191 | void 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 | |||
203 | void 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 | |||
215 | static 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 | |||
272 | err_map: | ||
273 | iounmap(sysmmusfrs[i]); | ||
274 | err_reg: | ||
275 | release_mem_region(mem->start, resource_size(mem)); | ||
276 | err_res: | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | static int s5p_sysmmu_remove(struct platform_device *pdev) | ||
281 | { | ||
282 | return 0; | ||
283 | } | ||
284 | int s5p_sysmmu_runtime_suspend(struct device *dev) | ||
285 | { | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | int s5p_sysmmu_runtime_resume(struct device *dev) | ||
290 | { | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | const struct dev_pm_ops s5p_sysmmu_pm_ops = { | ||
295 | .runtime_suspend = s5p_sysmmu_runtime_suspend, | ||
296 | .runtime_resume = s5p_sysmmu_runtime_resume, | ||
297 | }; | ||
298 | |||
299 | static 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 | |||
309 | static int __init s5p_sysmmu_init(void) | ||
310 | { | ||
311 | return platform_driver_register(&s5p_sysmmu_driver); | ||
312 | } | ||
313 | arch_initcall(s5p_sysmmu_init); | ||