|
|
1.1 ! root 1: /* ! 2: * Luminary Micro Stellaris preipherals ! 3: * ! 4: * Copyright (c) 2006 CodeSourcery. ! 5: * Written by Paul Brook ! 6: * ! 7: * This code is licenced under the GPL. ! 8: */ ! 9: ! 10: #include "hw.h" ! 11: #include "arm-misc.h" ! 12: #include "primecell.h" ! 13: #include "devices.h" ! 14: #include "qemu-timer.h" ! 15: #include "i2c.h" ! 16: #include "net.h" ! 17: #include "sd.h" ! 18: #include "sysemu.h" ! 19: #include "boards.h" ! 20: ! 21: #define GPIO_A 0 ! 22: #define GPIO_B 1 ! 23: #define GPIO_C 2 ! 24: #define GPIO_D 3 ! 25: #define GPIO_E 4 ! 26: #define GPIO_F 5 ! 27: #define GPIO_G 6 ! 28: ! 29: #define BP_OLED_I2C 0x01 ! 30: #define BP_OLED_SSI 0x02 ! 31: #define BP_GAMEPAD 0x04 ! 32: ! 33: typedef const struct { ! 34: const char *name; ! 35: uint32_t did0; ! 36: uint32_t did1; ! 37: uint32_t dc0; ! 38: uint32_t dc1; ! 39: uint32_t dc2; ! 40: uint32_t dc3; ! 41: uint32_t dc4; ! 42: uint32_t peripherals; ! 43: } stellaris_board_info; ! 44: ! 45: /* General purpose timer module. */ ! 46: ! 47: typedef struct gptm_state { ! 48: uint32_t config; ! 49: uint32_t mode[2]; ! 50: uint32_t control; ! 51: uint32_t state; ! 52: uint32_t mask; ! 53: uint32_t load[2]; ! 54: uint32_t match[2]; ! 55: uint32_t prescale[2]; ! 56: uint32_t match_prescale[2]; ! 57: uint32_t rtc; ! 58: int64_t tick[2]; ! 59: struct gptm_state *opaque[2]; ! 60: uint32_t base; ! 61: QEMUTimer *timer[2]; ! 62: /* The timers have an alternate output used to trigger the ADC. */ ! 63: qemu_irq trigger; ! 64: qemu_irq irq; ! 65: } gptm_state; ! 66: ! 67: static void gptm_update_irq(gptm_state *s) ! 68: { ! 69: int level; ! 70: level = (s->state & s->mask) != 0; ! 71: qemu_set_irq(s->irq, level); ! 72: } ! 73: ! 74: static void gptm_stop(gptm_state *s, int n) ! 75: { ! 76: qemu_del_timer(s->timer[n]); ! 77: } ! 78: ! 79: static void gptm_reload(gptm_state *s, int n, int reset) ! 80: { ! 81: int64_t tick; ! 82: if (reset) ! 83: tick = qemu_get_clock(vm_clock); ! 84: else ! 85: tick = s->tick[n]; ! 86: ! 87: if (s->config == 0) { ! 88: /* 32-bit CountDown. */ ! 89: uint32_t count; ! 90: count = s->load[0] | (s->load[1] << 16); ! 91: tick += (int64_t)count * system_clock_scale; ! 92: } else if (s->config == 1) { ! 93: /* 32-bit RTC. 1Hz tick. */ ! 94: tick += ticks_per_sec; ! 95: } else if (s->mode[n] == 0xa) { ! 96: /* PWM mode. Not implemented. */ ! 97: } else { ! 98: cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", ! 99: s->mode[n]); ! 100: } ! 101: s->tick[n] = tick; ! 102: qemu_mod_timer(s->timer[n], tick); ! 103: } ! 104: ! 105: static void gptm_tick(void *opaque) ! 106: { ! 107: gptm_state **p = (gptm_state **)opaque; ! 108: gptm_state *s; ! 109: int n; ! 110: ! 111: s = *p; ! 112: n = p - s->opaque; ! 113: if (s->config == 0) { ! 114: s->state |= 1; ! 115: if ((s->control & 0x20)) { ! 116: /* Output trigger. */ ! 117: qemu_irq_raise(s->trigger); ! 118: qemu_irq_lower(s->trigger); ! 119: } ! 120: if (s->mode[0] & 1) { ! 121: /* One-shot. */ ! 122: s->control &= ~1; ! 123: } else { ! 124: /* Periodic. */ ! 125: gptm_reload(s, 0, 0); ! 126: } ! 127: } else if (s->config == 1) { ! 128: /* RTC. */ ! 129: uint32_t match; ! 130: s->rtc++; ! 131: match = s->match[0] | (s->match[1] << 16); ! 132: if (s->rtc > match) ! 133: s->rtc = 0; ! 134: if (s->rtc == 0) { ! 135: s->state |= 8; ! 136: } ! 137: gptm_reload(s, 0, 0); ! 138: } else if (s->mode[n] == 0xa) { ! 139: /* PWM mode. Not implemented. */ ! 140: } else { ! 141: cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", ! 142: s->mode[n]); ! 143: } ! 144: gptm_update_irq(s); ! 145: } ! 146: ! 147: static uint32_t gptm_read(void *opaque, target_phys_addr_t offset) ! 148: { ! 149: gptm_state *s = (gptm_state *)opaque; ! 150: ! 151: offset -= s->base; ! 152: switch (offset) { ! 153: case 0x00: /* CFG */ ! 154: return s->config; ! 155: case 0x04: /* TAMR */ ! 156: return s->mode[0]; ! 157: case 0x08: /* TBMR */ ! 158: return s->mode[1]; ! 159: case 0x0c: /* CTL */ ! 160: return s->control; ! 161: case 0x18: /* IMR */ ! 162: return s->mask; ! 163: case 0x1c: /* RIS */ ! 164: return s->state; ! 165: case 0x20: /* MIS */ ! 166: return s->state & s->mask; ! 167: case 0x24: /* CR */ ! 168: return 0; ! 169: case 0x28: /* TAILR */ ! 170: return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0); ! 171: case 0x2c: /* TBILR */ ! 172: return s->load[1]; ! 173: case 0x30: /* TAMARCHR */ ! 174: return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0); ! 175: case 0x34: /* TBMATCHR */ ! 176: return s->match[1]; ! 177: case 0x38: /* TAPR */ ! 178: return s->prescale[0]; ! 179: case 0x3c: /* TBPR */ ! 180: return s->prescale[1]; ! 181: case 0x40: /* TAPMR */ ! 182: return s->match_prescale[0]; ! 183: case 0x44: /* TBPMR */ ! 184: return s->match_prescale[1]; ! 185: case 0x48: /* TAR */ ! 186: if (s->control == 1) ! 187: return s->rtc; ! 188: case 0x4c: /* TBR */ ! 189: cpu_abort(cpu_single_env, "TODO: Timer value read\n"); ! 190: default: ! 191: cpu_abort(cpu_single_env, "gptm_read: Bad offset 0x%x\n", (int)offset); ! 192: return 0; ! 193: } ! 194: } ! 195: ! 196: static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value) ! 197: { ! 198: gptm_state *s = (gptm_state *)opaque; ! 199: uint32_t oldval; ! 200: ! 201: offset -= s->base; ! 202: /* The timers should be disabled before changing the configuration. ! 203: We take advantage of this and defer everything until the timer ! 204: is enabled. */ ! 205: switch (offset) { ! 206: case 0x00: /* CFG */ ! 207: s->config = value; ! 208: break; ! 209: case 0x04: /* TAMR */ ! 210: s->mode[0] = value; ! 211: break; ! 212: case 0x08: /* TBMR */ ! 213: s->mode[1] = value; ! 214: break; ! 215: case 0x0c: /* CTL */ ! 216: oldval = s->control; ! 217: s->control = value; ! 218: /* TODO: Implement pause. */ ! 219: if ((oldval ^ value) & 1) { ! 220: if (value & 1) { ! 221: gptm_reload(s, 0, 1); ! 222: } else { ! 223: gptm_stop(s, 0); ! 224: } ! 225: } ! 226: if (((oldval ^ value) & 0x100) && s->config >= 4) { ! 227: if (value & 0x100) { ! 228: gptm_reload(s, 1, 1); ! 229: } else { ! 230: gptm_stop(s, 1); ! 231: } ! 232: } ! 233: break; ! 234: case 0x18: /* IMR */ ! 235: s->mask = value & 0x77; ! 236: gptm_update_irq(s); ! 237: break; ! 238: case 0x24: /* CR */ ! 239: s->state &= ~value; ! 240: break; ! 241: case 0x28: /* TAILR */ ! 242: s->load[0] = value & 0xffff; ! 243: if (s->config < 4) { ! 244: s->load[1] = value >> 16; ! 245: } ! 246: break; ! 247: case 0x2c: /* TBILR */ ! 248: s->load[1] = value & 0xffff; ! 249: break; ! 250: case 0x30: /* TAMARCHR */ ! 251: s->match[0] = value & 0xffff; ! 252: if (s->config < 4) { ! 253: s->match[1] = value >> 16; ! 254: } ! 255: break; ! 256: case 0x34: /* TBMATCHR */ ! 257: s->match[1] = value >> 16; ! 258: break; ! 259: case 0x38: /* TAPR */ ! 260: s->prescale[0] = value; ! 261: break; ! 262: case 0x3c: /* TBPR */ ! 263: s->prescale[1] = value; ! 264: break; ! 265: case 0x40: /* TAPMR */ ! 266: s->match_prescale[0] = value; ! 267: break; ! 268: case 0x44: /* TBPMR */ ! 269: s->match_prescale[0] = value; ! 270: break; ! 271: default: ! 272: cpu_abort(cpu_single_env, "gptm_write: Bad offset 0x%x\n", (int)offset); ! 273: } ! 274: gptm_update_irq(s); ! 275: } ! 276: ! 277: static CPUReadMemoryFunc *gptm_readfn[] = { ! 278: gptm_read, ! 279: gptm_read, ! 280: gptm_read ! 281: }; ! 282: ! 283: static CPUWriteMemoryFunc *gptm_writefn[] = { ! 284: gptm_write, ! 285: gptm_write, ! 286: gptm_write ! 287: }; ! 288: ! 289: static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger) ! 290: { ! 291: int iomemtype; ! 292: gptm_state *s; ! 293: ! 294: s = (gptm_state *)qemu_mallocz(sizeof(gptm_state)); ! 295: s->base = base; ! 296: s->irq = irq; ! 297: s->trigger = trigger; ! 298: s->opaque[0] = s->opaque[1] = s; ! 299: ! 300: iomemtype = cpu_register_io_memory(0, gptm_readfn, ! 301: gptm_writefn, s); ! 302: cpu_register_physical_memory(base, 0x00001000, iomemtype); ! 303: s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]); ! 304: s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]); ! 305: /* ??? Save/restore. */ ! 306: } ! 307: ! 308: ! 309: /* System controller. */ ! 310: ! 311: typedef struct { ! 312: uint32_t base; ! 313: uint32_t pborctl; ! 314: uint32_t ldopctl; ! 315: uint32_t int_status; ! 316: uint32_t int_mask; ! 317: uint32_t resc; ! 318: uint32_t rcc; ! 319: uint32_t rcgc[3]; ! 320: uint32_t scgc[3]; ! 321: uint32_t dcgc[3]; ! 322: uint32_t clkvclr; ! 323: uint32_t ldoarst; ! 324: uint32_t user0; ! 325: uint32_t user1; ! 326: qemu_irq irq; ! 327: stellaris_board_info *board; ! 328: } ssys_state; ! 329: ! 330: static void ssys_update(ssys_state *s) ! 331: { ! 332: qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0); ! 333: } ! 334: ! 335: static uint32_t pllcfg_sandstorm[16] = { ! 336: 0x31c0, /* 1 Mhz */ ! 337: 0x1ae0, /* 1.8432 Mhz */ ! 338: 0x18c0, /* 2 Mhz */ ! 339: 0xd573, /* 2.4576 Mhz */ ! 340: 0x37a6, /* 3.57954 Mhz */ ! 341: 0x1ae2, /* 3.6864 Mhz */ ! 342: 0x0c40, /* 4 Mhz */ ! 343: 0x98bc, /* 4.906 Mhz */ ! 344: 0x935b, /* 4.9152 Mhz */ ! 345: 0x09c0, /* 5 Mhz */ ! 346: 0x4dee, /* 5.12 Mhz */ ! 347: 0x0c41, /* 6 Mhz */ ! 348: 0x75db, /* 6.144 Mhz */ ! 349: 0x1ae6, /* 7.3728 Mhz */ ! 350: 0x0600, /* 8 Mhz */ ! 351: 0x585b /* 8.192 Mhz */ ! 352: }; ! 353: ! 354: static uint32_t pllcfg_fury[16] = { ! 355: 0x3200, /* 1 Mhz */ ! 356: 0x1b20, /* 1.8432 Mhz */ ! 357: 0x1900, /* 2 Mhz */ ! 358: 0xf42b, /* 2.4576 Mhz */ ! 359: 0x37e3, /* 3.57954 Mhz */ ! 360: 0x1b21, /* 3.6864 Mhz */ ! 361: 0x0c80, /* 4 Mhz */ ! 362: 0x98ee, /* 4.906 Mhz */ ! 363: 0xd5b4, /* 4.9152 Mhz */ ! 364: 0x0a00, /* 5 Mhz */ ! 365: 0x4e27, /* 5.12 Mhz */ ! 366: 0x1902, /* 6 Mhz */ ! 367: 0xec1c, /* 6.144 Mhz */ ! 368: 0x1b23, /* 7.3728 Mhz */ ! 369: 0x0640, /* 8 Mhz */ ! 370: 0xb11c /* 8.192 Mhz */ ! 371: }; ! 372: ! 373: static uint32_t ssys_read(void *opaque, target_phys_addr_t offset) ! 374: { ! 375: ssys_state *s = (ssys_state *)opaque; ! 376: ! 377: offset -= s->base; ! 378: switch (offset) { ! 379: case 0x000: /* DID0 */ ! 380: return s->board->did0; ! 381: case 0x004: /* DID1 */ ! 382: return s->board->did1; ! 383: case 0x008: /* DC0 */ ! 384: return s->board->dc0; ! 385: case 0x010: /* DC1 */ ! 386: return s->board->dc1; ! 387: case 0x014: /* DC2 */ ! 388: return s->board->dc2; ! 389: case 0x018: /* DC3 */ ! 390: return s->board->dc3; ! 391: case 0x01c: /* DC4 */ ! 392: return s->board->dc4; ! 393: case 0x030: /* PBORCTL */ ! 394: return s->pborctl; ! 395: case 0x034: /* LDOPCTL */ ! 396: return s->ldopctl; ! 397: case 0x040: /* SRCR0 */ ! 398: return 0; ! 399: case 0x044: /* SRCR1 */ ! 400: return 0; ! 401: case 0x048: /* SRCR2 */ ! 402: return 0; ! 403: case 0x050: /* RIS */ ! 404: return s->int_status; ! 405: case 0x054: /* IMC */ ! 406: return s->int_mask; ! 407: case 0x058: /* MISC */ ! 408: return s->int_status & s->int_mask; ! 409: case 0x05c: /* RESC */ ! 410: return s->resc; ! 411: case 0x060: /* RCC */ ! 412: return s->rcc; ! 413: case 0x064: /* PLLCFG */ ! 414: { ! 415: int xtal; ! 416: xtal = (s->rcc >> 6) & 0xf; ! 417: if (s->board->did0 & (1 << 16)) { ! 418: return pllcfg_fury[xtal]; ! 419: } else { ! 420: return pllcfg_sandstorm[xtal]; ! 421: } ! 422: } ! 423: case 0x100: /* RCGC0 */ ! 424: return s->rcgc[0]; ! 425: case 0x104: /* RCGC1 */ ! 426: return s->rcgc[1]; ! 427: case 0x108: /* RCGC2 */ ! 428: return s->rcgc[2]; ! 429: case 0x110: /* SCGC0 */ ! 430: return s->scgc[0]; ! 431: case 0x114: /* SCGC1 */ ! 432: return s->scgc[1]; ! 433: case 0x118: /* SCGC2 */ ! 434: return s->scgc[2]; ! 435: case 0x120: /* DCGC0 */ ! 436: return s->dcgc[0]; ! 437: case 0x124: /* DCGC1 */ ! 438: return s->dcgc[1]; ! 439: case 0x128: /* DCGC2 */ ! 440: return s->dcgc[2]; ! 441: case 0x150: /* CLKVCLR */ ! 442: return s->clkvclr; ! 443: case 0x160: /* LDOARST */ ! 444: return s->ldoarst; ! 445: case 0x1e0: /* USER0 */ ! 446: return s->user0; ! 447: case 0x1e4: /* USER1 */ ! 448: return s->user1; ! 449: default: ! 450: cpu_abort(cpu_single_env, "ssys_read: Bad offset 0x%x\n", (int)offset); ! 451: return 0; ! 452: } ! 453: } ! 454: ! 455: static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) ! 456: { ! 457: ssys_state *s = (ssys_state *)opaque; ! 458: ! 459: offset -= s->base; ! 460: switch (offset) { ! 461: case 0x030: /* PBORCTL */ ! 462: s->pborctl = value & 0xffff; ! 463: break; ! 464: case 0x034: /* LDOPCTL */ ! 465: s->ldopctl = value & 0x1f; ! 466: break; ! 467: case 0x040: /* SRCR0 */ ! 468: case 0x044: /* SRCR1 */ ! 469: case 0x048: /* SRCR2 */ ! 470: fprintf(stderr, "Peripheral reset not implemented\n"); ! 471: break; ! 472: case 0x054: /* IMC */ ! 473: s->int_mask = value & 0x7f; ! 474: break; ! 475: case 0x058: /* MISC */ ! 476: s->int_status &= ~value; ! 477: break; ! 478: case 0x05c: /* RESC */ ! 479: s->resc = value & 0x3f; ! 480: break; ! 481: case 0x060: /* RCC */ ! 482: if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { ! 483: /* PLL enable. */ ! 484: s->int_status |= (1 << 6); ! 485: } ! 486: s->rcc = value; ! 487: system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); ! 488: break; ! 489: case 0x100: /* RCGC0 */ ! 490: s->rcgc[0] = value; ! 491: break; ! 492: case 0x104: /* RCGC1 */ ! 493: s->rcgc[1] = value; ! 494: break; ! 495: case 0x108: /* RCGC2 */ ! 496: s->rcgc[2] = value; ! 497: break; ! 498: case 0x110: /* SCGC0 */ ! 499: s->scgc[0] = value; ! 500: break; ! 501: case 0x114: /* SCGC1 */ ! 502: s->scgc[1] = value; ! 503: break; ! 504: case 0x118: /* SCGC2 */ ! 505: s->scgc[2] = value; ! 506: break; ! 507: case 0x120: /* DCGC0 */ ! 508: s->dcgc[0] = value; ! 509: break; ! 510: case 0x124: /* DCGC1 */ ! 511: s->dcgc[1] = value; ! 512: break; ! 513: case 0x128: /* DCGC2 */ ! 514: s->dcgc[2] = value; ! 515: break; ! 516: case 0x150: /* CLKVCLR */ ! 517: s->clkvclr = value; ! 518: break; ! 519: case 0x160: /* LDOARST */ ! 520: s->ldoarst = value; ! 521: break; ! 522: default: ! 523: cpu_abort(cpu_single_env, "ssys_write: Bad offset 0x%x\n", (int)offset); ! 524: } ! 525: ssys_update(s); ! 526: } ! 527: ! 528: static CPUReadMemoryFunc *ssys_readfn[] = { ! 529: ssys_read, ! 530: ssys_read, ! 531: ssys_read ! 532: }; ! 533: ! 534: static CPUWriteMemoryFunc *ssys_writefn[] = { ! 535: ssys_write, ! 536: ssys_write, ! 537: ssys_write ! 538: }; ! 539: ! 540: static void ssys_reset(void *opaque) ! 541: { ! 542: ssys_state *s = (ssys_state *)opaque; ! 543: ! 544: s->pborctl = 0x7ffd; ! 545: s->rcc = 0x078e3ac0; ! 546: s->rcgc[0] = 1; ! 547: s->scgc[0] = 1; ! 548: s->dcgc[0] = 1; ! 549: } ! 550: ! 551: static void stellaris_sys_init(uint32_t base, qemu_irq irq, ! 552: stellaris_board_info * board, ! 553: uint8_t *macaddr) ! 554: { ! 555: int iomemtype; ! 556: ssys_state *s; ! 557: ! 558: s = (ssys_state *)qemu_mallocz(sizeof(ssys_state)); ! 559: s->base = base; ! 560: s->irq = irq; ! 561: s->board = board; ! 562: /* Most devices come preprogrammed with a MAC address in the user data. */ ! 563: s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); ! 564: s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); ! 565: ! 566: iomemtype = cpu_register_io_memory(0, ssys_readfn, ! 567: ssys_writefn, s); ! 568: cpu_register_physical_memory(base, 0x00001000, iomemtype); ! 569: ssys_reset(s); ! 570: /* ??? Save/restore. */ ! 571: } ! 572: ! 573: ! 574: /* I2C controller. */ ! 575: ! 576: typedef struct { ! 577: i2c_bus *bus; ! 578: qemu_irq irq; ! 579: uint32_t base; ! 580: uint32_t msa; ! 581: uint32_t mcs; ! 582: uint32_t mdr; ! 583: uint32_t mtpr; ! 584: uint32_t mimr; ! 585: uint32_t mris; ! 586: uint32_t mcr; ! 587: } stellaris_i2c_state; ! 588: ! 589: #define STELLARIS_I2C_MCS_BUSY 0x01 ! 590: #define STELLARIS_I2C_MCS_ERROR 0x02 ! 591: #define STELLARIS_I2C_MCS_ADRACK 0x04 ! 592: #define STELLARIS_I2C_MCS_DATACK 0x08 ! 593: #define STELLARIS_I2C_MCS_ARBLST 0x10 ! 594: #define STELLARIS_I2C_MCS_IDLE 0x20 ! 595: #define STELLARIS_I2C_MCS_BUSBSY 0x40 ! 596: ! 597: static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset) ! 598: { ! 599: stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; ! 600: ! 601: offset -= s->base; ! 602: switch (offset) { ! 603: case 0x00: /* MSA */ ! 604: return s->msa; ! 605: case 0x04: /* MCS */ ! 606: /* We don't emulate timing, so the controller is never busy. */ ! 607: return s->mcs | STELLARIS_I2C_MCS_IDLE; ! 608: case 0x08: /* MDR */ ! 609: return s->mdr; ! 610: case 0x0c: /* MTPR */ ! 611: return s->mtpr; ! 612: case 0x10: /* MIMR */ ! 613: return s->mimr; ! 614: case 0x14: /* MRIS */ ! 615: return s->mris; ! 616: case 0x18: /* MMIS */ ! 617: return s->mris & s->mimr; ! 618: case 0x20: /* MCR */ ! 619: return s->mcr; ! 620: default: ! 621: cpu_abort(cpu_single_env, "strllaris_i2c_read: Bad offset 0x%x\n", ! 622: (int)offset); ! 623: return 0; ! 624: } ! 625: } ! 626: ! 627: static void stellaris_i2c_update(stellaris_i2c_state *s) ! 628: { ! 629: int level; ! 630: ! 631: level = (s->mris & s->mimr) != 0; ! 632: qemu_set_irq(s->irq, level); ! 633: } ! 634: ! 635: static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset, ! 636: uint32_t value) ! 637: { ! 638: stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; ! 639: ! 640: offset -= s->base; ! 641: switch (offset) { ! 642: case 0x00: /* MSA */ ! 643: s->msa = value & 0xff; ! 644: break; ! 645: case 0x04: /* MCS */ ! 646: if ((s->mcr & 0x10) == 0) { ! 647: /* Disabled. Do nothing. */ ! 648: break; ! 649: } ! 650: /* Grab the bus if this is starting a transfer. */ ! 651: if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { ! 652: if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) { ! 653: s->mcs |= STELLARIS_I2C_MCS_ARBLST; ! 654: } else { ! 655: s->mcs &= ~STELLARIS_I2C_MCS_ARBLST; ! 656: s->mcs |= STELLARIS_I2C_MCS_BUSBSY; ! 657: } ! 658: } ! 659: /* If we don't have the bus then indicate an error. */ ! 660: if (!i2c_bus_busy(s->bus) ! 661: || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { ! 662: s->mcs |= STELLARIS_I2C_MCS_ERROR; ! 663: break; ! 664: } ! 665: s->mcs &= ~STELLARIS_I2C_MCS_ERROR; ! 666: if (value & 1) { ! 667: /* Transfer a byte. */ ! 668: /* TODO: Handle errors. */ ! 669: if (s->msa & 1) { ! 670: /* Recv */ ! 671: s->mdr = i2c_recv(s->bus) & 0xff; ! 672: } else { ! 673: /* Send */ ! 674: i2c_send(s->bus, s->mdr); ! 675: } ! 676: /* Raise an interrupt. */ ! 677: s->mris |= 1; ! 678: } ! 679: if (value & 4) { ! 680: /* Finish transfer. */ ! 681: i2c_end_transfer(s->bus); ! 682: s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY; ! 683: } ! 684: break; ! 685: case 0x08: /* MDR */ ! 686: s->mdr = value & 0xff; ! 687: break; ! 688: case 0x0c: /* MTPR */ ! 689: s->mtpr = value & 0xff; ! 690: break; ! 691: case 0x10: /* MIMR */ ! 692: s->mimr = 1; ! 693: break; ! 694: case 0x1c: /* MICR */ ! 695: s->mris &= ~value; ! 696: break; ! 697: case 0x20: /* MCR */ ! 698: if (value & 1) ! 699: cpu_abort(cpu_single_env, ! 700: "stellaris_i2c_write: Loopback not implemented\n"); ! 701: if (value & 0x20) ! 702: cpu_abort(cpu_single_env, ! 703: "stellaris_i2c_write: Slave mode not implemented\n"); ! 704: s->mcr = value & 0x31; ! 705: break; ! 706: default: ! 707: cpu_abort(cpu_single_env, "stellaris_i2c_write: Bad offset 0x%x\n", ! 708: (int)offset); ! 709: } ! 710: stellaris_i2c_update(s); ! 711: } ! 712: ! 713: static void stellaris_i2c_reset(stellaris_i2c_state *s) ! 714: { ! 715: if (s->mcs & STELLARIS_I2C_MCS_BUSBSY) ! 716: i2c_end_transfer(s->bus); ! 717: ! 718: s->msa = 0; ! 719: s->mcs = 0; ! 720: s->mdr = 0; ! 721: s->mtpr = 1; ! 722: s->mimr = 0; ! 723: s->mris = 0; ! 724: s->mcr = 0; ! 725: stellaris_i2c_update(s); ! 726: } ! 727: ! 728: static CPUReadMemoryFunc *stellaris_i2c_readfn[] = { ! 729: stellaris_i2c_read, ! 730: stellaris_i2c_read, ! 731: stellaris_i2c_read ! 732: }; ! 733: ! 734: static CPUWriteMemoryFunc *stellaris_i2c_writefn[] = { ! 735: stellaris_i2c_write, ! 736: stellaris_i2c_write, ! 737: stellaris_i2c_write ! 738: }; ! 739: ! 740: static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus) ! 741: { ! 742: stellaris_i2c_state *s; ! 743: int iomemtype; ! 744: ! 745: s = (stellaris_i2c_state *)qemu_mallocz(sizeof(stellaris_i2c_state)); ! 746: s->base = base; ! 747: s->irq = irq; ! 748: s->bus = bus; ! 749: ! 750: iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn, ! 751: stellaris_i2c_writefn, s); ! 752: cpu_register_physical_memory(base, 0x00001000, iomemtype); ! 753: /* ??? For now we only implement the master interface. */ ! 754: stellaris_i2c_reset(s); ! 755: } ! 756: ! 757: /* Analogue to Digital Converter. This is only partially implemented, ! 758: enough for applications that use a combined ADC and timer tick. */ ! 759: ! 760: #define STELLARIS_ADC_EM_CONTROLLER 0 ! 761: #define STELLARIS_ADC_EM_COMP 1 ! 762: #define STELLARIS_ADC_EM_EXTERNAL 4 ! 763: #define STELLARIS_ADC_EM_TIMER 5 ! 764: #define STELLARIS_ADC_EM_PWM0 6 ! 765: #define STELLARIS_ADC_EM_PWM1 7 ! 766: #define STELLARIS_ADC_EM_PWM2 8 ! 767: ! 768: #define STELLARIS_ADC_FIFO_EMPTY 0x0100 ! 769: #define STELLARIS_ADC_FIFO_FULL 0x1000 ! 770: ! 771: typedef struct ! 772: { ! 773: uint32_t base; ! 774: uint32_t actss; ! 775: uint32_t ris; ! 776: uint32_t im; ! 777: uint32_t emux; ! 778: uint32_t ostat; ! 779: uint32_t ustat; ! 780: uint32_t sspri; ! 781: uint32_t sac; ! 782: struct { ! 783: uint32_t state; ! 784: uint32_t data[16]; ! 785: } fifo[4]; ! 786: uint32_t ssmux[4]; ! 787: uint32_t ssctl[4]; ! 788: qemu_irq irq; ! 789: } stellaris_adc_state; ! 790: ! 791: static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) ! 792: { ! 793: int tail; ! 794: ! 795: tail = s->fifo[n].state & 0xf; ! 796: if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) { ! 797: s->ustat |= 1 << n; ! 798: } else { ! 799: s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf); ! 800: s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL; ! 801: if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf)) ! 802: s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY; ! 803: } ! 804: return s->fifo[n].data[tail]; ! 805: } ! 806: ! 807: static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, ! 808: uint32_t value) ! 809: { ! 810: int head; ! 811: ! 812: head = (s->fifo[n].state >> 4) & 0xf; ! 813: if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) { ! 814: s->ostat |= 1 << n; ! 815: return; ! 816: } ! 817: s->fifo[n].data[head] = value; ! 818: head = (head + 1) & 0xf; ! 819: s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY; ! 820: s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4); ! 821: if ((s->fifo[n].state & 0xf) == head) ! 822: s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; ! 823: } ! 824: ! 825: static void stellaris_adc_update(stellaris_adc_state *s) ! 826: { ! 827: int level; ! 828: ! 829: level = (s->ris & s->im) != 0; ! 830: qemu_set_irq(s->irq, level); ! 831: } ! 832: ! 833: static void stellaris_adc_trigger(void *opaque, int irq, int level) ! 834: { ! 835: stellaris_adc_state *s = (stellaris_adc_state *)opaque; ! 836: /* Some applications use the ADC as a random number source, so introduce ! 837: some variation into the signal. */ ! 838: static uint32_t noise = 0; ! 839: ! 840: if ((s->actss & 1) == 0) { ! 841: return; ! 842: } ! 843: ! 844: noise = noise * 314159 + 1; ! 845: /* ??? actual inputs not implemented. Return an arbitrary value. */ ! 846: stellaris_adc_fifo_write(s, 0, 0x200 + ((noise >> 16) & 7)); ! 847: s->ris |= 1; ! 848: stellaris_adc_update(s); ! 849: } ! 850: ! 851: static void stellaris_adc_reset(stellaris_adc_state *s) ! 852: { ! 853: int n; ! 854: ! 855: for (n = 0; n < 4; n++) { ! 856: s->ssmux[n] = 0; ! 857: s->ssctl[n] = 0; ! 858: s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY; ! 859: } ! 860: } ! 861: ! 862: static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset) ! 863: { ! 864: stellaris_adc_state *s = (stellaris_adc_state *)opaque; ! 865: ! 866: /* TODO: Implement this. */ ! 867: offset -= s->base; ! 868: if (offset >= 0x40 && offset < 0xc0) { ! 869: int n; ! 870: n = (offset - 0x40) >> 5; ! 871: switch (offset & 0x1f) { ! 872: case 0x00: /* SSMUX */ ! 873: return s->ssmux[n]; ! 874: case 0x04: /* SSCTL */ ! 875: return s->ssctl[n]; ! 876: case 0x08: /* SSFIFO */ ! 877: return stellaris_adc_fifo_read(s, n); ! 878: case 0x0c: /* SSFSTAT */ ! 879: return s->fifo[n].state; ! 880: default: ! 881: break; ! 882: } ! 883: } ! 884: switch (offset) { ! 885: case 0x00: /* ACTSS */ ! 886: return s->actss; ! 887: case 0x04: /* RIS */ ! 888: return s->ris; ! 889: case 0x08: /* IM */ ! 890: return s->im; ! 891: case 0x0c: /* ISC */ ! 892: return s->ris & s->im; ! 893: case 0x10: /* OSTAT */ ! 894: return s->ostat; ! 895: case 0x14: /* EMUX */ ! 896: return s->emux; ! 897: case 0x18: /* USTAT */ ! 898: return s->ustat; ! 899: case 0x20: /* SSPRI */ ! 900: return s->sspri; ! 901: case 0x30: /* SAC */ ! 902: return s->sac; ! 903: default: ! 904: cpu_abort(cpu_single_env, "strllaris_adc_read: Bad offset 0x%x\n", ! 905: (int)offset); ! 906: return 0; ! 907: } ! 908: } ! 909: ! 910: static void stellaris_adc_write(void *opaque, target_phys_addr_t offset, ! 911: uint32_t value) ! 912: { ! 913: stellaris_adc_state *s = (stellaris_adc_state *)opaque; ! 914: ! 915: /* TODO: Implement this. */ ! 916: offset -= s->base; ! 917: if (offset >= 0x40 && offset < 0xc0) { ! 918: int n; ! 919: n = (offset - 0x40) >> 5; ! 920: switch (offset & 0x1f) { ! 921: case 0x00: /* SSMUX */ ! 922: s->ssmux[n] = value & 0x33333333; ! 923: return; ! 924: case 0x04: /* SSCTL */ ! 925: if (value != 6) { ! 926: cpu_abort(cpu_single_env, "ADC: Unimplemented sequence %x\n", ! 927: value); ! 928: } ! 929: s->ssctl[n] = value; ! 930: return; ! 931: default: ! 932: break; ! 933: } ! 934: } ! 935: switch (offset) { ! 936: case 0x00: /* ACTSS */ ! 937: s->actss = value & 0xf; ! 938: if (value & 0xe) { ! 939: cpu_abort(cpu_single_env, ! 940: "Not implemented: ADC sequencers 1-3\n"); ! 941: } ! 942: break; ! 943: case 0x08: /* IM */ ! 944: s->im = value; ! 945: break; ! 946: case 0x0c: /* ISC */ ! 947: s->ris &= ~value; ! 948: break; ! 949: case 0x10: /* OSTAT */ ! 950: s->ostat &= ~value; ! 951: break; ! 952: case 0x14: /* EMUX */ ! 953: s->emux = value; ! 954: break; ! 955: case 0x18: /* USTAT */ ! 956: s->ustat &= ~value; ! 957: break; ! 958: case 0x20: /* SSPRI */ ! 959: s->sspri = value; ! 960: break; ! 961: case 0x28: /* PSSI */ ! 962: cpu_abort(cpu_single_env, "Not implemented: ADC sample initiate\n"); ! 963: break; ! 964: case 0x30: /* SAC */ ! 965: s->sac = value; ! 966: break; ! 967: default: ! 968: cpu_abort(cpu_single_env, "stellaris_adc_write: Bad offset 0x%x\n", ! 969: (int)offset); ! 970: } ! 971: stellaris_adc_update(s); ! 972: } ! 973: ! 974: static CPUReadMemoryFunc *stellaris_adc_readfn[] = { ! 975: stellaris_adc_read, ! 976: stellaris_adc_read, ! 977: stellaris_adc_read ! 978: }; ! 979: ! 980: static CPUWriteMemoryFunc *stellaris_adc_writefn[] = { ! 981: stellaris_adc_write, ! 982: stellaris_adc_write, ! 983: stellaris_adc_write ! 984: }; ! 985: ! 986: static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) ! 987: { ! 988: stellaris_adc_state *s; ! 989: int iomemtype; ! 990: qemu_irq *qi; ! 991: ! 992: s = (stellaris_adc_state *)qemu_mallocz(sizeof(stellaris_adc_state)); ! 993: s->base = base; ! 994: s->irq = irq; ! 995: ! 996: iomemtype = cpu_register_io_memory(0, stellaris_adc_readfn, ! 997: stellaris_adc_writefn, s); ! 998: cpu_register_physical_memory(base, 0x00001000, iomemtype); ! 999: stellaris_adc_reset(s); ! 1000: qi = qemu_allocate_irqs(stellaris_adc_trigger, s, 1); ! 1001: return qi[0]; ! 1002: } ! 1003: ! 1004: /* Some boards have both an OLED controller and SD card connected to ! 1005: the same SSI port, with the SD card chip select connected to a ! 1006: GPIO pin. Technically the OLED chip select is connected to the SSI ! 1007: Fss pin. We do not bother emulating that as both devices should ! 1008: never be selected simultaneously, and our OLED controller ignores stray ! 1009: 0xff commands that occur when deselecting the SD card. */ ! 1010: ! 1011: typedef struct { ! 1012: ssi_xfer_cb xfer_cb[2]; ! 1013: void *opaque[2]; ! 1014: qemu_irq irq; ! 1015: int current_dev; ! 1016: } stellaris_ssi_bus_state; ! 1017: ! 1018: static void stellaris_ssi_bus_select(void *opaque, int irq, int level) ! 1019: { ! 1020: stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; ! 1021: ! 1022: s->current_dev = level; ! 1023: } ! 1024: ! 1025: static int stellaris_ssi_bus_xfer(void *opaque, int val) ! 1026: { ! 1027: stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; ! 1028: ! 1029: return s->xfer_cb[s->current_dev](s->opaque[s->current_dev], val); ! 1030: } ! 1031: ! 1032: static void *stellaris_ssi_bus_init(qemu_irq *irqp, ! 1033: ssi_xfer_cb cb0, void *opaque0, ! 1034: ssi_xfer_cb cb1, void *opaque1) ! 1035: { ! 1036: qemu_irq *qi; ! 1037: stellaris_ssi_bus_state *s; ! 1038: ! 1039: s = (stellaris_ssi_bus_state *)qemu_mallocz(sizeof(stellaris_ssi_bus_state)); ! 1040: s->xfer_cb[0] = cb0; ! 1041: s->opaque[0] = opaque0; ! 1042: s->xfer_cb[1] = cb1; ! 1043: s->opaque[1] = opaque1; ! 1044: qi = qemu_allocate_irqs(stellaris_ssi_bus_select, s, 1); ! 1045: *irqp = *qi; ! 1046: return s; ! 1047: } ! 1048: ! 1049: /* Board init. */ ! 1050: static stellaris_board_info stellaris_boards[] = { ! 1051: { "LM3S811EVB", ! 1052: 0, ! 1053: 0x0032000e, ! 1054: 0x001f001f, /* dc0 */ ! 1055: 0x001132bf, ! 1056: 0x01071013, ! 1057: 0x3f0f01ff, ! 1058: 0x0000001f, ! 1059: BP_OLED_I2C ! 1060: }, ! 1061: { "LM3S6965EVB", ! 1062: 0x10010002, ! 1063: 0x1073402e, ! 1064: 0x00ff007f, /* dc0 */ ! 1065: 0x001133ff, ! 1066: 0x030f5317, ! 1067: 0x0f0f87ff, ! 1068: 0x5000007f, ! 1069: BP_OLED_SSI | BP_GAMEPAD ! 1070: } ! 1071: }; ! 1072: ! 1073: static void stellaris_init(const char *kernel_filename, const char *cpu_model, ! 1074: DisplayState *ds, stellaris_board_info *board) ! 1075: { ! 1076: static const int uart_irq[] = {5, 6, 33, 34}; ! 1077: static const int timer_irq[] = {19, 21, 23, 35}; ! 1078: static const uint32_t gpio_addr[7] = ! 1079: { 0x40004000, 0x40005000, 0x40006000, 0x40007000, ! 1080: 0x40024000, 0x40025000, 0x40026000}; ! 1081: static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; ! 1082: ! 1083: qemu_irq *pic; ! 1084: qemu_irq *gpio_in[5]; ! 1085: qemu_irq *gpio_out[5]; ! 1086: qemu_irq adc; ! 1087: int sram_size; ! 1088: int flash_size; ! 1089: i2c_bus *i2c; ! 1090: int i; ! 1091: ! 1092: flash_size = ((board->dc0 & 0xffff) + 1) << 1; ! 1093: sram_size = (board->dc0 >> 18) + 1; ! 1094: pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model); ! 1095: ! 1096: if (board->dc1 & (1 << 16)) { ! 1097: adc = stellaris_adc_init(0x40038000, pic[14]); ! 1098: } else { ! 1099: adc = NULL; ! 1100: } ! 1101: for (i = 0; i < 4; i++) { ! 1102: if (board->dc2 & (0x10000 << i)) { ! 1103: stellaris_gptm_init(0x40030000 + i * 0x1000, ! 1104: pic[timer_irq[i]], adc); ! 1105: } ! 1106: } ! 1107: ! 1108: stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr); ! 1109: ! 1110: for (i = 0; i < 7; i++) { ! 1111: if (board->dc4 & (1 << i)) { ! 1112: gpio_in[i] = pl061_init(gpio_addr[i], pic[gpio_irq[i]], ! 1113: &gpio_out[i]); ! 1114: } ! 1115: } ! 1116: ! 1117: if (board->dc2 & (1 << 12)) { ! 1118: i2c = i2c_init_bus(); ! 1119: stellaris_i2c_init(0x40020000, pic[8], i2c); ! 1120: if (board->peripherals & BP_OLED_I2C) { ! 1121: ssd0303_init(ds, i2c, 0x3d); ! 1122: } ! 1123: } ! 1124: ! 1125: for (i = 0; i < 4; i++) { ! 1126: if (board->dc2 & (1 << i)) { ! 1127: pl011_init(0x4000c000 + i * 0x1000, pic[uart_irq[i]], ! 1128: serial_hds[i], PL011_LUMINARY); ! 1129: } ! 1130: } ! 1131: if (board->dc2 & (1 << 4)) { ! 1132: if (board->peripherals & BP_OLED_SSI) { ! 1133: void * oled; ! 1134: void * sd; ! 1135: void *ssi_bus; ! 1136: int index; ! 1137: ! 1138: oled = ssd0323_init(ds, &gpio_out[GPIO_C][7]); ! 1139: index = drive_get_index(IF_SD, 0, 0); ! 1140: sd = ssi_sd_init(drives_table[index].bdrv); ! 1141: ! 1142: ssi_bus = stellaris_ssi_bus_init(&gpio_out[GPIO_D][0], ! 1143: ssi_sd_xfer, sd, ! 1144: ssd0323_xfer_ssi, oled); ! 1145: ! 1146: pl022_init(0x40008000, pic[7], stellaris_ssi_bus_xfer, ssi_bus); ! 1147: /* Make sure the select pin is high. */ ! 1148: qemu_irq_raise(gpio_out[GPIO_D][0]); ! 1149: } else { ! 1150: pl022_init(0x40008000, pic[7], NULL, NULL); ! 1151: } ! 1152: } ! 1153: if (board->dc4 & (1 << 28)) { ! 1154: /* FIXME: Obey network model. */ ! 1155: stellaris_enet_init(&nd_table[0], 0x40048000, pic[42]); ! 1156: } ! 1157: if (board->peripherals & BP_GAMEPAD) { ! 1158: qemu_irq gpad_irq[5]; ! 1159: static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; ! 1160: ! 1161: gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ ! 1162: gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ ! 1163: gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ ! 1164: gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ ! 1165: gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ ! 1166: ! 1167: stellaris_gamepad_init(5, gpad_irq, gpad_keycode); ! 1168: } ! 1169: } ! 1170: ! 1171: /* FIXME: Figure out how to generate these from stellaris_boards. */ ! 1172: static void lm3s811evb_init(int ram_size, int vga_ram_size, ! 1173: const char *boot_device, DisplayState *ds, ! 1174: const char *kernel_filename, const char *kernel_cmdline, ! 1175: const char *initrd_filename, const char *cpu_model) ! 1176: { ! 1177: stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[0]); ! 1178: } ! 1179: ! 1180: static void lm3s6965evb_init(int ram_size, int vga_ram_size, ! 1181: const char *boot_device, DisplayState *ds, ! 1182: const char *kernel_filename, const char *kernel_cmdline, ! 1183: const char *initrd_filename, const char *cpu_model) ! 1184: { ! 1185: stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[1]); ! 1186: } ! 1187: ! 1188: QEMUMachine lm3s811evb_machine = { ! 1189: "lm3s811evb", ! 1190: "Stellaris LM3S811EVB", ! 1191: lm3s811evb_init, ! 1192: }; ! 1193: ! 1194: QEMUMachine lm3s6965evb_machine = { ! 1195: "lm3s6965evb", ! 1196: "Stellaris LM3S6965EVB", ! 1197: lm3s6965evb_init, ! 1198: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.