aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/intc/access.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-10-05 09:10:30 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-05 09:10:30 -0400
commit2be6bb0c79c7fbda3425b65ee51c558bbaf4cf91 (patch)
treedb0dafd7e7f83945edc2c50c358a3d81fca960c3 /drivers/sh/intc/access.c
parentd74310d3b18aabbb7d0549ea9e3fd3259c1dce00 (diff)
sh: intc: Split up the INTC code.
This splits up the sh intc core in to something more vaguely resembling a subsystem. Most of the functionality was alread fairly well compartmentalized, and there were only a handful of interdependencies that needed to be resolved in the process. This also serves as future-proofing for the genirq and sparseirq rework, which will make some of the split out functionality wholly generic, allowing things to be killed off in place with minimal migration pain. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh/intc/access.c')
-rw-r--r--drivers/sh/intc/access.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/drivers/sh/intc/access.c b/drivers/sh/intc/access.c
new file mode 100644
index 000000000000..f892ae1d212a
--- /dev/null
+++ b/drivers/sh/intc/access.c
@@ -0,0 +1,237 @@
1/*
2 * Common INTC2 register accessors
3 *
4 * Copyright (C) 2007, 2008 Magnus Damm
5 * Copyright (C) 2009, 2010 Paul Mundt
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11#include <linux/io.h>
12#include "internals.h"
13
14unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
15{
16 struct intc_window *window;
17 int k;
18
19 /* scan through physical windows and convert address */
20 for (k = 0; k < d->nr_windows; k++) {
21 window = d->window + k;
22
23 if (address < window->phys)
24 continue;
25
26 if (address >= (window->phys + window->size))
27 continue;
28
29 address -= window->phys;
30 address += (unsigned long)window->virt;
31
32 return address;
33 }
34
35 /* no windows defined, register must be 1:1 mapped virt:phys */
36 return address;
37}
38
39unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
40{
41 unsigned int k;
42
43 address = intc_phys_to_virt(d, address);
44
45 for (k = 0; k < d->nr_reg; k++) {
46 if (d->reg[k] == address)
47 return k;
48 }
49
50 BUG();
51 return 0;
52}
53
54unsigned int intc_set_field_from_handle(unsigned int value,
55 unsigned int field_value,
56 unsigned int handle)
57{
58 unsigned int width = _INTC_WIDTH(handle);
59 unsigned int shift = _INTC_SHIFT(handle);
60
61 value &= ~(((1 << width) - 1) << shift);
62 value |= field_value << shift;
63 return value;
64}
65
66unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
67{
68 unsigned int width = _INTC_WIDTH(handle);
69 unsigned int shift = _INTC_SHIFT(handle);
70 unsigned int mask = ((1 << width) - 1) << shift;
71
72 return (value & mask) >> shift;
73}
74
75static unsigned long test_8(unsigned long addr, unsigned long h,
76 unsigned long ignore)
77{
78 return intc_get_field_from_handle(__raw_readb(addr), h);
79}
80
81static unsigned long test_16(unsigned long addr, unsigned long h,
82 unsigned long ignore)
83{
84 return intc_get_field_from_handle(__raw_readw(addr), h);
85}
86
87static unsigned long test_32(unsigned long addr, unsigned long h,
88 unsigned long ignore)
89{
90 return intc_get_field_from_handle(__raw_readl(addr), h);
91}
92
93static unsigned long write_8(unsigned long addr, unsigned long h,
94 unsigned long data)
95{
96 __raw_writeb(intc_set_field_from_handle(0, data, h), addr);
97 (void)__raw_readb(addr); /* Defeat write posting */
98 return 0;
99}
100
101static unsigned long write_16(unsigned long addr, unsigned long h,
102 unsigned long data)
103{
104 __raw_writew(intc_set_field_from_handle(0, data, h), addr);
105 (void)__raw_readw(addr); /* Defeat write posting */
106 return 0;
107}
108
109static unsigned long write_32(unsigned long addr, unsigned long h,
110 unsigned long data)
111{
112 __raw_writel(intc_set_field_from_handle(0, data, h), addr);
113 (void)__raw_readl(addr); /* Defeat write posting */
114 return 0;
115}
116
117static unsigned long modify_8(unsigned long addr, unsigned long h,
118 unsigned long data)
119{
120 unsigned long flags;
121 unsigned int value;
122 local_irq_save(flags);
123 value = intc_set_field_from_handle(__raw_readb(addr), data, h);
124 __raw_writeb(value, addr);
125 (void)__raw_readb(addr); /* Defeat write posting */
126 local_irq_restore(flags);
127 return 0;
128}
129
130static unsigned long modify_16(unsigned long addr, unsigned long h,
131 unsigned long data)
132{
133 unsigned long flags;
134 unsigned int value;
135 local_irq_save(flags);
136 value = intc_set_field_from_handle(__raw_readw(addr), data, h);
137 __raw_writew(value, addr);
138 (void)__raw_readw(addr); /* Defeat write posting */
139 local_irq_restore(flags);
140 return 0;
141}
142
143static unsigned long modify_32(unsigned long addr, unsigned long h,
144 unsigned long data)
145{
146 unsigned long flags;
147 unsigned int value;
148 local_irq_save(flags);
149 value = intc_set_field_from_handle(__raw_readl(addr), data, h);
150 __raw_writel(value, addr);
151 (void)__raw_readl(addr); /* Defeat write posting */
152 local_irq_restore(flags);
153 return 0;
154}
155
156static unsigned long intc_mode_field(unsigned long addr,
157 unsigned long handle,
158 unsigned long (*fn)(unsigned long,
159 unsigned long,
160 unsigned long),
161 unsigned int irq)
162{
163 return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
164}
165
166static unsigned long intc_mode_zero(unsigned long addr,
167 unsigned long handle,
168 unsigned long (*fn)(unsigned long,
169 unsigned long,
170 unsigned long),
171 unsigned int irq)
172{
173 return fn(addr, handle, 0);
174}
175
176static unsigned long intc_mode_prio(unsigned long addr,
177 unsigned long handle,
178 unsigned long (*fn)(unsigned long,
179 unsigned long,
180 unsigned long),
181 unsigned int irq)
182{
183 return fn(addr, handle, intc_get_prio_level(irq));
184}
185
186unsigned long (*intc_reg_fns[])(unsigned long addr,
187 unsigned long h,
188 unsigned long data) = {
189 [REG_FN_TEST_BASE + 0] = test_8,
190 [REG_FN_TEST_BASE + 1] = test_16,
191 [REG_FN_TEST_BASE + 3] = test_32,
192 [REG_FN_WRITE_BASE + 0] = write_8,
193 [REG_FN_WRITE_BASE + 1] = write_16,
194 [REG_FN_WRITE_BASE + 3] = write_32,
195 [REG_FN_MODIFY_BASE + 0] = modify_8,
196 [REG_FN_MODIFY_BASE + 1] = modify_16,
197 [REG_FN_MODIFY_BASE + 3] = modify_32,
198};
199
200unsigned long (*intc_enable_fns[])(unsigned long addr,
201 unsigned long handle,
202 unsigned long (*fn)(unsigned long,
203 unsigned long,
204 unsigned long),
205 unsigned int irq) = {
206 [MODE_ENABLE_REG] = intc_mode_field,
207 [MODE_MASK_REG] = intc_mode_zero,
208 [MODE_DUAL_REG] = intc_mode_field,
209 [MODE_PRIO_REG] = intc_mode_prio,
210 [MODE_PCLR_REG] = intc_mode_prio,
211};
212
213unsigned long (*intc_disable_fns[])(unsigned long addr,
214 unsigned long handle,
215 unsigned long (*fn)(unsigned long,
216 unsigned long,
217 unsigned long),
218 unsigned int irq) = {
219 [MODE_ENABLE_REG] = intc_mode_zero,
220 [MODE_MASK_REG] = intc_mode_field,
221 [MODE_DUAL_REG] = intc_mode_field,
222 [MODE_PRIO_REG] = intc_mode_zero,
223 [MODE_PCLR_REG] = intc_mode_field,
224};
225
226unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
227 unsigned long handle,
228 unsigned long (*fn)(unsigned long,
229 unsigned long,
230 unsigned long),
231 unsigned int irq) = {
232 [MODE_ENABLE_REG] = intc_mode_field,
233 [MODE_MASK_REG] = intc_mode_zero,
234 [MODE_DUAL_REG] = intc_mode_field,
235 [MODE_PRIO_REG] = intc_mode_field,
236 [MODE_PCLR_REG] = intc_mode_field,
237};