1 /* linux/arch/arm/plat-s5p/sysmmu.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
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.
12 #include <linux/interrupt.h>
13 #include <linux/platform_device.h>
16 #include <mach/regs-sysmmu.h>
17 #include <mach/sysmmu.h>
19 struct sysmmu_controller s5p_sysmmu_cntlrs
[S5P_SYSMMU_TOTAL_IPNUM
];
21 void s5p_sysmmu_register(struct sysmmu_controller
*sysmmuconp
)
23 unsigned int reg_mmu_ctrl
;
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
;
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
);
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
);
40 switch (reg_int_status
& 0xFF) {
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
);
46 printk(KERN_INFO
"%s: AR multi-hit fault\n", __func__
);
49 printk(KERN_INFO
"%s: AW multi-hit fault\n", __func__
);
52 printk(KERN_INFO
"%s: Bus error\n", __func__
);
55 printk(KERN_INFO
"%s: AR Security protection fault\n", __func__
);
58 printk(KERN_INFO
"%s: AR Access protection fault\n", __func__
);
61 printk(KERN_INFO
"%s: AW Security protection fault\n", __func__
);
64 printk(KERN_INFO
"%s: AW Access protection fault\n", __func__
);
69 static irqreturn_t
s5p_sysmmu_irq(int irq
, void *dev_id
)
72 unsigned int reg_int_status
;
73 struct sysmmu_controller
*sysmmuconp
;
75 for (i
= 0; i
< S5P_SYSMMU_TOTAL_IPNUM
; i
++) {
76 sysmmuconp
= &s5p_sysmmu_cntlrs
[i
];
78 if (sysmmuconp
->enable
== true) {
79 reg_int_status
= __raw_readl(sysmmuconp
->regs
+ S5P_INT_STATUS
);
81 if (reg_int_status
& 0xFF)
82 s5p_sysmmu_register(sysmmuconp
);
88 int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips
, unsigned long pgd
)
90 struct sysmmu_controller
*sysmmuconp
= NULL
;
92 sysmmuconp
= &s5p_sysmmu_cntlrs
[ips
];
94 if (sysmmuconp
== NULL
) {
95 printk(KERN_ERR
"failed to get ip's sysmmu info\n");
99 /* Set sysmmu page table base address */
100 __raw_writel(pgd
, sysmmuconp
->regs
+ S5P_PT_BASE_ADDR
);
102 if (s5p_sysmmu_tlb_invalidate(ips
) != 0)
103 printk(KERN_ERR
"failed s5p_sysmmu_tlb_invalidate\n");
108 static int s5p_sysmmu_set_tablebase(sysmmu_ips ips
)
111 struct sysmmu_controller
*sysmmuconp
;
113 sysmmuconp
= &s5p_sysmmu_cntlrs
[ips
];
115 if (sysmmuconp
== NULL
) {
116 printk(KERN_ERR
"failed to get ip's sysmmu info\n");
120 __asm__("mrc p15, 0, %0, c2, c0, 0" \
121 : "=r" (pg
) : : "cc"); \
124 printk(KERN_INFO
"%s: CP15 TTBR0 : 0x%x\n", __func__
, pg
);
126 /* Set sysmmu page table base address */
127 __raw_writel(pg
, sysmmuconp
->regs
+ S5P_PT_BASE_ADDR
);
132 int s5p_sysmmu_enable(sysmmu_ips ips
)
136 struct sysmmu_controller
*sysmmuconp
;
138 sysmmuconp
= &s5p_sysmmu_cntlrs
[ips
];
140 if (sysmmuconp
== NULL
) {
141 printk(KERN_ERR
"failed to get ip's sysmmu info\n");
145 s5p_sysmmu_set_tablebase(ips
);
147 /* replacement policy : LRU */
148 reg
= __raw_readl(sysmmuconp
->regs
+ S5P_MMU_CFG
);
150 __raw_writel(reg
, sysmmuconp
->regs
+ S5P_MMU_CFG
);
152 /* Enable interrupt, Enable MMU */
153 reg
= __raw_readl(sysmmuconp
->regs
+ S5P_MMU_CTRL
);
154 reg
|= (0x1 << 2) | (0x1 << 0);
156 __raw_writel(reg
, sysmmuconp
->regs
+ S5P_MMU_CTRL
);
158 sysmmuconp
->enable
= true;
163 int s5p_sysmmu_disable(sysmmu_ips ips
)
167 struct sysmmu_controller
*sysmmuconp
= NULL
;
169 if (ips
> S5P_SYSMMU_TOTAL_IPNUM
)
170 printk(KERN_ERR
"failed to get ips parameter\n");
172 sysmmuconp
= &s5p_sysmmu_cntlrs
[ips
];
174 if (sysmmuconp
== NULL
) {
175 printk(KERN_ERR
"failed to get ip's sysmmu info\n");
179 reg
= __raw_readl(sysmmuconp
->regs
+ S5P_MMU_CFG
);
181 /* replacement policy : LRU */
183 __raw_writel(reg
, sysmmuconp
->regs
+ S5P_MMU_CFG
);
185 reg
= __raw_readl(sysmmuconp
->regs
+ S5P_MMU_CTRL
);
189 __raw_writel(reg
, sysmmuconp
->regs
+ S5P_MMU_CTRL
);
191 sysmmuconp
->enable
= false;
196 int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips
)
199 struct sysmmu_controller
*sysmmuconp
= NULL
;
201 sysmmuconp
= &s5p_sysmmu_cntlrs
[ips
];
203 if (sysmmuconp
== NULL
) {
204 printk(KERN_ERR
"failed to get ip's sysmmu info\n");
208 /* set Block MMU for flush TLB */
209 reg
= __raw_readl(sysmmuconp
->regs
+ S5P_MMU_CTRL
);
211 __raw_writel(reg
, sysmmuconp
->regs
+ S5P_MMU_CTRL
);
213 /* flush all TLB entry */
214 __raw_writel(0x1, sysmmuconp
->regs
+ S5P_MMU_FLUSH
);
216 /* set Un-block MMU after flush TLB */
217 reg
= __raw_readl(sysmmuconp
->regs
+ S5P_MMU_CTRL
);
219 __raw_writel(reg
, sysmmuconp
->regs
+ S5P_MMU_CTRL
);
224 static int s5p_sysmmu_probe(struct platform_device
*pdev
)
228 struct resource
*res
;
229 struct sysmmu_controller
*sysmmuconp
;
232 for (i
= 0; i
< S5P_SYSMMU_TOTAL_IPNUM
; i
++) {
233 sysmmuconp
= &s5p_sysmmu_cntlrs
[i
];
234 if (sysmmuconp
== NULL
) {
235 printk(KERN_ERR
"failed to get ip's sysmmu info\n");
240 sysmmuconp
->name
= sysmmu_ips_name
[i
];
242 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, i
);
244 printk(KERN_ERR
"failed to get sysmmu resource\n");
249 sysmmuconp
->mem
= request_mem_region(res
->start
,
250 ((res
->end
) - (res
->start
)) + 1, pdev
->name
);
251 if (!sysmmuconp
->mem
) {
252 pr_err("failed to request sysmmu memory region\n");
257 sysmmuconp
->regs
= ioremap(res
->start
, res
->end
- res
->start
+ 1);
258 if (!sysmmuconp
->regs
) {
259 pr_err("failed to sysmmu ioremap\n");
264 sysmmuconp
->irq
= platform_get_irq(pdev
, i
);
265 if (sysmmuconp
->irq
<= 0) {
266 pr_err("failed to get sysmmu irq resource\n");
271 ret
= request_irq(sysmmuconp
->irq
, s5p_sysmmu_irq
, IRQF_DISABLED
, pdev
->name
, sysmmuconp
);
273 pr_err("failed to request irq\n");
280 sysmmuconp
->ips
= ips
;
286 release_mem_region((resource_size_t
)sysmmuconp
->mem
, (resource_size_t
)((res
->end
) - (res
->start
) + 1));
288 iounmap(sysmmuconp
->regs
);
293 static int s5p_sysmmu_remove(struct platform_device
*pdev
)
297 int s5p_sysmmu_runtime_suspend(struct device
*dev
)
302 int s5p_sysmmu_runtime_resume(struct device
*dev
)
307 const struct dev_pm_ops s5p_sysmmu_pm_ops
= {
308 .runtime_suspend
= s5p_sysmmu_runtime_suspend
,
309 .runtime_resume
= s5p_sysmmu_runtime_resume
,
312 static struct platform_driver s5p_sysmmu_driver
= {
313 .probe
= s5p_sysmmu_probe
,
314 .remove
= s5p_sysmmu_remove
,
316 .owner
= THIS_MODULE
,
317 .name
= "s5p-sysmmu",
318 .pm
= &s5p_sysmmu_pm_ops
,
322 static int __init
s5p_sysmmu_init(void)
324 return platform_driver_register(&s5p_sysmmu_driver
);
326 arch_initcall(s5p_sysmmu_init
);