|
|
1.1 ! root 1: /* ! 2: * ARM Integrator CP System emulation. ! 3: * ! 4: * Copyright (c) 2005 CodeSourcery, LLC. ! 5: * Written by Paul Brook ! 6: * ! 7: * This code is licenced under the GPL ! 8: */ ! 9: ! 10: #include <vl.h> ! 11: ! 12: #define KERNEL_ARGS_ADDR 0x100 ! 13: #define KERNEL_LOAD_ADDR 0x00010000 ! 14: #define INITRD_LOAD_ADDR 0x00800000 ! 15: ! 16: /* Stub functions for hardware that doesn't exist. */ ! 17: void pic_set_irq(int irq, int level) ! 18: { ! 19: cpu_abort (cpu_single_env, "pic_set_irq"); ! 20: } ! 21: ! 22: void pic_info(void) ! 23: { ! 24: } ! 25: ! 26: void irq_info(void) ! 27: { ! 28: } ! 29: ! 30: void vga_update_display(void) ! 31: { ! 32: } ! 33: ! 34: void vga_screen_dump(const char *filename) ! 35: { ! 36: } ! 37: ! 38: void vga_invalidate_display(void) ! 39: { ! 40: } ! 41: ! 42: void DMA_run (void) ! 43: { ! 44: } ! 45: ! 46: typedef struct { ! 47: uint32_t flash_offset; ! 48: uint32_t cm_osc; ! 49: uint32_t cm_ctrl; ! 50: uint32_t cm_lock; ! 51: uint32_t cm_auxosc; ! 52: uint32_t cm_sdram; ! 53: uint32_t cm_init; ! 54: uint32_t cm_flags; ! 55: uint32_t cm_nvflags; ! 56: uint32_t int_level; ! 57: uint32_t irq_enabled; ! 58: uint32_t fiq_enabled; ! 59: } integratorcm_state; ! 60: ! 61: static uint8_t integrator_spd[128] = { ! 62: 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, ! 63: 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 ! 64: }; ! 65: ! 66: static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset) ! 67: { ! 68: integratorcm_state *s = (integratorcm_state *)opaque; ! 69: offset -= 0x10000000; ! 70: if (offset >= 0x100 && offset < 0x200) { ! 71: /* CM_SPD */ ! 72: if (offset >= 0x180) ! 73: return 0; ! 74: return integrator_spd[offset >> 2]; ! 75: } ! 76: switch (offset >> 2) { ! 77: case 0: /* CM_ID */ ! 78: return 0x411a3001; ! 79: case 1: /* CM_PROC */ ! 80: return 0; ! 81: case 2: /* CM_OSC */ ! 82: return s->cm_osc; ! 83: case 3: /* CM_CTRL */ ! 84: return s->cm_ctrl; ! 85: case 4: /* CM_STAT */ ! 86: return 0x00100000; ! 87: case 5: /* CM_LOCK */ ! 88: if (s->cm_lock == 0xa05f) { ! 89: return 0x1a05f; ! 90: } else { ! 91: return s->cm_lock; ! 92: } ! 93: case 6: /* CM_LMBUSCNT */ ! 94: /* ??? High frequency timer. */ ! 95: cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT"); ! 96: case 7: /* CM_AUXOSC */ ! 97: return s->cm_auxosc; ! 98: case 8: /* CM_SDRAM */ ! 99: return s->cm_sdram; ! 100: case 9: /* CM_INIT */ ! 101: return s->cm_init; ! 102: case 10: /* CM_REFCT */ ! 103: /* ??? High frequency timer. */ ! 104: cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT"); ! 105: case 12: /* CM_FLAGS */ ! 106: return s->cm_flags; ! 107: case 14: /* CM_NVFLAGS */ ! 108: return s->cm_nvflags; ! 109: case 16: /* CM_IRQ_STAT */ ! 110: return s->int_level & s->irq_enabled; ! 111: case 17: /* CM_IRQ_RSTAT */ ! 112: return s->int_level; ! 113: case 18: /* CM_IRQ_ENSET */ ! 114: return s->irq_enabled; ! 115: case 20: /* CM_SOFT_INTSET */ ! 116: return s->int_level & 1; ! 117: case 24: /* CM_FIQ_STAT */ ! 118: return s->int_level & s->fiq_enabled; ! 119: case 25: /* CM_FIQ_RSTAT */ ! 120: return s->int_level; ! 121: case 26: /* CM_FIQ_ENSET */ ! 122: return s->fiq_enabled; ! 123: case 32: /* CM_VOLTAGE_CTL0 */ ! 124: case 33: /* CM_VOLTAGE_CTL1 */ ! 125: case 34: /* CM_VOLTAGE_CTL2 */ ! 126: case 35: /* CM_VOLTAGE_CTL3 */ ! 127: /* ??? Voltage control unimplemented. */ ! 128: return 0; ! 129: default: ! 130: cpu_abort (cpu_single_env, ! 131: "integratorcm_read: Unimplemented offset 0x%x\n", offset); ! 132: return 0; ! 133: } ! 134: } ! 135: ! 136: static void integratorcm_do_remap(integratorcm_state *s, int flash) ! 137: { ! 138: if (flash) { ! 139: cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM); ! 140: } else { ! 141: cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM); ! 142: } ! 143: //??? tlb_flush (cpu_single_env, 1); ! 144: } ! 145: ! 146: static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) ! 147: { ! 148: if (value & 8) { ! 149: cpu_abort(cpu_single_env, "Board reset\n"); ! 150: } ! 151: if ((s->cm_init ^ value) & 4) { ! 152: integratorcm_do_remap(s, (value & 4) == 0); ! 153: } ! 154: if ((s->cm_init ^ value) & 1) { ! 155: printf("Green LED %s\n", (value & 1) ? "on" : "off"); ! 156: } ! 157: s->cm_init = (s->cm_init & ~ 5) | (value ^ 5); ! 158: } ! 159: ! 160: static void integratorcm_update(integratorcm_state *s) ! 161: { ! 162: /* ??? The CPU irq/fiq is raised when either the core module or base PIC ! 163: are active. */ ! 164: if (s->int_level & (s->irq_enabled | s->fiq_enabled)) ! 165: cpu_abort(cpu_single_env, "Core module interrupt\n"); ! 166: } ! 167: ! 168: static void integratorcm_write(void *opaque, target_phys_addr_t offset, ! 169: uint32_t value) ! 170: { ! 171: integratorcm_state *s = (integratorcm_state *)opaque; ! 172: offset -= 0x10000000; ! 173: switch (offset >> 2) { ! 174: case 2: /* CM_OSC */ ! 175: if (s->cm_lock == 0xa05f) ! 176: s->cm_osc = value; ! 177: break; ! 178: case 3: /* CM_CTRL */ ! 179: integratorcm_set_ctrl(s, value); ! 180: break; ! 181: case 5: /* CM_LOCK */ ! 182: s->cm_lock = value & 0xffff; ! 183: break; ! 184: case 7: /* CM_AUXOSC */ ! 185: if (s->cm_lock == 0xa05f) ! 186: s->cm_auxosc = value; ! 187: break; ! 188: case 8: /* CM_SDRAM */ ! 189: s->cm_sdram = value; ! 190: break; ! 191: case 9: /* CM_INIT */ ! 192: /* ??? This can change the memory bus frequency. */ ! 193: s->cm_init = value; ! 194: break; ! 195: case 12: /* CM_FLAGSS */ ! 196: s->cm_flags |= value; ! 197: break; ! 198: case 13: /* CM_FLAGSC */ ! 199: s->cm_flags &= ~value; ! 200: break; ! 201: case 14: /* CM_NVFLAGSS */ ! 202: s->cm_nvflags |= value; ! 203: break; ! 204: case 15: /* CM_NVFLAGSS */ ! 205: s->cm_nvflags &= ~value; ! 206: break; ! 207: case 18: /* CM_IRQ_ENSET */ ! 208: s->irq_enabled |= value; ! 209: integratorcm_update(s); ! 210: break; ! 211: case 19: /* CM_IRQ_ENCLR */ ! 212: s->irq_enabled &= ~value; ! 213: integratorcm_update(s); ! 214: break; ! 215: case 20: /* CM_SOFT_INTSET */ ! 216: s->int_level |= (value & 1); ! 217: integratorcm_update(s); ! 218: break; ! 219: case 21: /* CM_SOFT_INTCLR */ ! 220: s->int_level &= ~(value & 1); ! 221: integratorcm_update(s); ! 222: break; ! 223: case 26: /* CM_FIQ_ENSET */ ! 224: s->fiq_enabled |= value; ! 225: integratorcm_update(s); ! 226: break; ! 227: case 27: /* CM_FIQ_ENCLR */ ! 228: s->fiq_enabled &= ~value; ! 229: integratorcm_update(s); ! 230: break; ! 231: case 32: /* CM_VOLTAGE_CTL0 */ ! 232: case 33: /* CM_VOLTAGE_CTL1 */ ! 233: case 34: /* CM_VOLTAGE_CTL2 */ ! 234: case 35: /* CM_VOLTAGE_CTL3 */ ! 235: /* ??? Voltage control unimplemented. */ ! 236: break; ! 237: default: ! 238: cpu_abort (cpu_single_env, ! 239: "integratorcm_write: Unimplemented offset 0x%x\n", offset); ! 240: break; ! 241: } ! 242: } ! 243: ! 244: /* Integrator/CM control registers. */ ! 245: ! 246: static CPUReadMemoryFunc *integratorcm_readfn[] = { ! 247: integratorcm_read, ! 248: integratorcm_read, ! 249: integratorcm_read ! 250: }; ! 251: ! 252: static CPUWriteMemoryFunc *integratorcm_writefn[] = { ! 253: integratorcm_write, ! 254: integratorcm_write, ! 255: integratorcm_write ! 256: }; ! 257: ! 258: static void integratorcm_init(int memsz, uint32_t flash_offset) ! 259: { ! 260: int iomemtype; ! 261: integratorcm_state *s; ! 262: ! 263: s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state)); ! 264: s->cm_osc = 0x01000048; ! 265: /* ??? What should the high bits of this value be? */ ! 266: s->cm_auxosc = 0x0007feff; ! 267: s->cm_sdram = 0x00011122; ! 268: if (memsz >= 256) { ! 269: integrator_spd[31] = 64; ! 270: s->cm_sdram |= 0x10; ! 271: } else if (memsz >= 128) { ! 272: integrator_spd[31] = 32; ! 273: s->cm_sdram |= 0x0c; ! 274: } else if (memsz >= 64) { ! 275: integrator_spd[31] = 16; ! 276: s->cm_sdram |= 0x08; ! 277: } else if (memsz >= 32) { ! 278: integrator_spd[31] = 4; ! 279: s->cm_sdram |= 0x04; ! 280: } else { ! 281: integrator_spd[31] = 2; ! 282: } ! 283: memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); ! 284: s->cm_init = 0x00000112; ! 285: s->flash_offset = flash_offset; ! 286: ! 287: iomemtype = cpu_register_io_memory(0, integratorcm_readfn, ! 288: integratorcm_writefn, s); ! 289: cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype); ! 290: integratorcm_do_remap(s, 1); ! 291: /* ??? Save/restore. */ ! 292: } ! 293: ! 294: /* Integrator/CP hardware emulation. */ ! 295: /* Primary interrupt controller. */ ! 296: ! 297: typedef struct icp_pic_state ! 298: { ! 299: uint32_t base; ! 300: uint32_t level; ! 301: uint32_t irq_enabled; ! 302: uint32_t fiq_enabled; ! 303: void *parent; ! 304: /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */ ! 305: int parent_irq; ! 306: } icp_pic_state; ! 307: ! 308: static void icp_pic_update(icp_pic_state *s) ! 309: { ! 310: CPUState *env; ! 311: if (s->parent_irq != -1) { ! 312: uint32_t flags; ! 313: ! 314: flags = (s->level & s->irq_enabled); ! 315: pic_set_irq_new(s->parent, s->parent_irq, ! 316: flags != 0); ! 317: return; ! 318: } ! 319: /* Raise CPU interrupt. */ ! 320: env = (CPUState *)s->parent; ! 321: if (s->level & s->fiq_enabled) { ! 322: cpu_interrupt (env, CPU_INTERRUPT_FIQ); ! 323: } else { ! 324: cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ); ! 325: } ! 326: if (s->level & s->irq_enabled) { ! 327: cpu_interrupt (env, CPU_INTERRUPT_HARD); ! 328: } else { ! 329: cpu_reset_interrupt (env, CPU_INTERRUPT_HARD); ! 330: } ! 331: } ! 332: ! 333: void pic_set_irq_new(void *opaque, int irq, int level) ! 334: { ! 335: icp_pic_state *s = (icp_pic_state *)opaque; ! 336: if (level) ! 337: s->level |= 1 << irq; ! 338: else ! 339: s->level &= ~(1 << irq); ! 340: icp_pic_update(s); ! 341: } ! 342: ! 343: static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) ! 344: { ! 345: icp_pic_state *s = (icp_pic_state *)opaque; ! 346: ! 347: offset -= s->base; ! 348: switch (offset >> 2) { ! 349: case 0: /* IRQ_STATUS */ ! 350: return s->level & s->irq_enabled; ! 351: case 1: /* IRQ_RAWSTAT */ ! 352: return s->level; ! 353: case 2: /* IRQ_ENABLESET */ ! 354: return s->irq_enabled; ! 355: case 4: /* INT_SOFTSET */ ! 356: return s->level & 1; ! 357: case 8: /* FRQ_STATUS */ ! 358: return s->level & s->fiq_enabled; ! 359: case 9: /* FRQ_RAWSTAT */ ! 360: return s->level; ! 361: case 10: /* FRQ_ENABLESET */ ! 362: return s->fiq_enabled; ! 363: case 3: /* IRQ_ENABLECLR */ ! 364: case 5: /* INT_SOFTCLR */ ! 365: case 11: /* FRQ_ENABLECLR */ ! 366: default: ! 367: printf ("icp_pic_read: Bad register offset 0x%x\n", offset); ! 368: return 0; ! 369: } ! 370: } ! 371: ! 372: static void icp_pic_write(void *opaque, target_phys_addr_t offset, ! 373: uint32_t value) ! 374: { ! 375: icp_pic_state *s = (icp_pic_state *)opaque; ! 376: offset -= s->base; ! 377: ! 378: switch (offset >> 2) { ! 379: case 2: /* IRQ_ENABLESET */ ! 380: s->irq_enabled |= value; ! 381: break; ! 382: case 3: /* IRQ_ENABLECLR */ ! 383: s->irq_enabled &= ~value; ! 384: break; ! 385: case 4: /* INT_SOFTSET */ ! 386: if (value & 1) ! 387: pic_set_irq_new(s, 0, 1); ! 388: break; ! 389: case 5: /* INT_SOFTCLR */ ! 390: if (value & 1) ! 391: pic_set_irq_new(s, 0, 0); ! 392: break; ! 393: case 10: /* FRQ_ENABLESET */ ! 394: s->fiq_enabled |= value; ! 395: break; ! 396: case 11: /* FRQ_ENABLECLR */ ! 397: s->fiq_enabled &= ~value; ! 398: break; ! 399: case 0: /* IRQ_STATUS */ ! 400: case 1: /* IRQ_RAWSTAT */ ! 401: case 8: /* FRQ_STATUS */ ! 402: case 9: /* FRQ_RAWSTAT */ ! 403: default: ! 404: printf ("icp_pic_write: Bad register offset 0x%x\n", offset); ! 405: return; ! 406: } ! 407: icp_pic_update(s); ! 408: } ! 409: ! 410: static CPUReadMemoryFunc *icp_pic_readfn[] = { ! 411: icp_pic_read, ! 412: icp_pic_read, ! 413: icp_pic_read ! 414: }; ! 415: ! 416: static CPUWriteMemoryFunc *icp_pic_writefn[] = { ! 417: icp_pic_write, ! 418: icp_pic_write, ! 419: icp_pic_write ! 420: }; ! 421: ! 422: static icp_pic_state *icp_pic_init(uint32_t base, void *parent, ! 423: int parent_irq) ! 424: { ! 425: icp_pic_state *s; ! 426: int iomemtype; ! 427: ! 428: s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); ! 429: if (!s) ! 430: return NULL; ! 431: ! 432: s->base = base; ! 433: s->parent = parent; ! 434: s->parent_irq = parent_irq; ! 435: iomemtype = cpu_register_io_memory(0, icp_pic_readfn, ! 436: icp_pic_writefn, s); ! 437: cpu_register_physical_memory(base, 0x007fffff, iomemtype); ! 438: /* ??? Save/restore. */ ! 439: return s; ! 440: } ! 441: ! 442: /* Timers. */ ! 443: ! 444: /* System bus clock speed (40MHz) for timer 0. Not sure about this value. */ ! 445: #define ICP_BUS_FREQ 40000000 ! 446: ! 447: typedef struct { ! 448: int64_t next_time; ! 449: int64_t expires[3]; ! 450: int64_t loaded[3]; ! 451: QEMUTimer *timer; ! 452: icp_pic_state *pic; ! 453: uint32_t base; ! 454: uint32_t control[3]; ! 455: uint32_t count[3]; ! 456: uint32_t limit[3]; ! 457: int freq[3]; ! 458: int int_level[3]; ! 459: } icp_pit_state; ! 460: ! 461: /* Calculate the new expiry time of the given timer. */ ! 462: ! 463: static void icp_pit_reload(icp_pit_state *s, int n) ! 464: { ! 465: int64_t delay; ! 466: ! 467: s->loaded[n] = s->expires[n]; ! 468: delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]); ! 469: if (delay == 0) ! 470: delay = 1; ! 471: s->expires[n] += delay; ! 472: } ! 473: ! 474: /* Check all active timers, and schedule the next timer interrupt. */ ! 475: ! 476: static void icp_pit_update(icp_pit_state *s, int64_t now) ! 477: { ! 478: int n; ! 479: int64_t next; ! 480: ! 481: next = now; ! 482: for (n = 0; n < 3; n++) { ! 483: /* Ignore disabled timers. */ ! 484: if ((s->control[n] & 0x80) == 0) ! 485: continue; ! 486: /* Ignore expired one-shot timers. */ ! 487: if (s->count[n] == 0 && s->control[n] & 1) ! 488: continue; ! 489: if (s->expires[n] - now <= 0) { ! 490: /* Timer has expired. */ ! 491: s->int_level[n] = 1; ! 492: if (s->control[n] & 1) { ! 493: /* One-shot. */ ! 494: s->count[n] = 0; ! 495: } else { ! 496: if ((s->control[n] & 0x40) == 0) { ! 497: /* Free running. */ ! 498: if (s->control[n] & 2) ! 499: s->count[n] = 0xffffffff; ! 500: else ! 501: s->count[n] = 0xffff; ! 502: } else { ! 503: /* Periodic. */ ! 504: s->count[n] = s->limit[n]; ! 505: } ! 506: } ! 507: } ! 508: while (s->expires[n] - now <= 0) { ! 509: icp_pit_reload(s, n); ! 510: } ! 511: } ! 512: /* Update interrupts. */ ! 513: for (n = 0; n < 3; n++) { ! 514: if (s->int_level[n] && (s->control[n] & 0x20)) { ! 515: pic_set_irq_new(s->pic, 5 + n, 1); ! 516: } else { ! 517: pic_set_irq_new(s->pic, 5 + n, 0); ! 518: } ! 519: if (next - s->expires[n] < 0) ! 520: next = s->expires[n]; ! 521: } ! 522: /* Schedule the next timer interrupt. */ ! 523: if (next == now) { ! 524: qemu_del_timer(s->timer); ! 525: s->next_time = 0; ! 526: } else if (next != s->next_time) { ! 527: qemu_mod_timer(s->timer, next); ! 528: s->next_time = next; ! 529: } ! 530: } ! 531: ! 532: /* Return the current value of the timer. */ ! 533: static uint32_t icp_pit_getcount(icp_pit_state *s, int n, int64_t now) ! 534: { ! 535: int64_t elapsed; ! 536: int64_t period; ! 537: ! 538: if (s->count[n] == 0) ! 539: return 0; ! 540: if ((s->control[n] & 0x80) == 0) ! 541: return s->count[n]; ! 542: elapsed = now - s->loaded[n]; ! 543: period = s->expires[n] - s->loaded[n]; ! 544: /* If the timer should have expired then return 0. This can happen ! 545: when the host timer signal doesnt occur immediately. It's better to ! 546: have a timer appear to sit at zero for a while than have it wrap ! 547: around before the guest interrupt is raised. */ ! 548: /* ??? Could we trigger the interrupt here? */ ! 549: if (elapsed > period) ! 550: return 0; ! 551: /* We need to calculate count * elapsed / period without overfowing. ! 552: Scale both elapsed and period so they fit in a 32-bit int. */ ! 553: while (period != (int32_t)period) { ! 554: period >>= 1; ! 555: elapsed >>= 1; ! 556: } ! 557: return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed) ! 558: / (int32_t)period; ! 559: } ! 560: ! 561: static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset) ! 562: { ! 563: int n; ! 564: icp_pit_state *s = (icp_pit_state *)opaque; ! 565: ! 566: offset -= s->base; ! 567: n = offset >> 8; ! 568: if (n > 2) ! 569: cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset); ! 570: switch ((offset & 0xff) >> 2) { ! 571: case 0: /* TimerLoad */ ! 572: case 6: /* TimerBGLoad */ ! 573: return s->limit[n]; ! 574: case 1: /* TimerValue */ ! 575: return icp_pit_getcount(s, n, qemu_get_clock(vm_clock)); ! 576: case 2: /* TimerControl */ ! 577: return s->control[n]; ! 578: case 4: /* TimerRIS */ ! 579: return s->int_level[n]; ! 580: case 5: /* TimerMIS */ ! 581: if ((s->control[n] & 0x20) == 0) ! 582: return 0; ! 583: return s->int_level[n]; ! 584: default: ! 585: cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset); ! 586: return 0; ! 587: } ! 588: } ! 589: ! 590: static void icp_pit_write(void *opaque, target_phys_addr_t offset, ! 591: uint32_t value) ! 592: { ! 593: icp_pit_state *s = (icp_pit_state *)opaque; ! 594: int n; ! 595: int64_t now; ! 596: ! 597: now = qemu_get_clock(vm_clock); ! 598: offset -= s->base; ! 599: n = offset >> 8; ! 600: if (n > 2) ! 601: cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); ! 602: ! 603: switch ((offset & 0xff) >> 2) { ! 604: case 0: /* TimerLoad */ ! 605: s->limit[n] = value; ! 606: s->count[n] = value; ! 607: s->expires[n] = now; ! 608: icp_pit_reload(s, n); ! 609: break; ! 610: case 1: /* TimerValue */ ! 611: /* ??? Linux seems to want to write to this readonly register. ! 612: Ignore it. */ ! 613: break; ! 614: case 2: /* TimerControl */ ! 615: if (s->control[n] & 0x80) { ! 616: /* Pause the timer if it is running. This may cause some ! 617: inaccuracy dure to rounding, but avoids a whole lot of other ! 618: messyness. */ ! 619: s->count[n] = icp_pit_getcount(s, n, now); ! 620: } ! 621: s->control[n] = value; ! 622: if (n == 0) ! 623: s->freq[n] = ICP_BUS_FREQ; ! 624: else ! 625: s->freq[n] = 1000000; ! 626: /* ??? Need to recalculate expiry time after changing divisor. */ ! 627: switch ((value >> 2) & 3) { ! 628: case 1: s->freq[n] >>= 4; break; ! 629: case 2: s->freq[n] >>= 8; break; ! 630: } ! 631: if (s->control[n] & 0x80) { ! 632: /* Restart the timer if still enabled. */ ! 633: s->expires[n] = now; ! 634: icp_pit_reload(s, n); ! 635: } ! 636: break; ! 637: case 3: /* TimerIntClr */ ! 638: s->int_level[n] = 0; ! 639: break; ! 640: case 6: /* TimerBGLoad */ ! 641: s->limit[n] = value; ! 642: break; ! 643: default: ! 644: cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); ! 645: } ! 646: icp_pit_update(s, now); ! 647: } ! 648: ! 649: static void icp_pit_tick(void *opaque) ! 650: { ! 651: int64_t now; ! 652: ! 653: now = qemu_get_clock(vm_clock); ! 654: icp_pit_update((icp_pit_state *)opaque, now); ! 655: } ! 656: ! 657: static CPUReadMemoryFunc *icp_pit_readfn[] = { ! 658: icp_pit_read, ! 659: icp_pit_read, ! 660: icp_pit_read ! 661: }; ! 662: ! 663: static CPUWriteMemoryFunc *icp_pit_writefn[] = { ! 664: icp_pit_write, ! 665: icp_pit_write, ! 666: icp_pit_write ! 667: }; ! 668: ! 669: static void icp_pit_init(uint32_t base, icp_pic_state *pic) ! 670: { ! 671: int iomemtype; ! 672: icp_pit_state *s; ! 673: int n; ! 674: ! 675: s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); ! 676: s->base = base; ! 677: s->pic = pic; ! 678: s->freq[0] = ICP_BUS_FREQ; ! 679: s->freq[1] = 1000000; ! 680: s->freq[2] = 1000000; ! 681: for (n = 0; n < 3; n++) { ! 682: s->control[n] = 0x20; ! 683: s->count[n] = 0xffffffff; ! 684: } ! 685: ! 686: iomemtype = cpu_register_io_memory(0, icp_pit_readfn, ! 687: icp_pit_writefn, s); ! 688: cpu_register_physical_memory(base, 0x007fffff, iomemtype); ! 689: s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s); ! 690: /* ??? Save/restore. */ ! 691: } ! 692: ! 693: /* ARM PrimeCell PL011 UART */ ! 694: ! 695: typedef struct { ! 696: uint32_t base; ! 697: uint32_t readbuff; ! 698: uint32_t flags; ! 699: uint32_t lcr; ! 700: uint32_t cr; ! 701: uint32_t dmacr; ! 702: uint32_t int_enabled; ! 703: uint32_t int_level; ! 704: uint32_t read_fifo[16]; ! 705: uint32_t ilpr; ! 706: uint32_t ibrd; ! 707: uint32_t fbrd; ! 708: uint32_t ifl; ! 709: int read_pos; ! 710: int read_count; ! 711: int read_trigger; ! 712: CharDriverState *chr; ! 713: icp_pic_state *pic; ! 714: int irq; ! 715: } pl011_state; ! 716: ! 717: #define PL011_INT_TX 0x20 ! 718: #define PL011_INT_RX 0x10 ! 719: ! 720: #define PL011_FLAG_TXFE 0x80 ! 721: #define PL011_FLAG_RXFF 0x40 ! 722: #define PL011_FLAG_TXFF 0x20 ! 723: #define PL011_FLAG_RXFE 0x10 ! 724: ! 725: static const unsigned char pl011_id[] = ! 726: { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; ! 727: ! 728: static void pl011_update(pl011_state *s) ! 729: { ! 730: uint32_t flags; ! 731: ! 732: flags = s->int_level & s->int_enabled; ! 733: pic_set_irq_new(s->pic, s->irq, flags != 0); ! 734: } ! 735: ! 736: static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) ! 737: { ! 738: pl011_state *s = (pl011_state *)opaque; ! 739: uint32_t c; ! 740: ! 741: offset -= s->base; ! 742: if (offset >= 0xfe0 && offset < 0x1000) { ! 743: return pl011_id[(offset - 0xfe0) >> 2]; ! 744: } ! 745: switch (offset >> 2) { ! 746: case 0: /* UARTDR */ ! 747: s->flags &= ~PL011_FLAG_RXFF; ! 748: c = s->read_fifo[s->read_pos]; ! 749: if (s->read_count > 0) { ! 750: s->read_count--; ! 751: if (++s->read_pos == 16) ! 752: s->read_pos = 0; ! 753: } ! 754: if (s->read_count == 0) { ! 755: s->flags |= PL011_FLAG_RXFE; ! 756: } ! 757: if (s->read_count == s->read_trigger - 1) ! 758: s->int_level &= ~ PL011_INT_RX; ! 759: pl011_update(s); ! 760: return c; ! 761: case 1: /* UARTCR */ ! 762: return 0; ! 763: case 6: /* UARTFR */ ! 764: return s->flags; ! 765: case 8: /* UARTILPR */ ! 766: return s->ilpr; ! 767: case 9: /* UARTIBRD */ ! 768: return s->ibrd; ! 769: case 10: /* UARTFBRD */ ! 770: return s->fbrd; ! 771: case 11: /* UARTLCR_H */ ! 772: return s->lcr; ! 773: case 12: /* UARTCR */ ! 774: return s->cr; ! 775: case 13: /* UARTIFLS */ ! 776: return s->ifl; ! 777: case 14: /* UARTIMSC */ ! 778: return s->int_enabled; ! 779: case 15: /* UARTRIS */ ! 780: return s->int_level; ! 781: case 16: /* UARTMIS */ ! 782: return s->int_level & s->int_enabled; ! 783: case 18: /* UARTDMACR */ ! 784: return s->dmacr; ! 785: default: ! 786: cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); ! 787: return 0; ! 788: } ! 789: } ! 790: ! 791: static void pl011_set_read_trigger(pl011_state *s) ! 792: { ! 793: #if 0 ! 794: /* The docs say the RX interrupt is triggered when the FIFO exceeds ! 795: the threshold. However linux only reads the FIFO in response to an ! 796: interrupt. Triggering the interrupt when the FIFO is non-empty seems ! 797: to make things work. */ ! 798: if (s->lcr & 0x10) ! 799: s->read_trigger = (s->ifl >> 1) & 0x1c; ! 800: else ! 801: #endif ! 802: s->read_trigger = 1; ! 803: } ! 804: ! 805: static void pl011_write(void *opaque, target_phys_addr_t offset, ! 806: uint32_t value) ! 807: { ! 808: pl011_state *s = (pl011_state *)opaque; ! 809: unsigned char ch; ! 810: ! 811: offset -= s->base; ! 812: switch (offset >> 2) { ! 813: case 0: /* UARTDR */ ! 814: /* ??? Check if transmitter is enabled. */ ! 815: ch = value; ! 816: if (s->chr) ! 817: qemu_chr_write(s->chr, &ch, 1); ! 818: s->int_level |= PL011_INT_TX; ! 819: pl011_update(s); ! 820: break; ! 821: case 1: /* UARTCR */ ! 822: s->cr = value; ! 823: break; ! 824: case 8: /* UARTUARTILPR */ ! 825: s->ilpr = value; ! 826: break; ! 827: case 9: /* UARTIBRD */ ! 828: s->ibrd = value; ! 829: break; ! 830: case 10: /* UARTFBRD */ ! 831: s->fbrd = value; ! 832: break; ! 833: case 11: /* UARTLCR_H */ ! 834: s->lcr = value; ! 835: pl011_set_read_trigger(s); ! 836: break; ! 837: case 12: /* UARTCR */ ! 838: /* ??? Need to implement the enable and loopback bits. */ ! 839: s->cr = value; ! 840: break; ! 841: case 13: /* UARTIFS */ ! 842: s->ifl = value; ! 843: pl011_set_read_trigger(s); ! 844: break; ! 845: case 14: /* UARTIMSC */ ! 846: s->int_enabled = value; ! 847: pl011_update(s); ! 848: break; ! 849: case 17: /* UARTICR */ ! 850: s->int_level &= ~value; ! 851: pl011_update(s); ! 852: break; ! 853: case 18: /* UARTDMACR */ ! 854: s->dmacr = value; ! 855: if (value & 3) ! 856: cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); ! 857: break; ! 858: default: ! 859: cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); ! 860: } ! 861: } ! 862: ! 863: static int pl011_can_recieve(void *opaque) ! 864: { ! 865: pl011_state *s = (pl011_state *)opaque; ! 866: ! 867: if (s->lcr & 0x10) ! 868: return s->read_count < 16; ! 869: else ! 870: return s->read_count < 1; ! 871: } ! 872: ! 873: static void pl011_recieve(void *opaque, const uint8_t *buf, int size) ! 874: { ! 875: pl011_state *s = (pl011_state *)opaque; ! 876: int slot; ! 877: ! 878: slot = s->read_pos + s->read_count; ! 879: if (slot >= 16) ! 880: slot -= 16; ! 881: s->read_fifo[slot] = *buf; ! 882: s->read_count++; ! 883: s->flags &= ~PL011_FLAG_RXFE; ! 884: if (s->cr & 0x10 || s->read_count == 16) { ! 885: s->flags |= PL011_FLAG_RXFF; ! 886: } ! 887: if (s->read_count == s->read_trigger) { ! 888: s->int_level |= PL011_INT_RX; ! 889: pl011_update(s); ! 890: } ! 891: } ! 892: ! 893: static void pl011_event(void *opaque, int event) ! 894: { ! 895: /* ??? Should probably implement break. */ ! 896: } ! 897: ! 898: static CPUReadMemoryFunc *pl011_readfn[] = { ! 899: pl011_read, ! 900: pl011_read, ! 901: pl011_read ! 902: }; ! 903: ! 904: static CPUWriteMemoryFunc *pl011_writefn[] = { ! 905: pl011_write, ! 906: pl011_write, ! 907: pl011_write ! 908: }; ! 909: ! 910: static void pl011_init(uint32_t base, icp_pic_state *pic, int irq, ! 911: CharDriverState *chr) ! 912: { ! 913: int iomemtype; ! 914: pl011_state *s; ! 915: ! 916: s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); ! 917: iomemtype = cpu_register_io_memory(0, pl011_readfn, ! 918: pl011_writefn, s); ! 919: cpu_register_physical_memory(base, 0x007fffff, iomemtype); ! 920: s->base = base; ! 921: s->pic = pic; ! 922: s->irq = irq; ! 923: s->chr = chr; ! 924: s->read_trigger = 1; ! 925: s->ifl = 0x12; ! 926: s->cr = 0x300; ! 927: s->flags = 0x90; ! 928: if (chr){ ! 929: qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); ! 930: qemu_chr_add_event_handler(chr, pl011_event); ! 931: } ! 932: /* ??? Save/restore. */ ! 933: } ! 934: ! 935: /* CP control registers. */ ! 936: typedef struct { ! 937: uint32_t base; ! 938: } icp_control_state; ! 939: ! 940: static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset) ! 941: { ! 942: icp_control_state *s = (icp_control_state *)opaque; ! 943: offset -= s->base; ! 944: switch (offset >> 2) { ! 945: case 0: /* CP_IDFIELD */ ! 946: return 0x41034003; ! 947: case 1: /* CP_FLASHPROG */ ! 948: return 0; ! 949: case 2: /* CP_INTREG */ ! 950: return 0; ! 951: case 3: /* CP_DECODE */ ! 952: return 0x11; ! 953: default: ! 954: cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset); ! 955: return 0; ! 956: } ! 957: } ! 958: ! 959: static void icp_control_write(void *opaque, target_phys_addr_t offset, ! 960: uint32_t value) ! 961: { ! 962: icp_control_state *s = (icp_control_state *)opaque; ! 963: offset -= s->base; ! 964: switch (offset >> 2) { ! 965: case 1: /* CP_FLASHPROG */ ! 966: case 2: /* CP_INTREG */ ! 967: case 3: /* CP_DECODE */ ! 968: /* Nothing interesting implemented yet. */ ! 969: break; ! 970: default: ! 971: cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset); ! 972: } ! 973: } ! 974: static CPUReadMemoryFunc *icp_control_readfn[] = { ! 975: icp_control_read, ! 976: icp_control_read, ! 977: icp_control_read ! 978: }; ! 979: ! 980: static CPUWriteMemoryFunc *icp_control_writefn[] = { ! 981: icp_control_write, ! 982: icp_control_write, ! 983: icp_control_write ! 984: }; ! 985: ! 986: static void icp_control_init(uint32_t base) ! 987: { ! 988: int iomemtype; ! 989: icp_control_state *s; ! 990: ! 991: s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state)); ! 992: iomemtype = cpu_register_io_memory(0, icp_control_readfn, ! 993: icp_control_writefn, s); ! 994: cpu_register_physical_memory(base, 0x007fffff, iomemtype); ! 995: s->base = base; ! 996: /* ??? Save/restore. */ ! 997: } ! 998: ! 999: ! 1000: /* Keyboard/Mouse Interface. */ ! 1001: ! 1002: typedef struct { ! 1003: void *dev; ! 1004: uint32_t base; ! 1005: uint32_t cr; ! 1006: uint32_t clk; ! 1007: uint32_t last; ! 1008: icp_pic_state *pic; ! 1009: int pending; ! 1010: int irq; ! 1011: int is_mouse; ! 1012: } icp_kmi_state; ! 1013: ! 1014: static void icp_kmi_update(void *opaque, int level) ! 1015: { ! 1016: icp_kmi_state *s = (icp_kmi_state *)opaque; ! 1017: int raise; ! 1018: ! 1019: s->pending = level; ! 1020: raise = (s->pending && (s->cr & 0x10) != 0) ! 1021: || (s->cr & 0x08) != 0; ! 1022: pic_set_irq_new(s->pic, s->irq, raise); ! 1023: } ! 1024: ! 1025: static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset) ! 1026: { ! 1027: icp_kmi_state *s = (icp_kmi_state *)opaque; ! 1028: offset -= s->base; ! 1029: if (offset >= 0xfe0 && offset < 0x1000) ! 1030: return 0; ! 1031: ! 1032: switch (offset >> 2) { ! 1033: case 0: /* KMICR */ ! 1034: return s->cr; ! 1035: case 1: /* KMISTAT */ ! 1036: /* KMIC and KMID bits not implemented. */ ! 1037: if (s->pending) { ! 1038: return 0x10; ! 1039: } else { ! 1040: return 0; ! 1041: } ! 1042: case 2: /* KMIDATA */ ! 1043: if (s->pending) ! 1044: s->last = ps2_read_data(s->dev); ! 1045: return s->last; ! 1046: case 3: /* KMICLKDIV */ ! 1047: return s->clk; ! 1048: case 4: /* KMIIR */ ! 1049: return s->pending | 2; ! 1050: default: ! 1051: cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset); ! 1052: return 0; ! 1053: } ! 1054: } ! 1055: ! 1056: static void icp_kmi_write(void *opaque, target_phys_addr_t offset, ! 1057: uint32_t value) ! 1058: { ! 1059: icp_kmi_state *s = (icp_kmi_state *)opaque; ! 1060: offset -= s->base; ! 1061: switch (offset >> 2) { ! 1062: case 0: /* KMICR */ ! 1063: s->cr = value; ! 1064: icp_kmi_update(s, s->pending); ! 1065: /* ??? Need to implement the enable/disable bit. */ ! 1066: break; ! 1067: case 2: /* KMIDATA */ ! 1068: /* ??? This should toggle the TX interrupt line. */ ! 1069: /* ??? This means kbd/mouse can block each other. */ ! 1070: if (s->is_mouse) { ! 1071: ps2_write_mouse(s->dev, value); ! 1072: } else { ! 1073: ps2_write_keyboard(s->dev, value); ! 1074: } ! 1075: break; ! 1076: case 3: /* KMICLKDIV */ ! 1077: s->clk = value; ! 1078: return; ! 1079: default: ! 1080: cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset); ! 1081: } ! 1082: } ! 1083: static CPUReadMemoryFunc *icp_kmi_readfn[] = { ! 1084: icp_kmi_read, ! 1085: icp_kmi_read, ! 1086: icp_kmi_read ! 1087: }; ! 1088: ! 1089: static CPUWriteMemoryFunc *icp_kmi_writefn[] = { ! 1090: icp_kmi_write, ! 1091: icp_kmi_write, ! 1092: icp_kmi_write ! 1093: }; ! 1094: ! 1095: static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq, ! 1096: int is_mouse) ! 1097: { ! 1098: int iomemtype; ! 1099: icp_kmi_state *s; ! 1100: ! 1101: s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state)); ! 1102: iomemtype = cpu_register_io_memory(0, icp_kmi_readfn, ! 1103: icp_kmi_writefn, s); ! 1104: cpu_register_physical_memory(base, 0x007fffff, iomemtype); ! 1105: s->base = base; ! 1106: s->pic = pic; ! 1107: s->irq = irq; ! 1108: s->is_mouse = is_mouse; ! 1109: if (is_mouse) ! 1110: s->dev = ps2_mouse_init(icp_kmi_update, s); ! 1111: else ! 1112: s->dev = ps2_kbd_init(icp_kmi_update, s); ! 1113: /* ??? Save/restore. */ ! 1114: } ! 1115: ! 1116: /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ ! 1117: static uint32_t bootloader[] = { ! 1118: 0xe3a00000, /* mov r0, #0 */ ! 1119: 0xe3a01013, /* mov r1, #0x13 */ ! 1120: 0xe3811c01, /* orr r1, r1, #0x100 */ ! 1121: 0xe59f2000, /* ldr r2, [pc, #0] */ ! 1122: 0xe59ff000, /* ldr pc, [pc, #0] */ ! 1123: 0, /* Address of kernel args. Set by integratorcp_init. */ ! 1124: 0 /* Kernel entry point. Set by integratorcp_init. */ ! 1125: }; ! 1126: ! 1127: static void set_kernel_args(uint32_t ram_size, int initrd_size, ! 1128: const char *kernel_cmdline) ! 1129: { ! 1130: uint32_t *p; ! 1131: ! 1132: p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); ! 1133: /* ATAG_CORE */ ! 1134: *(p++) = 5; ! 1135: *(p++) = 0x54410001; ! 1136: *(p++) = 1; ! 1137: *(p++) = 0x1000; ! 1138: *(p++) = 0; ! 1139: /* ATAG_MEM */ ! 1140: *(p++) = 4; ! 1141: *(p++) = 0x54410002; ! 1142: *(p++) = ram_size; ! 1143: *(p++) = 0; ! 1144: if (initrd_size) { ! 1145: /* ATAG_INITRD2 */ ! 1146: *(p++) = 4; ! 1147: *(p++) = 0x54420005; ! 1148: *(p++) = INITRD_LOAD_ADDR; ! 1149: *(p++) = initrd_size; ! 1150: } ! 1151: if (kernel_cmdline && *kernel_cmdline) { ! 1152: /* ATAG_CMDLINE */ ! 1153: int cmdline_size; ! 1154: ! 1155: cmdline_size = strlen(kernel_cmdline); ! 1156: memcpy (p + 2, kernel_cmdline, cmdline_size + 1); ! 1157: cmdline_size = (cmdline_size >> 2) + 1; ! 1158: *(p++) = cmdline_size + 2; ! 1159: *(p++) = 0x54410009; ! 1160: p += cmdline_size; ! 1161: } ! 1162: /* ATAG_END */ ! 1163: *(p++) = 0; ! 1164: *(p++) = 0; ! 1165: } ! 1166: ! 1167: /* Board init. */ ! 1168: ! 1169: static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, ! 1170: DisplayState *ds, const char **fd_filename, int snapshot, ! 1171: const char *kernel_filename, const char *kernel_cmdline, ! 1172: const char *initrd_filename) ! 1173: { ! 1174: CPUState *env; ! 1175: uint32_t bios_offset; ! 1176: icp_pic_state *pic; ! 1177: int kernel_size; ! 1178: int initrd_size; ! 1179: ! 1180: env = cpu_init(); ! 1181: bios_offset = ram_size + vga_ram_size; ! 1182: /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ ! 1183: /* ??? RAM shoud repeat to fill physical memory space. */ ! 1184: /* SDRAM at address zero*/ ! 1185: cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); ! 1186: /* And again at address 0x80000000 */ ! 1187: cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); ! 1188: ! 1189: integratorcm_init(ram_size >> 20, bios_offset); ! 1190: pic = icp_pic_init(0x14000000, env, -1); ! 1191: icp_pic_init(0xca000000, pic, 26); ! 1192: icp_pit_init(0x13000000, pic); ! 1193: pl011_init(0x16000000, pic, 1, serial_hds[0]); ! 1194: pl011_init(0x17000000, pic, 2, serial_hds[1]); ! 1195: icp_control_init(0xcb000000); ! 1196: icp_kmi_init(0x18000000, pic, 3, 0); ! 1197: icp_kmi_init(0x19000000, pic, 4, 1); ! 1198: if (nd_table[0].vlan) ! 1199: smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); ! 1200: ! 1201: /* Load the kernel. */ ! 1202: if (!kernel_filename) { ! 1203: fprintf(stderr, "Kernel image must be specified\n"); ! 1204: exit(1); ! 1205: } ! 1206: kernel_size = load_image(kernel_filename, ! 1207: phys_ram_base + KERNEL_LOAD_ADDR); ! 1208: if (kernel_size < 0) { ! 1209: fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); ! 1210: exit(1); ! 1211: } ! 1212: if (initrd_filename) { ! 1213: initrd_size = load_image(initrd_filename, ! 1214: phys_ram_base + INITRD_LOAD_ADDR); ! 1215: if (initrd_size < 0) { ! 1216: fprintf(stderr, "qemu: could not load initrd '%s'\n", ! 1217: initrd_filename); ! 1218: exit(1); ! 1219: } ! 1220: } else { ! 1221: initrd_size = 0; ! 1222: } ! 1223: bootloader[5] = KERNEL_ARGS_ADDR; ! 1224: bootloader[6] = KERNEL_LOAD_ADDR; ! 1225: memcpy(phys_ram_base, bootloader, sizeof(bootloader)); ! 1226: set_kernel_args(ram_size, initrd_size, kernel_cmdline); ! 1227: } ! 1228: ! 1229: QEMUMachine integratorcp_machine = { ! 1230: "integratorcp", ! 1231: "ARM Integrator/CP", ! 1232: integratorcp_init, ! 1233: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.