root / hw / omap_gpio.c @ ff753bb9
History | View | Annotate | Download (17.9 kB)
1 | e5c6b25a | cmchao | /*
|
---|---|---|---|
2 | e5c6b25a | cmchao | * TI OMAP processors GPIO emulation.
|
3 | e5c6b25a | cmchao | *
|
4 | e5c6b25a | cmchao | * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
|
5 | e5c6b25a | cmchao | * Copyright (C) 2007-2009 Nokia Corporation
|
6 | e5c6b25a | cmchao | *
|
7 | e5c6b25a | cmchao | * This program is free software; you can redistribute it and/or
|
8 | e5c6b25a | cmchao | * modify it under the terms of the GNU General Public License as
|
9 | e5c6b25a | cmchao | * published by the Free Software Foundation; either version 2 or
|
10 | e5c6b25a | cmchao | * (at your option) version 3 of the License.
|
11 | e5c6b25a | cmchao | *
|
12 | e5c6b25a | cmchao | * This program is distributed in the hope that it will be useful,
|
13 | e5c6b25a | cmchao | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | e5c6b25a | cmchao | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 | e5c6b25a | cmchao | * GNU General Public License for more details.
|
16 | e5c6b25a | cmchao | *
|
17 | e5c6b25a | cmchao | * You should have received a copy of the GNU General Public License along
|
18 | e5c6b25a | cmchao | * with this program; if not, see <http://www.gnu.org/licenses/>.
|
19 | e5c6b25a | cmchao | */
|
20 | e5c6b25a | cmchao | |
21 | e5c6b25a | cmchao | #include "hw.h" |
22 | e5c6b25a | cmchao | #include "omap.h" |
23 | e5c6b25a | cmchao | /* General-Purpose I/O */
|
24 | e5c6b25a | cmchao | struct omap_gpio_s {
|
25 | e5c6b25a | cmchao | qemu_irq irq; |
26 | e5c6b25a | cmchao | qemu_irq *in; |
27 | e5c6b25a | cmchao | qemu_irq handler[16];
|
28 | e5c6b25a | cmchao | |
29 | e5c6b25a | cmchao | uint16_t inputs; |
30 | e5c6b25a | cmchao | uint16_t outputs; |
31 | e5c6b25a | cmchao | uint16_t dir; |
32 | e5c6b25a | cmchao | uint16_t edge; |
33 | e5c6b25a | cmchao | uint16_t mask; |
34 | e5c6b25a | cmchao | uint16_t ints; |
35 | e5c6b25a | cmchao | uint16_t pins; |
36 | e5c6b25a | cmchao | }; |
37 | e5c6b25a | cmchao | |
38 | e5c6b25a | cmchao | static void omap_gpio_set(void *opaque, int line, int level) |
39 | e5c6b25a | cmchao | { |
40 | e5c6b25a | cmchao | struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
41 | e5c6b25a | cmchao | uint16_t prev = s->inputs; |
42 | e5c6b25a | cmchao | |
43 | e5c6b25a | cmchao | if (level)
|
44 | e5c6b25a | cmchao | s->inputs |= 1 << line;
|
45 | e5c6b25a | cmchao | else
|
46 | e5c6b25a | cmchao | s->inputs &= ~(1 << line);
|
47 | e5c6b25a | cmchao | |
48 | e5c6b25a | cmchao | if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
|
49 | e5c6b25a | cmchao | (1 << line) & s->dir & ~s->mask) {
|
50 | e5c6b25a | cmchao | s->ints |= 1 << line;
|
51 | e5c6b25a | cmchao | qemu_irq_raise(s->irq); |
52 | e5c6b25a | cmchao | } |
53 | e5c6b25a | cmchao | } |
54 | e5c6b25a | cmchao | |
55 | e5c6b25a | cmchao | static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) |
56 | e5c6b25a | cmchao | { |
57 | e5c6b25a | cmchao | struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
58 | e5c6b25a | cmchao | int offset = addr & OMAP_MPUI_REG_MASK;
|
59 | e5c6b25a | cmchao | |
60 | e5c6b25a | cmchao | switch (offset) {
|
61 | e5c6b25a | cmchao | case 0x00: /* DATA_INPUT */ |
62 | e5c6b25a | cmchao | return s->inputs & s->pins;
|
63 | e5c6b25a | cmchao | |
64 | e5c6b25a | cmchao | case 0x04: /* DATA_OUTPUT */ |
65 | e5c6b25a | cmchao | return s->outputs;
|
66 | e5c6b25a | cmchao | |
67 | e5c6b25a | cmchao | case 0x08: /* DIRECTION_CONTROL */ |
68 | e5c6b25a | cmchao | return s->dir;
|
69 | e5c6b25a | cmchao | |
70 | e5c6b25a | cmchao | case 0x0c: /* INTERRUPT_CONTROL */ |
71 | e5c6b25a | cmchao | return s->edge;
|
72 | e5c6b25a | cmchao | |
73 | e5c6b25a | cmchao | case 0x10: /* INTERRUPT_MASK */ |
74 | e5c6b25a | cmchao | return s->mask;
|
75 | e5c6b25a | cmchao | |
76 | e5c6b25a | cmchao | case 0x14: /* INTERRUPT_STATUS */ |
77 | e5c6b25a | cmchao | return s->ints;
|
78 | e5c6b25a | cmchao | |
79 | e5c6b25a | cmchao | case 0x18: /* PIN_CONTROL (not in OMAP310) */ |
80 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
81 | e5c6b25a | cmchao | return s->pins;
|
82 | e5c6b25a | cmchao | } |
83 | e5c6b25a | cmchao | |
84 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
85 | e5c6b25a | cmchao | return 0; |
86 | e5c6b25a | cmchao | } |
87 | e5c6b25a | cmchao | |
88 | e5c6b25a | cmchao | static void omap_gpio_write(void *opaque, target_phys_addr_t addr, |
89 | e5c6b25a | cmchao | uint32_t value) |
90 | e5c6b25a | cmchao | { |
91 | e5c6b25a | cmchao | struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
92 | e5c6b25a | cmchao | int offset = addr & OMAP_MPUI_REG_MASK;
|
93 | e5c6b25a | cmchao | uint16_t diff; |
94 | e5c6b25a | cmchao | int ln;
|
95 | e5c6b25a | cmchao | |
96 | e5c6b25a | cmchao | switch (offset) {
|
97 | e5c6b25a | cmchao | case 0x00: /* DATA_INPUT */ |
98 | e5c6b25a | cmchao | OMAP_RO_REG(addr); |
99 | e5c6b25a | cmchao | return;
|
100 | e5c6b25a | cmchao | |
101 | e5c6b25a | cmchao | case 0x04: /* DATA_OUTPUT */ |
102 | e5c6b25a | cmchao | diff = (s->outputs ^ value) & ~s->dir; |
103 | e5c6b25a | cmchao | s->outputs = value; |
104 | e5c6b25a | cmchao | while ((ln = ffs(diff))) {
|
105 | e5c6b25a | cmchao | ln --; |
106 | e5c6b25a | cmchao | if (s->handler[ln])
|
107 | e5c6b25a | cmchao | qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
108 | e5c6b25a | cmchao | diff &= ~(1 << ln);
|
109 | e5c6b25a | cmchao | } |
110 | e5c6b25a | cmchao | break;
|
111 | e5c6b25a | cmchao | |
112 | e5c6b25a | cmchao | case 0x08: /* DIRECTION_CONTROL */ |
113 | e5c6b25a | cmchao | diff = s->outputs & (s->dir ^ value); |
114 | e5c6b25a | cmchao | s->dir = value; |
115 | e5c6b25a | cmchao | |
116 | e5c6b25a | cmchao | value = s->outputs & ~s->dir; |
117 | e5c6b25a | cmchao | while ((ln = ffs(diff))) {
|
118 | e5c6b25a | cmchao | ln --; |
119 | e5c6b25a | cmchao | if (s->handler[ln])
|
120 | e5c6b25a | cmchao | qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
121 | e5c6b25a | cmchao | diff &= ~(1 << ln);
|
122 | e5c6b25a | cmchao | } |
123 | e5c6b25a | cmchao | break;
|
124 | e5c6b25a | cmchao | |
125 | e5c6b25a | cmchao | case 0x0c: /* INTERRUPT_CONTROL */ |
126 | e5c6b25a | cmchao | s->edge = value; |
127 | e5c6b25a | cmchao | break;
|
128 | e5c6b25a | cmchao | |
129 | e5c6b25a | cmchao | case 0x10: /* INTERRUPT_MASK */ |
130 | e5c6b25a | cmchao | s->mask = value; |
131 | e5c6b25a | cmchao | break;
|
132 | e5c6b25a | cmchao | |
133 | e5c6b25a | cmchao | case 0x14: /* INTERRUPT_STATUS */ |
134 | e5c6b25a | cmchao | s->ints &= ~value; |
135 | e5c6b25a | cmchao | if (!s->ints)
|
136 | e5c6b25a | cmchao | qemu_irq_lower(s->irq); |
137 | e5c6b25a | cmchao | break;
|
138 | e5c6b25a | cmchao | |
139 | e5c6b25a | cmchao | case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ |
140 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
141 | e5c6b25a | cmchao | s->pins = value; |
142 | e5c6b25a | cmchao | break;
|
143 | e5c6b25a | cmchao | |
144 | e5c6b25a | cmchao | default:
|
145 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
146 | e5c6b25a | cmchao | return;
|
147 | e5c6b25a | cmchao | } |
148 | e5c6b25a | cmchao | } |
149 | e5c6b25a | cmchao | |
150 | e5c6b25a | cmchao | /* *Some* sources say the memory region is 32-bit. */
|
151 | e5c6b25a | cmchao | static CPUReadMemoryFunc * const omap_gpio_readfn[] = { |
152 | e5c6b25a | cmchao | omap_badwidth_read16, |
153 | e5c6b25a | cmchao | omap_gpio_read, |
154 | e5c6b25a | cmchao | omap_badwidth_read16, |
155 | e5c6b25a | cmchao | }; |
156 | e5c6b25a | cmchao | |
157 | e5c6b25a | cmchao | static CPUWriteMemoryFunc * const omap_gpio_writefn[] = { |
158 | e5c6b25a | cmchao | omap_badwidth_write16, |
159 | e5c6b25a | cmchao | omap_gpio_write, |
160 | e5c6b25a | cmchao | omap_badwidth_write16, |
161 | e5c6b25a | cmchao | }; |
162 | e5c6b25a | cmchao | |
163 | e5c6b25a | cmchao | void omap_gpio_reset(struct omap_gpio_s *s) |
164 | e5c6b25a | cmchao | { |
165 | e5c6b25a | cmchao | s->inputs = 0;
|
166 | e5c6b25a | cmchao | s->outputs = ~0;
|
167 | e5c6b25a | cmchao | s->dir = ~0;
|
168 | e5c6b25a | cmchao | s->edge = ~0;
|
169 | e5c6b25a | cmchao | s->mask = ~0;
|
170 | e5c6b25a | cmchao | s->ints = 0;
|
171 | e5c6b25a | cmchao | s->pins = ~0;
|
172 | e5c6b25a | cmchao | } |
173 | e5c6b25a | cmchao | |
174 | e5c6b25a | cmchao | struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
|
175 | e5c6b25a | cmchao | qemu_irq irq, omap_clk clk) |
176 | e5c6b25a | cmchao | { |
177 | e5c6b25a | cmchao | int iomemtype;
|
178 | e5c6b25a | cmchao | struct omap_gpio_s *s = (struct omap_gpio_s *) |
179 | e5c6b25a | cmchao | qemu_mallocz(sizeof(struct omap_gpio_s)); |
180 | e5c6b25a | cmchao | |
181 | e5c6b25a | cmchao | s->irq = irq; |
182 | e5c6b25a | cmchao | s->in = qemu_allocate_irqs(omap_gpio_set, s, 16);
|
183 | e5c6b25a | cmchao | omap_gpio_reset(s); |
184 | e5c6b25a | cmchao | |
185 | e5c6b25a | cmchao | iomemtype = cpu_register_io_memory(omap_gpio_readfn, |
186 | e5c6b25a | cmchao | omap_gpio_writefn, s); |
187 | e5c6b25a | cmchao | cpu_register_physical_memory(base, 0x1000, iomemtype);
|
188 | e5c6b25a | cmchao | |
189 | e5c6b25a | cmchao | return s;
|
190 | e5c6b25a | cmchao | } |
191 | e5c6b25a | cmchao | |
192 | e5c6b25a | cmchao | qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s)
|
193 | e5c6b25a | cmchao | { |
194 | e5c6b25a | cmchao | return s->in;
|
195 | e5c6b25a | cmchao | } |
196 | e5c6b25a | cmchao | |
197 | e5c6b25a | cmchao | void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) |
198 | e5c6b25a | cmchao | { |
199 | e5c6b25a | cmchao | if (line >= 16 || line < 0) |
200 | e5c6b25a | cmchao | hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
|
201 | e5c6b25a | cmchao | s->handler[line] = handler; |
202 | e5c6b25a | cmchao | } |
203 | d82310f7 | cmchao | |
204 | d82310f7 | cmchao | /* General-Purpose Interface of OMAP2 */
|
205 | d82310f7 | cmchao | struct omap2_gpio_s {
|
206 | d82310f7 | cmchao | qemu_irq irq[2];
|
207 | d82310f7 | cmchao | qemu_irq wkup; |
208 | d82310f7 | cmchao | qemu_irq *in; |
209 | d82310f7 | cmchao | qemu_irq handler[32];
|
210 | d82310f7 | cmchao | |
211 | d82310f7 | cmchao | uint8_t config[2];
|
212 | d82310f7 | cmchao | uint32_t inputs; |
213 | d82310f7 | cmchao | uint32_t outputs; |
214 | d82310f7 | cmchao | uint32_t dir; |
215 | d82310f7 | cmchao | uint32_t level[2];
|
216 | d82310f7 | cmchao | uint32_t edge[2];
|
217 | d82310f7 | cmchao | uint32_t mask[2];
|
218 | d82310f7 | cmchao | uint32_t wumask; |
219 | d82310f7 | cmchao | uint32_t ints[2];
|
220 | d82310f7 | cmchao | uint32_t debounce; |
221 | d82310f7 | cmchao | uint8_t delay; |
222 | d82310f7 | cmchao | }; |
223 | d82310f7 | cmchao | |
224 | d82310f7 | cmchao | static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s, |
225 | d82310f7 | cmchao | int line)
|
226 | d82310f7 | cmchao | { |
227 | d82310f7 | cmchao | qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); |
228 | d82310f7 | cmchao | } |
229 | d82310f7 | cmchao | |
230 | d82310f7 | cmchao | static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line) |
231 | d82310f7 | cmchao | { |
232 | d82310f7 | cmchao | if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ |
233 | d82310f7 | cmchao | return;
|
234 | d82310f7 | cmchao | if (!(s->config[0] & (3 << 3))) /* Force Idle */ |
235 | d82310f7 | cmchao | return;
|
236 | d82310f7 | cmchao | if (!(s->wumask & (1 << line))) |
237 | d82310f7 | cmchao | return;
|
238 | d82310f7 | cmchao | |
239 | d82310f7 | cmchao | qemu_irq_raise(s->wkup); |
240 | d82310f7 | cmchao | } |
241 | d82310f7 | cmchao | |
242 | d82310f7 | cmchao | static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s, |
243 | d82310f7 | cmchao | uint32_t diff) |
244 | d82310f7 | cmchao | { |
245 | d82310f7 | cmchao | int ln;
|
246 | d82310f7 | cmchao | |
247 | d82310f7 | cmchao | s->outputs ^= diff; |
248 | d82310f7 | cmchao | diff &= ~s->dir; |
249 | d82310f7 | cmchao | while ((ln = ffs(diff))) {
|
250 | d82310f7 | cmchao | ln --; |
251 | d82310f7 | cmchao | qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
|
252 | d82310f7 | cmchao | diff &= ~(1 << ln);
|
253 | d82310f7 | cmchao | } |
254 | d82310f7 | cmchao | } |
255 | d82310f7 | cmchao | |
256 | d82310f7 | cmchao | static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line) |
257 | d82310f7 | cmchao | { |
258 | d82310f7 | cmchao | s->ints[line] |= s->dir & |
259 | d82310f7 | cmchao | ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); |
260 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, line); |
261 | d82310f7 | cmchao | } |
262 | d82310f7 | cmchao | |
263 | d82310f7 | cmchao | static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line) |
264 | d82310f7 | cmchao | { |
265 | d82310f7 | cmchao | s->ints[0] |= 1 << line; |
266 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
267 | d82310f7 | cmchao | s->ints[1] |= 1 << line; |
268 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
269 | d82310f7 | cmchao | omap2_gpio_module_wake(s, line); |
270 | d82310f7 | cmchao | } |
271 | d82310f7 | cmchao | |
272 | d82310f7 | cmchao | static void omap2_gpio_module_set(void *opaque, int line, int level) |
273 | d82310f7 | cmchao | { |
274 | d82310f7 | cmchao | struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
275 | d82310f7 | cmchao | |
276 | d82310f7 | cmchao | if (level) {
|
277 | d82310f7 | cmchao | if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) |
278 | d82310f7 | cmchao | omap2_gpio_module_int(s, line); |
279 | d82310f7 | cmchao | s->inputs |= 1 << line;
|
280 | d82310f7 | cmchao | } else {
|
281 | d82310f7 | cmchao | if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) |
282 | d82310f7 | cmchao | omap2_gpio_module_int(s, line); |
283 | d82310f7 | cmchao | s->inputs &= ~(1 << line);
|
284 | d82310f7 | cmchao | } |
285 | d82310f7 | cmchao | } |
286 | d82310f7 | cmchao | |
287 | d82310f7 | cmchao | static void omap2_gpio_module_reset(struct omap2_gpio_s *s) |
288 | d82310f7 | cmchao | { |
289 | d82310f7 | cmchao | s->config[0] = 0; |
290 | d82310f7 | cmchao | s->config[1] = 2; |
291 | d82310f7 | cmchao | s->ints[0] = 0; |
292 | d82310f7 | cmchao | s->ints[1] = 0; |
293 | d82310f7 | cmchao | s->mask[0] = 0; |
294 | d82310f7 | cmchao | s->mask[1] = 0; |
295 | d82310f7 | cmchao | s->wumask = 0;
|
296 | d82310f7 | cmchao | s->dir = ~0;
|
297 | d82310f7 | cmchao | s->level[0] = 0; |
298 | d82310f7 | cmchao | s->level[1] = 0; |
299 | d82310f7 | cmchao | s->edge[0] = 0; |
300 | d82310f7 | cmchao | s->edge[1] = 0; |
301 | d82310f7 | cmchao | s->debounce = 0;
|
302 | d82310f7 | cmchao | s->delay = 0;
|
303 | d82310f7 | cmchao | } |
304 | d82310f7 | cmchao | |
305 | d82310f7 | cmchao | static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr) |
306 | d82310f7 | cmchao | { |
307 | d82310f7 | cmchao | struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
308 | d82310f7 | cmchao | |
309 | d82310f7 | cmchao | switch (addr) {
|
310 | d82310f7 | cmchao | case 0x00: /* GPIO_REVISION */ |
311 | d82310f7 | cmchao | return 0x18; |
312 | d82310f7 | cmchao | |
313 | d82310f7 | cmchao | case 0x10: /* GPIO_SYSCONFIG */ |
314 | d82310f7 | cmchao | return s->config[0]; |
315 | d82310f7 | cmchao | |
316 | d82310f7 | cmchao | case 0x14: /* GPIO_SYSSTATUS */ |
317 | d82310f7 | cmchao | return 0x01; |
318 | d82310f7 | cmchao | |
319 | d82310f7 | cmchao | case 0x18: /* GPIO_IRQSTATUS1 */ |
320 | d82310f7 | cmchao | return s->ints[0]; |
321 | d82310f7 | cmchao | |
322 | d82310f7 | cmchao | case 0x1c: /* GPIO_IRQENABLE1 */ |
323 | d82310f7 | cmchao | case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
324 | d82310f7 | cmchao | case 0x64: /* GPIO_SETIRQENABLE1 */ |
325 | d82310f7 | cmchao | return s->mask[0]; |
326 | d82310f7 | cmchao | |
327 | d82310f7 | cmchao | case 0x20: /* GPIO_WAKEUPENABLE */ |
328 | d82310f7 | cmchao | case 0x80: /* GPIO_CLEARWKUENA */ |
329 | d82310f7 | cmchao | case 0x84: /* GPIO_SETWKUENA */ |
330 | d82310f7 | cmchao | return s->wumask;
|
331 | d82310f7 | cmchao | |
332 | d82310f7 | cmchao | case 0x28: /* GPIO_IRQSTATUS2 */ |
333 | d82310f7 | cmchao | return s->ints[1]; |
334 | d82310f7 | cmchao | |
335 | d82310f7 | cmchao | case 0x2c: /* GPIO_IRQENABLE2 */ |
336 | d82310f7 | cmchao | case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
337 | d82310f7 | cmchao | case 0x74: /* GPIO_SETIREQNEABLE2 */ |
338 | d82310f7 | cmchao | return s->mask[1]; |
339 | d82310f7 | cmchao | |
340 | d82310f7 | cmchao | case 0x30: /* GPIO_CTRL */ |
341 | d82310f7 | cmchao | return s->config[1]; |
342 | d82310f7 | cmchao | |
343 | d82310f7 | cmchao | case 0x34: /* GPIO_OE */ |
344 | d82310f7 | cmchao | return s->dir;
|
345 | d82310f7 | cmchao | |
346 | d82310f7 | cmchao | case 0x38: /* GPIO_DATAIN */ |
347 | d82310f7 | cmchao | return s->inputs;
|
348 | d82310f7 | cmchao | |
349 | d82310f7 | cmchao | case 0x3c: /* GPIO_DATAOUT */ |
350 | d82310f7 | cmchao | case 0x90: /* GPIO_CLEARDATAOUT */ |
351 | d82310f7 | cmchao | case 0x94: /* GPIO_SETDATAOUT */ |
352 | d82310f7 | cmchao | return s->outputs;
|
353 | d82310f7 | cmchao | |
354 | d82310f7 | cmchao | case 0x40: /* GPIO_LEVELDETECT0 */ |
355 | d82310f7 | cmchao | return s->level[0]; |
356 | d82310f7 | cmchao | |
357 | d82310f7 | cmchao | case 0x44: /* GPIO_LEVELDETECT1 */ |
358 | d82310f7 | cmchao | return s->level[1]; |
359 | d82310f7 | cmchao | |
360 | d82310f7 | cmchao | case 0x48: /* GPIO_RISINGDETECT */ |
361 | d82310f7 | cmchao | return s->edge[0]; |
362 | d82310f7 | cmchao | |
363 | d82310f7 | cmchao | case 0x4c: /* GPIO_FALLINGDETECT */ |
364 | d82310f7 | cmchao | return s->edge[1]; |
365 | d82310f7 | cmchao | |
366 | d82310f7 | cmchao | case 0x50: /* GPIO_DEBOUNCENABLE */ |
367 | d82310f7 | cmchao | return s->debounce;
|
368 | d82310f7 | cmchao | |
369 | d82310f7 | cmchao | case 0x54: /* GPIO_DEBOUNCINGTIME */ |
370 | d82310f7 | cmchao | return s->delay;
|
371 | d82310f7 | cmchao | } |
372 | d82310f7 | cmchao | |
373 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
374 | d82310f7 | cmchao | return 0; |
375 | d82310f7 | cmchao | } |
376 | d82310f7 | cmchao | |
377 | d82310f7 | cmchao | static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr, |
378 | d82310f7 | cmchao | uint32_t value) |
379 | d82310f7 | cmchao | { |
380 | d82310f7 | cmchao | struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
381 | d82310f7 | cmchao | uint32_t diff; |
382 | d82310f7 | cmchao | int ln;
|
383 | d82310f7 | cmchao | |
384 | d82310f7 | cmchao | switch (addr) {
|
385 | d82310f7 | cmchao | case 0x00: /* GPIO_REVISION */ |
386 | d82310f7 | cmchao | case 0x14: /* GPIO_SYSSTATUS */ |
387 | d82310f7 | cmchao | case 0x38: /* GPIO_DATAIN */ |
388 | d82310f7 | cmchao | OMAP_RO_REG(addr); |
389 | d82310f7 | cmchao | break;
|
390 | d82310f7 | cmchao | |
391 | d82310f7 | cmchao | case 0x10: /* GPIO_SYSCONFIG */ |
392 | d82310f7 | cmchao | if (((value >> 3) & 3) == 3) |
393 | d82310f7 | cmchao | fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
|
394 | d82310f7 | cmchao | if (value & 2) |
395 | d82310f7 | cmchao | omap2_gpio_module_reset(s); |
396 | d82310f7 | cmchao | s->config[0] = value & 0x1d; |
397 | d82310f7 | cmchao | break;
|
398 | d82310f7 | cmchao | |
399 | d82310f7 | cmchao | case 0x18: /* GPIO_IRQSTATUS1 */ |
400 | d82310f7 | cmchao | if (s->ints[0] & value) { |
401 | d82310f7 | cmchao | s->ints[0] &= ~value;
|
402 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
403 | d82310f7 | cmchao | } |
404 | d82310f7 | cmchao | break;
|
405 | d82310f7 | cmchao | |
406 | d82310f7 | cmchao | case 0x1c: /* GPIO_IRQENABLE1 */ |
407 | d82310f7 | cmchao | s->mask[0] = value;
|
408 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
409 | d82310f7 | cmchao | break;
|
410 | d82310f7 | cmchao | |
411 | d82310f7 | cmchao | case 0x20: /* GPIO_WAKEUPENABLE */ |
412 | d82310f7 | cmchao | s->wumask = value; |
413 | d82310f7 | cmchao | break;
|
414 | d82310f7 | cmchao | |
415 | d82310f7 | cmchao | case 0x28: /* GPIO_IRQSTATUS2 */ |
416 | d82310f7 | cmchao | if (s->ints[1] & value) { |
417 | d82310f7 | cmchao | s->ints[1] &= ~value;
|
418 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
419 | d82310f7 | cmchao | } |
420 | d82310f7 | cmchao | break;
|
421 | d82310f7 | cmchao | |
422 | d82310f7 | cmchao | case 0x2c: /* GPIO_IRQENABLE2 */ |
423 | d82310f7 | cmchao | s->mask[1] = value;
|
424 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
425 | d82310f7 | cmchao | break;
|
426 | d82310f7 | cmchao | |
427 | d82310f7 | cmchao | case 0x30: /* GPIO_CTRL */ |
428 | d82310f7 | cmchao | s->config[1] = value & 7; |
429 | d82310f7 | cmchao | break;
|
430 | d82310f7 | cmchao | |
431 | d82310f7 | cmchao | case 0x34: /* GPIO_OE */ |
432 | d82310f7 | cmchao | diff = s->outputs & (s->dir ^ value); |
433 | d82310f7 | cmchao | s->dir = value; |
434 | d82310f7 | cmchao | |
435 | d82310f7 | cmchao | value = s->outputs & ~s->dir; |
436 | d82310f7 | cmchao | while ((ln = ffs(diff))) {
|
437 | d82310f7 | cmchao | diff &= ~(1 <<-- ln);
|
438 | d82310f7 | cmchao | qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
439 | d82310f7 | cmchao | } |
440 | d82310f7 | cmchao | |
441 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
442 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
443 | d82310f7 | cmchao | break;
|
444 | d82310f7 | cmchao | |
445 | d82310f7 | cmchao | case 0x3c: /* GPIO_DATAOUT */ |
446 | d82310f7 | cmchao | omap2_gpio_module_out_update(s, s->outputs ^ value); |
447 | d82310f7 | cmchao | break;
|
448 | d82310f7 | cmchao | |
449 | d82310f7 | cmchao | case 0x40: /* GPIO_LEVELDETECT0 */ |
450 | d82310f7 | cmchao | s->level[0] = value;
|
451 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
452 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
453 | d82310f7 | cmchao | break;
|
454 | d82310f7 | cmchao | |
455 | d82310f7 | cmchao | case 0x44: /* GPIO_LEVELDETECT1 */ |
456 | d82310f7 | cmchao | s->level[1] = value;
|
457 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
458 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
459 | d82310f7 | cmchao | break;
|
460 | d82310f7 | cmchao | |
461 | d82310f7 | cmchao | case 0x48: /* GPIO_RISINGDETECT */ |
462 | d82310f7 | cmchao | s->edge[0] = value;
|
463 | d82310f7 | cmchao | break;
|
464 | d82310f7 | cmchao | |
465 | d82310f7 | cmchao | case 0x4c: /* GPIO_FALLINGDETECT */ |
466 | d82310f7 | cmchao | s->edge[1] = value;
|
467 | d82310f7 | cmchao | break;
|
468 | d82310f7 | cmchao | |
469 | d82310f7 | cmchao | case 0x50: /* GPIO_DEBOUNCENABLE */ |
470 | d82310f7 | cmchao | s->debounce = value; |
471 | d82310f7 | cmchao | break;
|
472 | d82310f7 | cmchao | |
473 | d82310f7 | cmchao | case 0x54: /* GPIO_DEBOUNCINGTIME */ |
474 | d82310f7 | cmchao | s->delay = value; |
475 | d82310f7 | cmchao | break;
|
476 | d82310f7 | cmchao | |
477 | d82310f7 | cmchao | case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
478 | d82310f7 | cmchao | s->mask[0] &= ~value;
|
479 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
480 | d82310f7 | cmchao | break;
|
481 | d82310f7 | cmchao | |
482 | d82310f7 | cmchao | case 0x64: /* GPIO_SETIRQENABLE1 */ |
483 | d82310f7 | cmchao | s->mask[0] |= value;
|
484 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
485 | d82310f7 | cmchao | break;
|
486 | d82310f7 | cmchao | |
487 | d82310f7 | cmchao | case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
488 | d82310f7 | cmchao | s->mask[1] &= ~value;
|
489 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
490 | d82310f7 | cmchao | break;
|
491 | d82310f7 | cmchao | |
492 | d82310f7 | cmchao | case 0x74: /* GPIO_SETIREQNEABLE2 */ |
493 | d82310f7 | cmchao | s->mask[1] |= value;
|
494 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
495 | d82310f7 | cmchao | break;
|
496 | d82310f7 | cmchao | |
497 | d82310f7 | cmchao | case 0x80: /* GPIO_CLEARWKUENA */ |
498 | d82310f7 | cmchao | s->wumask &= ~value; |
499 | d82310f7 | cmchao | break;
|
500 | d82310f7 | cmchao | |
501 | d82310f7 | cmchao | case 0x84: /* GPIO_SETWKUENA */ |
502 | d82310f7 | cmchao | s->wumask |= value; |
503 | d82310f7 | cmchao | break;
|
504 | d82310f7 | cmchao | |
505 | d82310f7 | cmchao | case 0x90: /* GPIO_CLEARDATAOUT */ |
506 | d82310f7 | cmchao | omap2_gpio_module_out_update(s, s->outputs & value); |
507 | d82310f7 | cmchao | break;
|
508 | d82310f7 | cmchao | |
509 | d82310f7 | cmchao | case 0x94: /* GPIO_SETDATAOUT */ |
510 | d82310f7 | cmchao | omap2_gpio_module_out_update(s, ~s->outputs & value); |
511 | d82310f7 | cmchao | break;
|
512 | d82310f7 | cmchao | |
513 | d82310f7 | cmchao | default:
|
514 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
515 | d82310f7 | cmchao | return;
|
516 | d82310f7 | cmchao | } |
517 | d82310f7 | cmchao | } |
518 | d82310f7 | cmchao | |
519 | d82310f7 | cmchao | static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr) |
520 | d82310f7 | cmchao | { |
521 | d82310f7 | cmchao | return omap2_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3); |
522 | d82310f7 | cmchao | } |
523 | d82310f7 | cmchao | |
524 | d82310f7 | cmchao | static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr, |
525 | d82310f7 | cmchao | uint32_t value) |
526 | d82310f7 | cmchao | { |
527 | d82310f7 | cmchao | uint32_t cur = 0;
|
528 | d82310f7 | cmchao | uint32_t mask = 0xffff;
|
529 | d82310f7 | cmchao | |
530 | d82310f7 | cmchao | switch (addr & ~3) { |
531 | d82310f7 | cmchao | case 0x00: /* GPIO_REVISION */ |
532 | d82310f7 | cmchao | case 0x14: /* GPIO_SYSSTATUS */ |
533 | d82310f7 | cmchao | case 0x38: /* GPIO_DATAIN */ |
534 | d82310f7 | cmchao | OMAP_RO_REG(addr); |
535 | d82310f7 | cmchao | break;
|
536 | d82310f7 | cmchao | |
537 | d82310f7 | cmchao | case 0x10: /* GPIO_SYSCONFIG */ |
538 | d82310f7 | cmchao | case 0x1c: /* GPIO_IRQENABLE1 */ |
539 | d82310f7 | cmchao | case 0x20: /* GPIO_WAKEUPENABLE */ |
540 | d82310f7 | cmchao | case 0x2c: /* GPIO_IRQENABLE2 */ |
541 | d82310f7 | cmchao | case 0x30: /* GPIO_CTRL */ |
542 | d82310f7 | cmchao | case 0x34: /* GPIO_OE */ |
543 | d82310f7 | cmchao | case 0x3c: /* GPIO_DATAOUT */ |
544 | d82310f7 | cmchao | case 0x40: /* GPIO_LEVELDETECT0 */ |
545 | d82310f7 | cmchao | case 0x44: /* GPIO_LEVELDETECT1 */ |
546 | d82310f7 | cmchao | case 0x48: /* GPIO_RISINGDETECT */ |
547 | d82310f7 | cmchao | case 0x4c: /* GPIO_FALLINGDETECT */ |
548 | d82310f7 | cmchao | case 0x50: /* GPIO_DEBOUNCENABLE */ |
549 | d82310f7 | cmchao | case 0x54: /* GPIO_DEBOUNCINGTIME */ |
550 | d82310f7 | cmchao | cur = omap2_gpio_module_read(opaque, addr & ~3) &
|
551 | d82310f7 | cmchao | ~(mask << ((addr & 3) << 3)); |
552 | d82310f7 | cmchao | |
553 | d82310f7 | cmchao | /* Fall through. */
|
554 | d82310f7 | cmchao | case 0x18: /* GPIO_IRQSTATUS1 */ |
555 | d82310f7 | cmchao | case 0x28: /* GPIO_IRQSTATUS2 */ |
556 | d82310f7 | cmchao | case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
557 | d82310f7 | cmchao | case 0x64: /* GPIO_SETIRQENABLE1 */ |
558 | d82310f7 | cmchao | case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
559 | d82310f7 | cmchao | case 0x74: /* GPIO_SETIREQNEABLE2 */ |
560 | d82310f7 | cmchao | case 0x80: /* GPIO_CLEARWKUENA */ |
561 | d82310f7 | cmchao | case 0x84: /* GPIO_SETWKUENA */ |
562 | d82310f7 | cmchao | case 0x90: /* GPIO_CLEARDATAOUT */ |
563 | d82310f7 | cmchao | case 0x94: /* GPIO_SETDATAOUT */ |
564 | d82310f7 | cmchao | value <<= (addr & 3) << 3; |
565 | d82310f7 | cmchao | omap2_gpio_module_write(opaque, addr, cur | value); |
566 | d82310f7 | cmchao | break;
|
567 | d82310f7 | cmchao | |
568 | d82310f7 | cmchao | default:
|
569 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
570 | d82310f7 | cmchao | return;
|
571 | d82310f7 | cmchao | } |
572 | d82310f7 | cmchao | } |
573 | d82310f7 | cmchao | |
574 | d82310f7 | cmchao | static CPUReadMemoryFunc * const omap2_gpio_module_readfn[] = { |
575 | d82310f7 | cmchao | omap2_gpio_module_readp, |
576 | d82310f7 | cmchao | omap2_gpio_module_readp, |
577 | d82310f7 | cmchao | omap2_gpio_module_read, |
578 | d82310f7 | cmchao | }; |
579 | d82310f7 | cmchao | |
580 | d82310f7 | cmchao | static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = { |
581 | d82310f7 | cmchao | omap2_gpio_module_writep, |
582 | d82310f7 | cmchao | omap2_gpio_module_writep, |
583 | d82310f7 | cmchao | omap2_gpio_module_write, |
584 | d82310f7 | cmchao | }; |
585 | d82310f7 | cmchao | |
586 | d82310f7 | cmchao | static void omap2_gpio_module_init(struct omap2_gpio_s *s, |
587 | d82310f7 | cmchao | struct omap_target_agent_s *ta, int region, |
588 | d82310f7 | cmchao | qemu_irq mpu, qemu_irq dsp, qemu_irq wkup, |
589 | d82310f7 | cmchao | omap_clk fclk, omap_clk iclk) |
590 | d82310f7 | cmchao | { |
591 | d82310f7 | cmchao | int iomemtype;
|
592 | d82310f7 | cmchao | |
593 | d82310f7 | cmchao | s->irq[0] = mpu;
|
594 | d82310f7 | cmchao | s->irq[1] = dsp;
|
595 | d82310f7 | cmchao | s->wkup = wkup; |
596 | d82310f7 | cmchao | s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32);
|
597 | d82310f7 | cmchao | |
598 | d82310f7 | cmchao | iomemtype = l4_register_io_memory(omap2_gpio_module_readfn, |
599 | d82310f7 | cmchao | omap2_gpio_module_writefn, s); |
600 | d82310f7 | cmchao | omap_l4_attach(ta, region, iomemtype); |
601 | d82310f7 | cmchao | } |
602 | d82310f7 | cmchao | |
603 | d82310f7 | cmchao | struct omap_gpif_s {
|
604 | d82310f7 | cmchao | struct omap2_gpio_s module[5]; |
605 | d82310f7 | cmchao | int modules;
|
606 | d82310f7 | cmchao | |
607 | d82310f7 | cmchao | int autoidle;
|
608 | d82310f7 | cmchao | int gpo;
|
609 | d82310f7 | cmchao | }; |
610 | d82310f7 | cmchao | |
611 | d82310f7 | cmchao | void omap_gpif_reset(struct omap_gpif_s *s) |
612 | d82310f7 | cmchao | { |
613 | d82310f7 | cmchao | int i;
|
614 | d82310f7 | cmchao | |
615 | d82310f7 | cmchao | for (i = 0; i < s->modules; i ++) |
616 | d82310f7 | cmchao | omap2_gpio_module_reset(s->module + i); |
617 | d82310f7 | cmchao | |
618 | d82310f7 | cmchao | s->autoidle = 0;
|
619 | d82310f7 | cmchao | s->gpo = 0;
|
620 | d82310f7 | cmchao | } |
621 | d82310f7 | cmchao | |
622 | d82310f7 | cmchao | static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr) |
623 | d82310f7 | cmchao | { |
624 | d82310f7 | cmchao | struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; |
625 | d82310f7 | cmchao | |
626 | d82310f7 | cmchao | switch (addr) {
|
627 | d82310f7 | cmchao | case 0x00: /* IPGENERICOCPSPL_REVISION */ |
628 | d82310f7 | cmchao | return 0x18; |
629 | d82310f7 | cmchao | |
630 | d82310f7 | cmchao | case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ |
631 | d82310f7 | cmchao | return s->autoidle;
|
632 | d82310f7 | cmchao | |
633 | d82310f7 | cmchao | case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ |
634 | d82310f7 | cmchao | return 0x01; |
635 | d82310f7 | cmchao | |
636 | d82310f7 | cmchao | case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ |
637 | d82310f7 | cmchao | return 0x00; |
638 | d82310f7 | cmchao | |
639 | d82310f7 | cmchao | case 0x40: /* IPGENERICOCPSPL_GPO */ |
640 | d82310f7 | cmchao | return s->gpo;
|
641 | d82310f7 | cmchao | |
642 | d82310f7 | cmchao | case 0x50: /* IPGENERICOCPSPL_GPI */ |
643 | d82310f7 | cmchao | return 0x00; |
644 | d82310f7 | cmchao | } |
645 | d82310f7 | cmchao | |
646 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
647 | d82310f7 | cmchao | return 0; |
648 | d82310f7 | cmchao | } |
649 | d82310f7 | cmchao | |
650 | d82310f7 | cmchao | static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr, |
651 | d82310f7 | cmchao | uint32_t value) |
652 | d82310f7 | cmchao | { |
653 | d82310f7 | cmchao | struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; |
654 | d82310f7 | cmchao | |
655 | d82310f7 | cmchao | switch (addr) {
|
656 | d82310f7 | cmchao | case 0x00: /* IPGENERICOCPSPL_REVISION */ |
657 | d82310f7 | cmchao | case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ |
658 | d82310f7 | cmchao | case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ |
659 | d82310f7 | cmchao | case 0x50: /* IPGENERICOCPSPL_GPI */ |
660 | d82310f7 | cmchao | OMAP_RO_REG(addr); |
661 | d82310f7 | cmchao | break;
|
662 | d82310f7 | cmchao | |
663 | d82310f7 | cmchao | case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ |
664 | d82310f7 | cmchao | if (value & (1 << 1)) /* SOFTRESET */ |
665 | d82310f7 | cmchao | omap_gpif_reset(s); |
666 | d82310f7 | cmchao | s->autoidle = value & 1;
|
667 | d82310f7 | cmchao | break;
|
668 | d82310f7 | cmchao | |
669 | d82310f7 | cmchao | case 0x40: /* IPGENERICOCPSPL_GPO */ |
670 | d82310f7 | cmchao | s->gpo = value & 1;
|
671 | d82310f7 | cmchao | break;
|
672 | d82310f7 | cmchao | |
673 | d82310f7 | cmchao | default:
|
674 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
675 | d82310f7 | cmchao | return;
|
676 | d82310f7 | cmchao | } |
677 | d82310f7 | cmchao | } |
678 | d82310f7 | cmchao | |
679 | d82310f7 | cmchao | static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = { |
680 | d82310f7 | cmchao | omap_gpif_top_read, |
681 | d82310f7 | cmchao | omap_gpif_top_read, |
682 | d82310f7 | cmchao | omap_gpif_top_read, |
683 | d82310f7 | cmchao | }; |
684 | d82310f7 | cmchao | |
685 | d82310f7 | cmchao | static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = { |
686 | d82310f7 | cmchao | omap_gpif_top_write, |
687 | d82310f7 | cmchao | omap_gpif_top_write, |
688 | d82310f7 | cmchao | omap_gpif_top_write, |
689 | d82310f7 | cmchao | }; |
690 | d82310f7 | cmchao | |
691 | d82310f7 | cmchao | struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, |
692 | d82310f7 | cmchao | qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
|
693 | d82310f7 | cmchao | { |
694 | d82310f7 | cmchao | int iomemtype, i;
|
695 | d82310f7 | cmchao | struct omap_gpif_s *s = (struct omap_gpif_s *) |
696 | d82310f7 | cmchao | qemu_mallocz(sizeof(struct omap_gpif_s)); |
697 | d82310f7 | cmchao | int region[4] = { 0, 2, 4, 5 }; |
698 | d82310f7 | cmchao | |
699 | d82310f7 | cmchao | s->modules = modules; |
700 | d82310f7 | cmchao | for (i = 0; i < modules; i ++) |
701 | d82310f7 | cmchao | omap2_gpio_module_init(s->module + i, ta, region[i], |
702 | d82310f7 | cmchao | irq[i], NULL, NULL, fclk[i], iclk); |
703 | d82310f7 | cmchao | |
704 | d82310f7 | cmchao | omap_gpif_reset(s); |
705 | d82310f7 | cmchao | |
706 | d82310f7 | cmchao | iomemtype = l4_register_io_memory(omap_gpif_top_readfn, |
707 | d82310f7 | cmchao | omap_gpif_top_writefn, s); |
708 | d82310f7 | cmchao | omap_l4_attach(ta, 1, iomemtype);
|
709 | d82310f7 | cmchao | |
710 | d82310f7 | cmchao | return s;
|
711 | d82310f7 | cmchao | } |
712 | d82310f7 | cmchao | |
713 | d82310f7 | cmchao | qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start) |
714 | d82310f7 | cmchao | { |
715 | d82310f7 | cmchao | if (start >= s->modules * 32 || start < 0) |
716 | d82310f7 | cmchao | hw_error("%s: No GPIO line %i\n", __FUNCTION__, start);
|
717 | d82310f7 | cmchao | return s->module[start >> 5].in + (start & 31); |
718 | d82310f7 | cmchao | } |
719 | d82310f7 | cmchao | |
720 | d82310f7 | cmchao | void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler) |
721 | d82310f7 | cmchao | { |
722 | d82310f7 | cmchao | if (line >= s->modules * 32 || line < 0) |
723 | d82310f7 | cmchao | hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
|
724 | d82310f7 | cmchao | s->module[line >> 5].handler[line & 31] = handler; |
725 | d82310f7 | cmchao | } |