|
|
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" ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.