root / hw / omap_gpio.c @ 0cdd3d14
History | View | Annotate | Download (20.7 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 |
#include "sysbus.h" |
24 |
|
25 |
struct omap_gpio_s {
|
26 |
qemu_irq irq; |
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 |
struct omap_gpif_s {
|
39 |
SysBusDevice busdev; |
40 |
MemoryRegion iomem; |
41 |
int mpu_model;
|
42 |
void *clk;
|
43 |
struct omap_gpio_s omap1;
|
44 |
}; |
45 |
|
46 |
/* General-Purpose I/O of OMAP1 */
|
47 |
static void omap_gpio_set(void *opaque, int line, int level) |
48 |
{ |
49 |
struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1; |
50 |
uint16_t prev = s->inputs; |
51 |
|
52 |
if (level)
|
53 |
s->inputs |= 1 << line;
|
54 |
else
|
55 |
s->inputs &= ~(1 << line);
|
56 |
|
57 |
if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
|
58 |
(1 << line) & s->dir & ~s->mask) {
|
59 |
s->ints |= 1 << line;
|
60 |
qemu_irq_raise(s->irq); |
61 |
} |
62 |
} |
63 |
|
64 |
static uint64_t omap_gpio_read(void *opaque, target_phys_addr_t addr, |
65 |
unsigned size)
|
66 |
{ |
67 |
struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
68 |
int offset = addr & OMAP_MPUI_REG_MASK;
|
69 |
|
70 |
if (size != 2) { |
71 |
return omap_badwidth_read16(opaque, addr);
|
72 |
} |
73 |
|
74 |
switch (offset) {
|
75 |
case 0x00: /* DATA_INPUT */ |
76 |
return s->inputs & s->pins;
|
77 |
|
78 |
case 0x04: /* DATA_OUTPUT */ |
79 |
return s->outputs;
|
80 |
|
81 |
case 0x08: /* DIRECTION_CONTROL */ |
82 |
return s->dir;
|
83 |
|
84 |
case 0x0c: /* INTERRUPT_CONTROL */ |
85 |
return s->edge;
|
86 |
|
87 |
case 0x10: /* INTERRUPT_MASK */ |
88 |
return s->mask;
|
89 |
|
90 |
case 0x14: /* INTERRUPT_STATUS */ |
91 |
return s->ints;
|
92 |
|
93 |
case 0x18: /* PIN_CONTROL (not in OMAP310) */ |
94 |
OMAP_BAD_REG(addr); |
95 |
return s->pins;
|
96 |
} |
97 |
|
98 |
OMAP_BAD_REG(addr); |
99 |
return 0; |
100 |
} |
101 |
|
102 |
static void omap_gpio_write(void *opaque, target_phys_addr_t addr, |
103 |
uint64_t value, unsigned size)
|
104 |
{ |
105 |
struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
106 |
int offset = addr & OMAP_MPUI_REG_MASK;
|
107 |
uint16_t diff; |
108 |
int ln;
|
109 |
|
110 |
if (size != 2) { |
111 |
return omap_badwidth_write16(opaque, addr, value);
|
112 |
} |
113 |
|
114 |
switch (offset) {
|
115 |
case 0x00: /* DATA_INPUT */ |
116 |
OMAP_RO_REG(addr); |
117 |
return;
|
118 |
|
119 |
case 0x04: /* DATA_OUTPUT */ |
120 |
diff = (s->outputs ^ value) & ~s->dir; |
121 |
s->outputs = value; |
122 |
while ((ln = ffs(diff))) {
|
123 |
ln --; |
124 |
if (s->handler[ln])
|
125 |
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
126 |
diff &= ~(1 << ln);
|
127 |
} |
128 |
break;
|
129 |
|
130 |
case 0x08: /* DIRECTION_CONTROL */ |
131 |
diff = s->outputs & (s->dir ^ value); |
132 |
s->dir = value; |
133 |
|
134 |
value = s->outputs & ~s->dir; |
135 |
while ((ln = ffs(diff))) {
|
136 |
ln --; |
137 |
if (s->handler[ln])
|
138 |
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
139 |
diff &= ~(1 << ln);
|
140 |
} |
141 |
break;
|
142 |
|
143 |
case 0x0c: /* INTERRUPT_CONTROL */ |
144 |
s->edge = value; |
145 |
break;
|
146 |
|
147 |
case 0x10: /* INTERRUPT_MASK */ |
148 |
s->mask = value; |
149 |
break;
|
150 |
|
151 |
case 0x14: /* INTERRUPT_STATUS */ |
152 |
s->ints &= ~value; |
153 |
if (!s->ints)
|
154 |
qemu_irq_lower(s->irq); |
155 |
break;
|
156 |
|
157 |
case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ |
158 |
OMAP_BAD_REG(addr); |
159 |
s->pins = value; |
160 |
break;
|
161 |
|
162 |
default:
|
163 |
OMAP_BAD_REG(addr); |
164 |
return;
|
165 |
} |
166 |
} |
167 |
|
168 |
/* *Some* sources say the memory region is 32-bit. */
|
169 |
static const MemoryRegionOps omap_gpio_ops = { |
170 |
.read = omap_gpio_read, |
171 |
.write = omap_gpio_write, |
172 |
.endianness = DEVICE_NATIVE_ENDIAN, |
173 |
}; |
174 |
|
175 |
static void omap_gpio_reset(struct omap_gpio_s *s) |
176 |
{ |
177 |
s->inputs = 0;
|
178 |
s->outputs = ~0;
|
179 |
s->dir = ~0;
|
180 |
s->edge = ~0;
|
181 |
s->mask = ~0;
|
182 |
s->ints = 0;
|
183 |
s->pins = ~0;
|
184 |
} |
185 |
|
186 |
struct omap2_gpio_s {
|
187 |
qemu_irq irq[2];
|
188 |
qemu_irq wkup; |
189 |
qemu_irq *handler; |
190 |
MemoryRegion iomem; |
191 |
|
192 |
uint8_t revision; |
193 |
uint8_t config[2];
|
194 |
uint32_t inputs; |
195 |
uint32_t outputs; |
196 |
uint32_t dir; |
197 |
uint32_t level[2];
|
198 |
uint32_t edge[2];
|
199 |
uint32_t mask[2];
|
200 |
uint32_t wumask; |
201 |
uint32_t ints[2];
|
202 |
uint32_t debounce; |
203 |
uint8_t delay; |
204 |
}; |
205 |
|
206 |
struct omap2_gpif_s {
|
207 |
SysBusDevice busdev; |
208 |
MemoryRegion iomem; |
209 |
int mpu_model;
|
210 |
void *iclk;
|
211 |
void *fclk[6]; |
212 |
int modulecount;
|
213 |
struct omap2_gpio_s *modules;
|
214 |
qemu_irq *handler; |
215 |
int autoidle;
|
216 |
int gpo;
|
217 |
}; |
218 |
|
219 |
/* General-Purpose Interface of OMAP2/3 */
|
220 |
static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s, |
221 |
int line)
|
222 |
{ |
223 |
qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); |
224 |
} |
225 |
|
226 |
static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line) |
227 |
{ |
228 |
if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ |
229 |
return;
|
230 |
if (!(s->config[0] & (3 << 3))) /* Force Idle */ |
231 |
return;
|
232 |
if (!(s->wumask & (1 << line))) |
233 |
return;
|
234 |
|
235 |
qemu_irq_raise(s->wkup); |
236 |
} |
237 |
|
238 |
static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s, |
239 |
uint32_t diff) |
240 |
{ |
241 |
int ln;
|
242 |
|
243 |
s->outputs ^= diff; |
244 |
diff &= ~s->dir; |
245 |
while ((ln = ffs(diff))) {
|
246 |
ln --; |
247 |
qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
|
248 |
diff &= ~(1 << ln);
|
249 |
} |
250 |
} |
251 |
|
252 |
static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line) |
253 |
{ |
254 |
s->ints[line] |= s->dir & |
255 |
((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); |
256 |
omap2_gpio_module_int_update(s, line); |
257 |
} |
258 |
|
259 |
static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line) |
260 |
{ |
261 |
s->ints[0] |= 1 << line; |
262 |
omap2_gpio_module_int_update(s, 0);
|
263 |
s->ints[1] |= 1 << line; |
264 |
omap2_gpio_module_int_update(s, 1);
|
265 |
omap2_gpio_module_wake(s, line); |
266 |
} |
267 |
|
268 |
static void omap2_gpio_set(void *opaque, int line, int level) |
269 |
{ |
270 |
struct omap2_gpif_s *p = opaque;
|
271 |
struct omap2_gpio_s *s = &p->modules[line >> 5]; |
272 |
|
273 |
line &= 31;
|
274 |
if (level) {
|
275 |
if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) |
276 |
omap2_gpio_module_int(s, line); |
277 |
s->inputs |= 1 << line;
|
278 |
} else {
|
279 |
if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) |
280 |
omap2_gpio_module_int(s, line); |
281 |
s->inputs &= ~(1 << line);
|
282 |
} |
283 |
} |
284 |
|
285 |
static void omap2_gpio_module_reset(struct omap2_gpio_s *s) |
286 |
{ |
287 |
s->config[0] = 0; |
288 |
s->config[1] = 2; |
289 |
s->ints[0] = 0; |
290 |
s->ints[1] = 0; |
291 |
s->mask[0] = 0; |
292 |
s->mask[1] = 0; |
293 |
s->wumask = 0;
|
294 |
s->dir = ~0;
|
295 |
s->level[0] = 0; |
296 |
s->level[1] = 0; |
297 |
s->edge[0] = 0; |
298 |
s->edge[1] = 0; |
299 |
s->debounce = 0;
|
300 |
s->delay = 0;
|
301 |
} |
302 |
|
303 |
static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr) |
304 |
{ |
305 |
struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
306 |
|
307 |
switch (addr) {
|
308 |
case 0x00: /* GPIO_REVISION */ |
309 |
return s->revision;
|
310 |
|
311 |
case 0x10: /* GPIO_SYSCONFIG */ |
312 |
return s->config[0]; |
313 |
|
314 |
case 0x14: /* GPIO_SYSSTATUS */ |
315 |
return 0x01; |
316 |
|
317 |
case 0x18: /* GPIO_IRQSTATUS1 */ |
318 |
return s->ints[0]; |
319 |
|
320 |
case 0x1c: /* GPIO_IRQENABLE1 */ |
321 |
case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
322 |
case 0x64: /* GPIO_SETIRQENABLE1 */ |
323 |
return s->mask[0]; |
324 |
|
325 |
case 0x20: /* GPIO_WAKEUPENABLE */ |
326 |
case 0x80: /* GPIO_CLEARWKUENA */ |
327 |
case 0x84: /* GPIO_SETWKUENA */ |
328 |
return s->wumask;
|
329 |
|
330 |
case 0x28: /* GPIO_IRQSTATUS2 */ |
331 |
return s->ints[1]; |
332 |
|
333 |
case 0x2c: /* GPIO_IRQENABLE2 */ |
334 |
case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
335 |
case 0x74: /* GPIO_SETIREQNEABLE2 */ |
336 |
return s->mask[1]; |
337 |
|
338 |
case 0x30: /* GPIO_CTRL */ |
339 |
return s->config[1]; |
340 |
|
341 |
case 0x34: /* GPIO_OE */ |
342 |
return s->dir;
|
343 |
|
344 |
case 0x38: /* GPIO_DATAIN */ |
345 |
return s->inputs;
|
346 |
|
347 |
case 0x3c: /* GPIO_DATAOUT */ |
348 |
case 0x90: /* GPIO_CLEARDATAOUT */ |
349 |
case 0x94: /* GPIO_SETDATAOUT */ |
350 |
return s->outputs;
|
351 |
|
352 |
case 0x40: /* GPIO_LEVELDETECT0 */ |
353 |
return s->level[0]; |
354 |
|
355 |
case 0x44: /* GPIO_LEVELDETECT1 */ |
356 |
return s->level[1]; |
357 |
|
358 |
case 0x48: /* GPIO_RISINGDETECT */ |
359 |
return s->edge[0]; |
360 |
|
361 |
case 0x4c: /* GPIO_FALLINGDETECT */ |
362 |
return s->edge[1]; |
363 |
|
364 |
case 0x50: /* GPIO_DEBOUNCENABLE */ |
365 |
return s->debounce;
|
366 |
|
367 |
case 0x54: /* GPIO_DEBOUNCINGTIME */ |
368 |
return s->delay;
|
369 |
} |
370 |
|
371 |
OMAP_BAD_REG(addr); |
372 |
return 0; |
373 |
} |
374 |
|
375 |
static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr, |
376 |
uint32_t value) |
377 |
{ |
378 |
struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
379 |
uint32_t diff; |
380 |
int ln;
|
381 |
|
382 |
switch (addr) {
|
383 |
case 0x00: /* GPIO_REVISION */ |
384 |
case 0x14: /* GPIO_SYSSTATUS */ |
385 |
case 0x38: /* GPIO_DATAIN */ |
386 |
OMAP_RO_REG(addr); |
387 |
break;
|
388 |
|
389 |
case 0x10: /* GPIO_SYSCONFIG */ |
390 |
if (((value >> 3) & 3) == 3) |
391 |
fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
|
392 |
if (value & 2) |
393 |
omap2_gpio_module_reset(s); |
394 |
s->config[0] = value & 0x1d; |
395 |
break;
|
396 |
|
397 |
case 0x18: /* GPIO_IRQSTATUS1 */ |
398 |
if (s->ints[0] & value) { |
399 |
s->ints[0] &= ~value;
|
400 |
omap2_gpio_module_level_update(s, 0);
|
401 |
} |
402 |
break;
|
403 |
|
404 |
case 0x1c: /* GPIO_IRQENABLE1 */ |
405 |
s->mask[0] = value;
|
406 |
omap2_gpio_module_int_update(s, 0);
|
407 |
break;
|
408 |
|
409 |
case 0x20: /* GPIO_WAKEUPENABLE */ |
410 |
s->wumask = value; |
411 |
break;
|
412 |
|
413 |
case 0x28: /* GPIO_IRQSTATUS2 */ |
414 |
if (s->ints[1] & value) { |
415 |
s->ints[1] &= ~value;
|
416 |
omap2_gpio_module_level_update(s, 1);
|
417 |
} |
418 |
break;
|
419 |
|
420 |
case 0x2c: /* GPIO_IRQENABLE2 */ |
421 |
s->mask[1] = value;
|
422 |
omap2_gpio_module_int_update(s, 1);
|
423 |
break;
|
424 |
|
425 |
case 0x30: /* GPIO_CTRL */ |
426 |
s->config[1] = value & 7; |
427 |
break;
|
428 |
|
429 |
case 0x34: /* GPIO_OE */ |
430 |
diff = s->outputs & (s->dir ^ value); |
431 |
s->dir = value; |
432 |
|
433 |
value = s->outputs & ~s->dir; |
434 |
while ((ln = ffs(diff))) {
|
435 |
diff &= ~(1 <<-- ln);
|
436 |
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
437 |
} |
438 |
|
439 |
omap2_gpio_module_level_update(s, 0);
|
440 |
omap2_gpio_module_level_update(s, 1);
|
441 |
break;
|
442 |
|
443 |
case 0x3c: /* GPIO_DATAOUT */ |
444 |
omap2_gpio_module_out_update(s, s->outputs ^ value); |
445 |
break;
|
446 |
|
447 |
case 0x40: /* GPIO_LEVELDETECT0 */ |
448 |
s->level[0] = value;
|
449 |
omap2_gpio_module_level_update(s, 0);
|
450 |
omap2_gpio_module_level_update(s, 1);
|
451 |
break;
|
452 |
|
453 |
case 0x44: /* GPIO_LEVELDETECT1 */ |
454 |
s->level[1] = value;
|
455 |
omap2_gpio_module_level_update(s, 0);
|
456 |
omap2_gpio_module_level_update(s, 1);
|
457 |
break;
|
458 |
|
459 |
case 0x48: /* GPIO_RISINGDETECT */ |
460 |
s->edge[0] = value;
|
461 |
break;
|
462 |
|
463 |
case 0x4c: /* GPIO_FALLINGDETECT */ |
464 |
s->edge[1] = value;
|
465 |
break;
|
466 |
|
467 |
case 0x50: /* GPIO_DEBOUNCENABLE */ |
468 |
s->debounce = value; |
469 |
break;
|
470 |
|
471 |
case 0x54: /* GPIO_DEBOUNCINGTIME */ |
472 |
s->delay = value; |
473 |
break;
|
474 |
|
475 |
case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
476 |
s->mask[0] &= ~value;
|
477 |
omap2_gpio_module_int_update(s, 0);
|
478 |
break;
|
479 |
|
480 |
case 0x64: /* GPIO_SETIRQENABLE1 */ |
481 |
s->mask[0] |= value;
|
482 |
omap2_gpio_module_int_update(s, 0);
|
483 |
break;
|
484 |
|
485 |
case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
486 |
s->mask[1] &= ~value;
|
487 |
omap2_gpio_module_int_update(s, 1);
|
488 |
break;
|
489 |
|
490 |
case 0x74: /* GPIO_SETIREQNEABLE2 */ |
491 |
s->mask[1] |= value;
|
492 |
omap2_gpio_module_int_update(s, 1);
|
493 |
break;
|
494 |
|
495 |
case 0x80: /* GPIO_CLEARWKUENA */ |
496 |
s->wumask &= ~value; |
497 |
break;
|
498 |
|
499 |
case 0x84: /* GPIO_SETWKUENA */ |
500 |
s->wumask |= value; |
501 |
break;
|
502 |
|
503 |
case 0x90: /* GPIO_CLEARDATAOUT */ |
504 |
omap2_gpio_module_out_update(s, s->outputs & value); |
505 |
break;
|
506 |
|
507 |
case 0x94: /* GPIO_SETDATAOUT */ |
508 |
omap2_gpio_module_out_update(s, ~s->outputs & value); |
509 |
break;
|
510 |
|
511 |
default:
|
512 |
OMAP_BAD_REG(addr); |
513 |
return;
|
514 |
} |
515 |
} |
516 |
|
517 |
static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr) |
518 |
{ |
519 |
return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3); |
520 |
} |
521 |
|
522 |
static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr, |
523 |
uint32_t value) |
524 |
{ |
525 |
uint32_t cur = 0;
|
526 |
uint32_t mask = 0xffff;
|
527 |
|
528 |
switch (addr & ~3) { |
529 |
case 0x00: /* GPIO_REVISION */ |
530 |
case 0x14: /* GPIO_SYSSTATUS */ |
531 |
case 0x38: /* GPIO_DATAIN */ |
532 |
OMAP_RO_REG(addr); |
533 |
break;
|
534 |
|
535 |
case 0x10: /* GPIO_SYSCONFIG */ |
536 |
case 0x1c: /* GPIO_IRQENABLE1 */ |
537 |
case 0x20: /* GPIO_WAKEUPENABLE */ |
538 |
case 0x2c: /* GPIO_IRQENABLE2 */ |
539 |
case 0x30: /* GPIO_CTRL */ |
540 |
case 0x34: /* GPIO_OE */ |
541 |
case 0x3c: /* GPIO_DATAOUT */ |
542 |
case 0x40: /* GPIO_LEVELDETECT0 */ |
543 |
case 0x44: /* GPIO_LEVELDETECT1 */ |
544 |
case 0x48: /* GPIO_RISINGDETECT */ |
545 |
case 0x4c: /* GPIO_FALLINGDETECT */ |
546 |
case 0x50: /* GPIO_DEBOUNCENABLE */ |
547 |
case 0x54: /* GPIO_DEBOUNCINGTIME */ |
548 |
cur = omap2_gpio_module_read(opaque, addr & ~3) &
|
549 |
~(mask << ((addr & 3) << 3)); |
550 |
|
551 |
/* Fall through. */
|
552 |
case 0x18: /* GPIO_IRQSTATUS1 */ |
553 |
case 0x28: /* GPIO_IRQSTATUS2 */ |
554 |
case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
555 |
case 0x64: /* GPIO_SETIRQENABLE1 */ |
556 |
case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
557 |
case 0x74: /* GPIO_SETIREQNEABLE2 */ |
558 |
case 0x80: /* GPIO_CLEARWKUENA */ |
559 |
case 0x84: /* GPIO_SETWKUENA */ |
560 |
case 0x90: /* GPIO_CLEARDATAOUT */ |
561 |
case 0x94: /* GPIO_SETDATAOUT */ |
562 |
value <<= (addr & 3) << 3; |
563 |
omap2_gpio_module_write(opaque, addr, cur | value); |
564 |
break;
|
565 |
|
566 |
default:
|
567 |
OMAP_BAD_REG(addr); |
568 |
return;
|
569 |
} |
570 |
} |
571 |
|
572 |
static const MemoryRegionOps omap2_gpio_module_ops = { |
573 |
.old_mmio = { |
574 |
.read = { |
575 |
omap2_gpio_module_readp, |
576 |
omap2_gpio_module_readp, |
577 |
omap2_gpio_module_read, |
578 |
}, |
579 |
.write = { |
580 |
omap2_gpio_module_writep, |
581 |
omap2_gpio_module_writep, |
582 |
omap2_gpio_module_write, |
583 |
}, |
584 |
}, |
585 |
.endianness = DEVICE_NATIVE_ENDIAN, |
586 |
}; |
587 |
|
588 |
static void omap_gpif_reset(DeviceState *dev) |
589 |
{ |
590 |
struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, |
591 |
sysbus_from_qdev(dev)); |
592 |
omap_gpio_reset(&s->omap1); |
593 |
} |
594 |
|
595 |
static void omap2_gpif_reset(DeviceState *dev) |
596 |
{ |
597 |
int i;
|
598 |
struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, |
599 |
sysbus_from_qdev(dev)); |
600 |
for (i = 0; i < s->modulecount; i++) { |
601 |
omap2_gpio_module_reset(&s->modules[i]); |
602 |
} |
603 |
s->autoidle = 0;
|
604 |
s->gpo = 0;
|
605 |
} |
606 |
|
607 |
static uint64_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr, |
608 |
unsigned size)
|
609 |
{ |
610 |
struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; |
611 |
|
612 |
switch (addr) {
|
613 |
case 0x00: /* IPGENERICOCPSPL_REVISION */ |
614 |
return 0x18; |
615 |
|
616 |
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ |
617 |
return s->autoidle;
|
618 |
|
619 |
case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ |
620 |
return 0x01; |
621 |
|
622 |
case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ |
623 |
return 0x00; |
624 |
|
625 |
case 0x40: /* IPGENERICOCPSPL_GPO */ |
626 |
return s->gpo;
|
627 |
|
628 |
case 0x50: /* IPGENERICOCPSPL_GPI */ |
629 |
return 0x00; |
630 |
} |
631 |
|
632 |
OMAP_BAD_REG(addr); |
633 |
return 0; |
634 |
} |
635 |
|
636 |
static void omap2_gpif_top_write(void *opaque, target_phys_addr_t addr, |
637 |
uint64_t value, unsigned size)
|
638 |
{ |
639 |
struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; |
640 |
|
641 |
switch (addr) {
|
642 |
case 0x00: /* IPGENERICOCPSPL_REVISION */ |
643 |
case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ |
644 |
case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ |
645 |
case 0x50: /* IPGENERICOCPSPL_GPI */ |
646 |
OMAP_RO_REG(addr); |
647 |
break;
|
648 |
|
649 |
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ |
650 |
if (value & (1 << 1)) /* SOFTRESET */ |
651 |
omap2_gpif_reset(&s->busdev.qdev); |
652 |
s->autoidle = value & 1;
|
653 |
break;
|
654 |
|
655 |
case 0x40: /* IPGENERICOCPSPL_GPO */ |
656 |
s->gpo = value & 1;
|
657 |
break;
|
658 |
|
659 |
default:
|
660 |
OMAP_BAD_REG(addr); |
661 |
return;
|
662 |
} |
663 |
} |
664 |
|
665 |
static const MemoryRegionOps omap2_gpif_top_ops = { |
666 |
.read = omap2_gpif_top_read, |
667 |
.write = omap2_gpif_top_write, |
668 |
.endianness = DEVICE_NATIVE_ENDIAN, |
669 |
}; |
670 |
|
671 |
static int omap_gpio_init(SysBusDevice *dev) |
672 |
{ |
673 |
struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev); |
674 |
if (!s->clk) {
|
675 |
hw_error("omap-gpio: clk not connected\n");
|
676 |
} |
677 |
qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
|
678 |
qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
|
679 |
sysbus_init_irq(dev, &s->omap1.irq); |
680 |
memory_region_init_io(&s->iomem, &omap_gpio_ops, &s->omap1, |
681 |
"omap.gpio", 0x1000); |
682 |
sysbus_init_mmio(dev, &s->iomem); |
683 |
return 0; |
684 |
} |
685 |
|
686 |
static int omap2_gpio_init(SysBusDevice *dev) |
687 |
{ |
688 |
int i;
|
689 |
struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev); |
690 |
if (!s->iclk) {
|
691 |
hw_error("omap2-gpio: iclk not connected\n");
|
692 |
} |
693 |
if (s->mpu_model < omap3430) {
|
694 |
s->modulecount = (s->mpu_model < omap2430) ? 4 : 5; |
695 |
memory_region_init_io(&s->iomem, &omap2_gpif_top_ops, s, |
696 |
"omap2.gpio", 0x1000); |
697 |
sysbus_init_mmio(dev, &s->iomem); |
698 |
} else {
|
699 |
s->modulecount = 6;
|
700 |
} |
701 |
s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s)); |
702 |
s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq)); |
703 |
qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
|
704 |
qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
|
705 |
for (i = 0; i < s->modulecount; i++) { |
706 |
struct omap2_gpio_s *m = &s->modules[i];
|
707 |
if (!s->fclk[i]) {
|
708 |
hw_error("omap2-gpio: fclk%d not connected\n", i);
|
709 |
} |
710 |
m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25; |
711 |
m->handler = &s->handler[i * 32];
|
712 |
sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */ |
713 |
sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */ |
714 |
sysbus_init_irq(dev, &m->wkup); |
715 |
memory_region_init_io(&m->iomem, &omap2_gpio_module_ops, m, |
716 |
"omap.gpio-module", 0x1000); |
717 |
sysbus_init_mmio(dev, &m->iomem); |
718 |
} |
719 |
return 0; |
720 |
} |
721 |
|
722 |
/* Using qdev pointer properties for the clocks is not ideal.
|
723 |
* qdev should support a generic means of defining a 'port' with
|
724 |
* an arbitrary interface for connecting two devices. Then we
|
725 |
* could reframe the omap clock API in terms of clock ports,
|
726 |
* and get some type safety. For now the best qdev provides is
|
727 |
* passing an arbitrary pointer.
|
728 |
* (It's not possible to pass in the string which is the clock
|
729 |
* name, because this device does not have the necessary information
|
730 |
* (ie the struct omap_mpu_state_s*) to do the clockname to pointer
|
731 |
* translation.)
|
732 |
*/
|
733 |
|
734 |
static Property omap_gpio_properties[] = {
|
735 |
DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0), |
736 |
DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk), |
737 |
DEFINE_PROP_END_OF_LIST(), |
738 |
}; |
739 |
|
740 |
static void omap_gpio_class_init(ObjectClass *klass, void *data) |
741 |
{ |
742 |
DeviceClass *dc = DEVICE_CLASS(klass); |
743 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
744 |
|
745 |
k->init = omap_gpio_init; |
746 |
dc->reset = omap_gpif_reset; |
747 |
dc->props = omap_gpio_properties; |
748 |
} |
749 |
|
750 |
static TypeInfo omap_gpio_info = {
|
751 |
.name = "omap-gpio",
|
752 |
.parent = TYPE_SYS_BUS_DEVICE, |
753 |
.instance_size = sizeof(struct omap_gpif_s), |
754 |
.class_init = omap_gpio_class_init, |
755 |
}; |
756 |
|
757 |
static Property omap2_gpio_properties[] = {
|
758 |
DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0), |
759 |
DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk), |
760 |
DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]), |
761 |
DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]), |
762 |
DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]), |
763 |
DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]), |
764 |
DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]), |
765 |
DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]), |
766 |
DEFINE_PROP_END_OF_LIST(), |
767 |
}; |
768 |
|
769 |
static void omap2_gpio_class_init(ObjectClass *klass, void *data) |
770 |
{ |
771 |
DeviceClass *dc = DEVICE_CLASS(klass); |
772 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
773 |
|
774 |
k->init = omap2_gpio_init; |
775 |
dc->reset = omap2_gpif_reset; |
776 |
dc->props = omap2_gpio_properties; |
777 |
} |
778 |
|
779 |
static TypeInfo omap2_gpio_info = {
|
780 |
.name = "omap2-gpio",
|
781 |
.parent = TYPE_SYS_BUS_DEVICE, |
782 |
.instance_size = sizeof(struct omap2_gpif_s), |
783 |
.class_init = omap2_gpio_class_init, |
784 |
}; |
785 |
|
786 |
static void omap_gpio_register_types(void) |
787 |
{ |
788 |
type_register_static(&omap_gpio_info); |
789 |
type_register_static(&omap2_gpio_info); |
790 |
} |
791 |
|
792 |
type_init(omap_gpio_register_types) |