diff options
Diffstat (limited to 'drivers/sh/intc/access.c')
-rw-r--r-- | drivers/sh/intc/access.c | 237 |
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 | |||
14 | unsigned 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 | |||
39 | unsigned 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 | |||
54 | unsigned 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 | |||
66 | unsigned 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 | |||
75 | static 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 | |||
81 | static 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 | |||
87 | static 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 | |||
93 | static 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 | |||
101 | static 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 | |||
109 | static 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 | |||
117 | static 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 | |||
130 | static 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 | |||
143 | static 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 | |||
156 | static 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 | |||
166 | static 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 | |||
176 | static 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 | |||
186 | unsigned 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 | |||
200 | unsigned 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 | |||
213 | unsigned 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 | |||
226 | unsigned 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 | }; | ||