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