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