aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2012-11-02 15:24:06 -0400
committerTony Lindgren <tony@atomide.com>2012-11-20 13:04:41 -0500
commited1c7de29f9f3d56b3ca5ef69682cc1a3d369e9d (patch)
treecd61bc6adacd14f97d12e51f43171bf0b685727f /drivers/iommu
parentc8d35c84f5494d8d294205b598f927a11fd41f34 (diff)
ARM: OMAP2+: Move iommu2 to drivers/iommu/omap-iommu2.c
This file should not be in arch/arm. Move it to drivers/iommu to allow making most of the header local to drivers/iommu. This is needed as we are removing plat and mach includes from drivers for ARM common zImage support. Cc: Ido Yariv <ido@wizery.com> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: Mauro Carvalho Chehab <mchehab@infradead.org> Cc: Omar Ramirez Luna <omar.luna@linaro.org> Cc: linux-media@vger.kernel.org Acked-by: Ohad Ben-Cohen <ohad@wizery.com> Acked-by: Joerg Roedel <joro@8bytes.org> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/omap-iommu-debug.c1
-rw-r--r--drivers/iommu/omap-iommu.c19
-rw-r--r--drivers/iommu/omap-iommu.h255
-rw-r--r--drivers/iommu/omap-iommu2.c364
-rw-r--r--drivers/iommu/omap-iopgtable.h22
-rw-r--r--drivers/iommu/omap-iovmm.c1
7 files changed, 641 insertions, 22 deletions
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 14a4d5fc94f..f66b816d455 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_DMAR_TABLE) += dmar.o
7obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o 7obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
8obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o 8obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
9obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o 9obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
10obj-$(CONFIG_OMAP_IOMMU) += omap-iommu2.o
10obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o 11obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
11obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o 12obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
12obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o 13obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index cf4a0b5c1d8..d0427bd2136 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -23,6 +23,7 @@
23#include <plat/iommu.h> 23#include <plat/iommu.h>
24 24
25#include "omap-iopgtable.h" 25#include "omap-iopgtable.h"
26#include "omap-iommu.h"
26 27
27#define MAXCOLUMN 100 /* for short messages */ 28#define MAXCOLUMN 100 /* for short messages */
28 29
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index eadcfde757e..4db86e12c20 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -22,12 +22,14 @@
22#include <linux/omap-iommu.h> 22#include <linux/omap-iommu.h>
23#include <linux/mutex.h> 23#include <linux/mutex.h>
24#include <linux/spinlock.h> 24#include <linux/spinlock.h>
25#include <linux/io.h>
25 26
26#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
27 28
28#include <plat/iommu.h> 29#include <plat/iommu.h>
29 30
30#include "omap-iopgtable.h" 31#include "omap-iopgtable.h"
32#include "omap-iommu.h"
31 33
32#define for_each_iotlb_cr(obj, n, __i, cr) \ 34#define for_each_iotlb_cr(obj, n, __i, cr) \
33 for (__i = 0; \ 35 for (__i = 0; \
@@ -1016,6 +1018,23 @@ static void iopte_cachep_ctor(void *iopte)
1016 clean_dcache_area(iopte, IOPTE_TABLE_SIZE); 1018 clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
1017} 1019}
1018 1020
1021static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
1022 u32 flags)
1023{
1024 memset(e, 0, sizeof(*e));
1025
1026 e->da = da;
1027 e->pa = pa;
1028 e->valid = 1;
1029 /* FIXME: add OMAP1 support */
1030 e->pgsz = flags & MMU_CAM_PGSZ_MASK;
1031 e->endian = flags & MMU_RAM_ENDIAN_MASK;
1032 e->elsz = flags & MMU_RAM_ELSZ_MASK;
1033 e->mixed = flags & MMU_RAM_MIXED_MASK;
1034
1035 return iopgsz_to_bytes(e->pgsz);
1036}
1037
1019static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, 1038static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
1020 phys_addr_t pa, size_t bytes, int prot) 1039 phys_addr_t pa, size_t bytes, int prot)
1021{ 1040{
diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h
new file mode 100644
index 00000000000..8c3378d99b8
--- /dev/null
+++ b/drivers/iommu/omap-iommu.h
@@ -0,0 +1,255 @@
1/*
2 * omap iommu: main structures
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
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#if defined(CONFIG_ARCH_OMAP1)
14#error "iommu for this processor not implemented yet"
15#endif
16
17struct iotlb_entry {
18 u32 da;
19 u32 pa;
20 u32 pgsz, prsvd, valid;
21 union {
22 u16 ap;
23 struct {
24 u32 endian, elsz, mixed;
25 };
26 };
27};
28
29struct omap_iommu {
30 const char *name;
31 struct module *owner;
32 struct clk *clk;
33 void __iomem *regbase;
34 struct device *dev;
35 void *isr_priv;
36 struct iommu_domain *domain;
37
38 unsigned int refcount;
39 spinlock_t iommu_lock; /* global for this whole object */
40
41 /*
42 * We don't change iopgd for a situation like pgd for a task,
43 * but share it globally for each iommu.
44 */
45 u32 *iopgd;
46 spinlock_t page_table_lock; /* protect iopgd */
47
48 int nr_tlb_entries;
49
50 struct list_head mmap;
51 struct mutex mmap_lock; /* protect mmap */
52
53 void *ctx; /* iommu context: registres saved area */
54 u32 da_start;
55 u32 da_end;
56};
57
58struct cr_regs {
59 union {
60 struct {
61 u16 cam_l;
62 u16 cam_h;
63 };
64 u32 cam;
65 };
66 union {
67 struct {
68 u16 ram_l;
69 u16 ram_h;
70 };
71 u32 ram;
72 };
73};
74
75struct iotlb_lock {
76 short base;
77 short vict;
78};
79
80/* architecture specific functions */
81struct iommu_functions {
82 unsigned long version;
83
84 int (*enable)(struct omap_iommu *obj);
85 void (*disable)(struct omap_iommu *obj);
86 void (*set_twl)(struct omap_iommu *obj, bool on);
87 u32 (*fault_isr)(struct omap_iommu *obj, u32 *ra);
88
89 void (*tlb_read_cr)(struct omap_iommu *obj, struct cr_regs *cr);
90 void (*tlb_load_cr)(struct omap_iommu *obj, struct cr_regs *cr);
91
92 struct cr_regs *(*alloc_cr)(struct omap_iommu *obj,
93 struct iotlb_entry *e);
94 int (*cr_valid)(struct cr_regs *cr);
95 u32 (*cr_to_virt)(struct cr_regs *cr);
96 void (*cr_to_e)(struct cr_regs *cr, struct iotlb_entry *e);
97 ssize_t (*dump_cr)(struct omap_iommu *obj, struct cr_regs *cr,
98 char *buf);
99
100 u32 (*get_pte_attr)(struct iotlb_entry *e);
101
102 void (*save_ctx)(struct omap_iommu *obj);
103 void (*restore_ctx)(struct omap_iommu *obj);
104 ssize_t (*dump_ctx)(struct omap_iommu *obj, char *buf, ssize_t len);
105};
106
107#ifdef CONFIG_IOMMU_API
108/**
109 * dev_to_omap_iommu() - retrieves an omap iommu object from a user device
110 * @dev: iommu client device
111 */
112static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev)
113{
114 struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
115
116 return arch_data->iommu_dev;
117}
118#endif
119
120/* IOMMU errors */
121#define OMAP_IOMMU_ERR_TLB_MISS (1 << 0)
122#define OMAP_IOMMU_ERR_TRANS_FAULT (1 << 1)
123#define OMAP_IOMMU_ERR_EMU_MISS (1 << 2)
124#define OMAP_IOMMU_ERR_TBLWALK_FAULT (1 << 3)
125#define OMAP_IOMMU_ERR_MULTIHIT_FAULT (1 << 4)
126
127/*
128 * MMU Register offsets
129 */
130#define MMU_REVISION 0x00
131#define MMU_SYSCONFIG 0x10
132#define MMU_SYSSTATUS 0x14
133#define MMU_IRQSTATUS 0x18
134#define MMU_IRQENABLE 0x1c
135#define MMU_WALKING_ST 0x40
136#define MMU_CNTL 0x44
137#define MMU_FAULT_AD 0x48
138#define MMU_TTB 0x4c
139#define MMU_LOCK 0x50
140#define MMU_LD_TLB 0x54
141#define MMU_CAM 0x58
142#define MMU_RAM 0x5c
143#define MMU_GFLUSH 0x60
144#define MMU_FLUSH_ENTRY 0x64
145#define MMU_READ_CAM 0x68
146#define MMU_READ_RAM 0x6c
147#define MMU_EMU_FAULT_AD 0x70
148
149#define MMU_REG_SIZE 256
150
151/*
152 * MMU Register bit definitions
153 */
154#define MMU_LOCK_BASE_SHIFT 10
155#define MMU_LOCK_BASE_MASK (0x1f << MMU_LOCK_BASE_SHIFT)
156#define MMU_LOCK_BASE(x) \
157 ((x & MMU_LOCK_BASE_MASK) >> MMU_LOCK_BASE_SHIFT)
158
159#define MMU_LOCK_VICT_SHIFT 4
160#define MMU_LOCK_VICT_MASK (0x1f << MMU_LOCK_VICT_SHIFT)
161#define MMU_LOCK_VICT(x) \
162 ((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT)
163
164#define MMU_CAM_VATAG_SHIFT 12
165#define MMU_CAM_VATAG_MASK \
166 ((~0UL >> MMU_CAM_VATAG_SHIFT) << MMU_CAM_VATAG_SHIFT)
167#define MMU_CAM_P (1 << 3)
168#define MMU_CAM_V (1 << 2)
169#define MMU_CAM_PGSZ_MASK 3
170#define MMU_CAM_PGSZ_1M (0 << 0)
171#define MMU_CAM_PGSZ_64K (1 << 0)
172#define MMU_CAM_PGSZ_4K (2 << 0)
173#define MMU_CAM_PGSZ_16M (3 << 0)
174
175#define MMU_RAM_PADDR_SHIFT 12
176#define MMU_RAM_PADDR_MASK \
177 ((~0UL >> MMU_RAM_PADDR_SHIFT) << MMU_RAM_PADDR_SHIFT)
178
179#define MMU_RAM_ENDIAN_MASK (1 << MMU_RAM_ENDIAN_SHIFT)
180#define MMU_RAM_ENDIAN_BIG (1 << MMU_RAM_ENDIAN_SHIFT)
181
182#define MMU_RAM_ELSZ_MASK (3 << MMU_RAM_ELSZ_SHIFT)
183#define MMU_RAM_ELSZ_8 (0 << MMU_RAM_ELSZ_SHIFT)
184#define MMU_RAM_ELSZ_16 (1 << MMU_RAM_ELSZ_SHIFT)
185#define MMU_RAM_ELSZ_32 (2 << MMU_RAM_ELSZ_SHIFT)
186#define MMU_RAM_ELSZ_NONE (3 << MMU_RAM_ELSZ_SHIFT)
187#define MMU_RAM_MIXED_SHIFT 6
188#define MMU_RAM_MIXED_MASK (1 << MMU_RAM_MIXED_SHIFT)
189#define MMU_RAM_MIXED MMU_RAM_MIXED_MASK
190
191/*
192 * utilities for super page(16MB, 1MB, 64KB and 4KB)
193 */
194
195#define iopgsz_max(bytes) \
196 (((bytes) >= SZ_16M) ? SZ_16M : \
197 ((bytes) >= SZ_1M) ? SZ_1M : \
198 ((bytes) >= SZ_64K) ? SZ_64K : \
199 ((bytes) >= SZ_4K) ? SZ_4K : 0)
200
201#define bytes_to_iopgsz(bytes) \
202 (((bytes) == SZ_16M) ? MMU_CAM_PGSZ_16M : \
203 ((bytes) == SZ_1M) ? MMU_CAM_PGSZ_1M : \
204 ((bytes) == SZ_64K) ? MMU_CAM_PGSZ_64K : \
205 ((bytes) == SZ_4K) ? MMU_CAM_PGSZ_4K : -1)
206
207#define iopgsz_to_bytes(iopgsz) \
208 (((iopgsz) == MMU_CAM_PGSZ_16M) ? SZ_16M : \
209 ((iopgsz) == MMU_CAM_PGSZ_1M) ? SZ_1M : \
210 ((iopgsz) == MMU_CAM_PGSZ_64K) ? SZ_64K : \
211 ((iopgsz) == MMU_CAM_PGSZ_4K) ? SZ_4K : 0)
212
213#define iopgsz_ok(bytes) (bytes_to_iopgsz(bytes) >= 0)
214
215/*
216 * global functions
217 */
218extern u32 omap_iommu_arch_version(void);
219
220extern void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
221
222extern int
223omap_iopgtable_store_entry(struct omap_iommu *obj, struct iotlb_entry *e);
224
225extern int omap_iommu_set_isr(const char *name,
226 int (*isr)(struct omap_iommu *obj, u32 da, u32 iommu_errs,
227 void *priv),
228 void *isr_priv);
229
230extern void omap_iommu_save_ctx(struct device *dev);
231extern void omap_iommu_restore_ctx(struct device *dev);
232
233extern int omap_install_iommu_arch(const struct iommu_functions *ops);
234extern void omap_uninstall_iommu_arch(const struct iommu_functions *ops);
235
236extern int omap_foreach_iommu_device(void *data,
237 int (*fn)(struct device *, void *));
238
239extern ssize_t
240omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len);
241extern size_t
242omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t len);
243
244/*
245 * register accessors
246 */
247static inline u32 iommu_read_reg(struct omap_iommu *obj, size_t offs)
248{
249 return __raw_readl(obj->regbase + offs);
250}
251
252static inline void iommu_write_reg(struct omap_iommu *obj, u32 val, size_t offs)
253{
254 __raw_writel(val, obj->regbase + offs);
255}
diff --git a/drivers/iommu/omap-iommu2.c b/drivers/iommu/omap-iommu2.c
new file mode 100644
index 00000000000..f97c3863ef8
--- /dev/null
+++ b/drivers/iommu/omap-iommu2.c
@@ -0,0 +1,364 @@
1/*
2 * omap iommu: omap2/3 architecture specific functions
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
7 * Paul Mundt and Toshihiro Kobayashi
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/err.h>
15#include <linux/device.h>
16#include <linux/io.h>
17#include <linux/jiffies.h>
18#include <linux/module.h>
19#include <linux/omap-iommu.h>
20#include <linux/slab.h>
21#include <linux/stringify.h>
22
23#include <plat/iommu.h>
24#include "omap-iommu.h"
25
26/*
27 * omap2 architecture specific register bit definitions
28 */
29#define IOMMU_ARCH_VERSION 0x00000011
30
31/* SYSCONF */
32#define MMU_SYS_IDLE_SHIFT 3
33#define MMU_SYS_IDLE_FORCE (0 << MMU_SYS_IDLE_SHIFT)
34#define MMU_SYS_IDLE_NONE (1 << MMU_SYS_IDLE_SHIFT)
35#define MMU_SYS_IDLE_SMART (2 << MMU_SYS_IDLE_SHIFT)
36#define MMU_SYS_IDLE_MASK (3 << MMU_SYS_IDLE_SHIFT)
37
38#define MMU_SYS_SOFTRESET (1 << 1)
39#define MMU_SYS_AUTOIDLE 1
40
41/* SYSSTATUS */
42#define MMU_SYS_RESETDONE 1
43
44/* IRQSTATUS & IRQENABLE */
45#define MMU_IRQ_MULTIHITFAULT (1 << 4)
46#define MMU_IRQ_TABLEWALKFAULT (1 << 3)
47#define MMU_IRQ_EMUMISS (1 << 2)
48#define MMU_IRQ_TRANSLATIONFAULT (1 << 1)
49#define MMU_IRQ_TLBMISS (1 << 0)
50
51#define __MMU_IRQ_FAULT \
52 (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_EMUMISS | MMU_IRQ_TRANSLATIONFAULT)
53#define MMU_IRQ_MASK \
54 (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_TLBMISS)
55#define MMU_IRQ_TWL_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT)
56#define MMU_IRQ_TLB_MISS_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TLBMISS)
57
58/* MMU_CNTL */
59#define MMU_CNTL_SHIFT 1
60#define MMU_CNTL_MASK (7 << MMU_CNTL_SHIFT)
61#define MMU_CNTL_EML_TLB (1 << 3)
62#define MMU_CNTL_TWL_EN (1 << 2)
63#define MMU_CNTL_MMU_EN (1 << 1)
64
65#define get_cam_va_mask(pgsz) \
66 (((pgsz) == MMU_CAM_PGSZ_16M) ? 0xff000000 : \
67 ((pgsz) == MMU_CAM_PGSZ_1M) ? 0xfff00000 : \
68 ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \
69 ((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0)
70
71
72static void __iommu_set_twl(struct omap_iommu *obj, bool on)
73{
74 u32 l = iommu_read_reg(obj, MMU_CNTL);
75
76 if (on)
77 iommu_write_reg(obj, MMU_IRQ_TWL_MASK, MMU_IRQENABLE);
78 else
79 iommu_write_reg(obj, MMU_IRQ_TLB_MISS_MASK, MMU_IRQENABLE);
80
81 l &= ~MMU_CNTL_MASK;
82 if (on)
83 l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
84 else
85 l |= (MMU_CNTL_MMU_EN);
86
87 iommu_write_reg(obj, l, MMU_CNTL);
88}
89
90
91static int omap2_iommu_enable(struct omap_iommu *obj)
92{
93 u32 l, pa;
94 unsigned long timeout;
95
96 if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K))
97 return -EINVAL;
98
99 pa = virt_to_phys(obj->iopgd);
100 if (!IS_ALIGNED(pa, SZ_16K))
101 return -EINVAL;
102
103 iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG);
104
105 timeout = jiffies + msecs_to_jiffies(20);
106 do {
107 l = iommu_read_reg(obj, MMU_SYSSTATUS);
108 if (l & MMU_SYS_RESETDONE)
109 break;
110 } while (!time_after(jiffies, timeout));
111
112 if (!(l & MMU_SYS_RESETDONE)) {
113 dev_err(obj->dev, "can't take mmu out of reset\n");
114 return -ENODEV;
115 }
116
117 l = iommu_read_reg(obj, MMU_REVISION);
118 dev_info(obj->dev, "%s: version %d.%d\n", obj->name,
119 (l >> 4) & 0xf, l & 0xf);
120
121 l = iommu_read_reg(obj, MMU_SYSCONFIG);
122 l &= ~MMU_SYS_IDLE_MASK;
123 l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
124 iommu_write_reg(obj, l, MMU_SYSCONFIG);
125
126 iommu_write_reg(obj, pa, MMU_TTB);
127
128 __iommu_set_twl(obj, true);
129
130 return 0;
131}
132
133static void omap2_iommu_disable(struct omap_iommu *obj)
134{
135 u32 l = iommu_read_reg(obj, MMU_CNTL);
136
137 l &= ~MMU_CNTL_MASK;
138 iommu_write_reg(obj, l, MMU_CNTL);
139 iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG);
140
141 dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
142}
143
144static void omap2_iommu_set_twl(struct omap_iommu *obj, bool on)
145{
146 __iommu_set_twl(obj, false);
147}
148
149static u32 omap2_iommu_fault_isr(struct omap_iommu *obj, u32 *ra)
150{
151 u32 stat, da;
152 u32 errs = 0;
153
154 stat = iommu_read_reg(obj, MMU_IRQSTATUS);
155 stat &= MMU_IRQ_MASK;
156 if (!stat) {
157 *ra = 0;
158 return 0;
159 }
160
161 da = iommu_read_reg(obj, MMU_FAULT_AD);
162 *ra = da;
163
164 if (stat & MMU_IRQ_TLBMISS)
165 errs |= OMAP_IOMMU_ERR_TLB_MISS;
166 if (stat & MMU_IRQ_TRANSLATIONFAULT)
167 errs |= OMAP_IOMMU_ERR_TRANS_FAULT;
168 if (stat & MMU_IRQ_EMUMISS)
169 errs |= OMAP_IOMMU_ERR_EMU_MISS;
170 if (stat & MMU_IRQ_TABLEWALKFAULT)
171 errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT;
172 if (stat & MMU_IRQ_MULTIHITFAULT)
173 errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT;
174 iommu_write_reg(obj, stat, MMU_IRQSTATUS);
175
176 return errs;
177}
178
179static void omap2_tlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
180{
181 cr->cam = iommu_read_reg(obj, MMU_READ_CAM);
182 cr->ram = iommu_read_reg(obj, MMU_READ_RAM);
183}
184
185static void omap2_tlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
186{
187 iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM);
188 iommu_write_reg(obj, cr->ram, MMU_RAM);
189}
190
191static u32 omap2_cr_to_virt(struct cr_regs *cr)
192{
193 u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK;
194 u32 mask = get_cam_va_mask(cr->cam & page_size);
195
196 return cr->cam & mask;
197}
198
199static struct cr_regs *omap2_alloc_cr(struct omap_iommu *obj,
200 struct iotlb_entry *e)
201{
202 struct cr_regs *cr;
203
204 if (e->da & ~(get_cam_va_mask(e->pgsz))) {
205 dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__,
206 e->da);
207 return ERR_PTR(-EINVAL);
208 }
209
210 cr = kmalloc(sizeof(*cr), GFP_KERNEL);
211 if (!cr)
212 return ERR_PTR(-ENOMEM);
213
214 cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz | e->valid;
215 cr->ram = e->pa | e->endian | e->elsz | e->mixed;
216
217 return cr;
218}
219
220static inline int omap2_cr_valid(struct cr_regs *cr)
221{
222 return cr->cam & MMU_CAM_V;
223}
224
225static u32 omap2_get_pte_attr(struct iotlb_entry *e)
226{
227 u32 attr;
228
229 attr = e->mixed << 5;
230 attr |= e->endian;
231 attr |= e->elsz >> 3;
232 attr <<= (((e->pgsz == MMU_CAM_PGSZ_4K) ||
233 (e->pgsz == MMU_CAM_PGSZ_64K)) ? 0 : 6);
234 return attr;
235}
236
237static ssize_t
238omap2_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, char *buf)
239{
240 char *p = buf;
241
242 /* FIXME: Need more detail analysis of cam/ram */
243 p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram,
244 (cr->cam & MMU_CAM_P) ? 1 : 0);
245
246 return p - buf;
247}
248
249#define pr_reg(name) \
250 do { \
251 ssize_t bytes; \
252 const char *str = "%20s: %08x\n"; \
253 const int maxcol = 32; \
254 bytes = snprintf(p, maxcol, str, __stringify(name), \
255 iommu_read_reg(obj, MMU_##name)); \
256 p += bytes; \
257 len -= bytes; \
258 if (len < maxcol) \
259 goto out; \
260 } while (0)
261
262static ssize_t
263omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len)
264{
265 char *p = buf;
266
267 pr_reg(REVISION);
268 pr_reg(SYSCONFIG);
269 pr_reg(SYSSTATUS);
270 pr_reg(IRQSTATUS);
271 pr_reg(IRQENABLE);
272 pr_reg(WALKING_ST);
273 pr_reg(CNTL);
274 pr_reg(FAULT_AD);
275 pr_reg(TTB);
276 pr_reg(LOCK);
277 pr_reg(LD_TLB);
278 pr_reg(CAM);
279 pr_reg(RAM);
280 pr_reg(GFLUSH);
281 pr_reg(FLUSH_ENTRY);
282 pr_reg(READ_CAM);
283 pr_reg(READ_RAM);
284 pr_reg(EMU_FAULT_AD);
285out:
286 return p - buf;
287}
288
289static void omap2_iommu_save_ctx(struct omap_iommu *obj)
290{
291 int i;
292 u32 *p = obj->ctx;
293
294 for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
295 p[i] = iommu_read_reg(obj, i * sizeof(u32));
296 dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
297 }
298
299 BUG_ON(p[0] != IOMMU_ARCH_VERSION);
300}
301
302static void omap2_iommu_restore_ctx(struct omap_iommu *obj)
303{
304 int i;
305 u32 *p = obj->ctx;
306
307 for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
308 iommu_write_reg(obj, p[i], i * sizeof(u32));
309 dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
310 }
311
312 BUG_ON(p[0] != IOMMU_ARCH_VERSION);
313}
314
315static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
316{
317 e->da = cr->cam & MMU_CAM_VATAG_MASK;
318 e->pa = cr->ram & MMU_RAM_PADDR_MASK;
319 e->valid = cr->cam & MMU_CAM_V;
320 e->pgsz = cr->cam & MMU_CAM_PGSZ_MASK;
321 e->endian = cr->ram & MMU_RAM_ENDIAN_MASK;
322 e->elsz = cr->ram & MMU_RAM_ELSZ_MASK;
323 e->mixed = cr->ram & MMU_RAM_MIXED;
324}
325
326static const struct iommu_functions omap2_iommu_ops = {
327 .version = IOMMU_ARCH_VERSION,
328
329 .enable = omap2_iommu_enable,
330 .disable = omap2_iommu_disable,
331 .set_twl = omap2_iommu_set_twl,
332 .fault_isr = omap2_iommu_fault_isr,
333
334 .tlb_read_cr = omap2_tlb_read_cr,
335 .tlb_load_cr = omap2_tlb_load_cr,
336
337 .cr_to_e = omap2_cr_to_e,
338 .cr_to_virt = omap2_cr_to_virt,
339 .alloc_cr = omap2_alloc_cr,
340 .cr_valid = omap2_cr_valid,
341 .dump_cr = omap2_dump_cr,
342
343 .get_pte_attr = omap2_get_pte_attr,
344
345 .save_ctx = omap2_iommu_save_ctx,
346 .restore_ctx = omap2_iommu_restore_ctx,
347 .dump_ctx = omap2_iommu_dump_ctx,
348};
349
350static int __init omap2_iommu_init(void)
351{
352 return omap_install_iommu_arch(&omap2_iommu_ops);
353}
354module_init(omap2_iommu_init);
355
356static void __exit omap2_iommu_exit(void)
357{
358 omap_uninstall_iommu_arch(&omap2_iommu_ops);
359}
360module_exit(omap2_iommu_exit);
361
362MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
363MODULE_DESCRIPTION("omap iommu: omap2/3 architecture specific functions");
364MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h
index 66a813977d5..cd4ae9e5b0c 100644
--- a/drivers/iommu/omap-iopgtable.h
+++ b/drivers/iommu/omap-iopgtable.h
@@ -10,9 +10,6 @@
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 */ 11 */
12 12
13#ifndef __PLAT_OMAP_IOMMU_H
14#define __PLAT_OMAP_IOMMU_H
15
16/* 13/*
17 * "L2 table" address mask and size definitions. 14 * "L2 table" address mask and size definitions.
18 */ 15 */
@@ -97,24 +94,5 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
97#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) 94#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
98#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) 95#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da))
99 96
100static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
101 u32 flags)
102{
103 memset(e, 0, sizeof(*e));
104
105 e->da = da;
106 e->pa = pa;
107 e->valid = 1;
108 /* FIXME: add OMAP1 support */
109 e->pgsz = flags & MMU_CAM_PGSZ_MASK;
110 e->endian = flags & MMU_RAM_ENDIAN_MASK;
111 e->elsz = flags & MMU_RAM_ELSZ_MASK;
112 e->mixed = flags & MMU_RAM_MIXED_MASK;
113
114 return iopgsz_to_bytes(e->pgsz);
115}
116
117#define to_iommu(dev) \ 97#define to_iommu(dev) \
118 (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev)) 98 (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
119
120#endif /* __PLAT_OMAP_IOMMU_H */
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index 9852101cf04..3e3b2421b92 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -25,6 +25,7 @@
25#include <plat/iommu.h> 25#include <plat/iommu.h>
26 26
27#include "omap-iopgtable.h" 27#include "omap-iopgtable.h"
28#include "omap-iommu.h"
28 29
29/* 30/*
30 * IOVMF_FLAGS: attribute for iommu virtual memory area(iovma) 31 * IOVMF_FLAGS: attribute for iommu virtual memory area(iovma)