|
|
1.1 root 1: /*
2: * ARM Versatile Platform/Application Baseboard System emulation.
3: *
4: * Copyright (c) 2005-2006 CodeSourcery.
5: * Written by Paul Brook
6: *
7: * This code is licenced under the GPL.
8: */
9:
10: #include "vl.h"
11: #include "arm_pic.h"
12:
1.1.1.2 ! root 13: #define LOCK_VALUE 0xa05f
! 14:
1.1 root 15: /* Primary interrupt controller. */
16:
17: typedef struct vpb_sic_state
18: {
19: arm_pic_handler handler;
20: uint32_t base;
21: uint32_t level;
22: uint32_t mask;
23: uint32_t pic_enable;
24: void *parent;
25: int irq;
26: } vpb_sic_state;
27:
28: static void vpb_sic_update(vpb_sic_state *s)
29: {
30: uint32_t flags;
31:
32: flags = s->level & s->mask;
33: pic_set_irq_new(s->parent, s->irq, flags != 0);
34: }
35:
36: static void vpb_sic_update_pic(vpb_sic_state *s)
37: {
38: int i;
39: uint32_t mask;
40:
41: for (i = 21; i <= 30; i++) {
42: mask = 1u << i;
43: if (!(s->pic_enable & mask))
44: continue;
45: pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
46: }
47: }
48:
49: static void vpb_sic_set_irq(void *opaque, int irq, int level)
50: {
51: vpb_sic_state *s = (vpb_sic_state *)opaque;
52: if (level)
53: s->level |= 1u << irq;
54: else
55: s->level &= ~(1u << irq);
56: if (s->pic_enable & (1u << irq))
57: pic_set_irq_new(s->parent, irq, level);
58: vpb_sic_update(s);
59: }
60:
61: static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
62: {
63: vpb_sic_state *s = (vpb_sic_state *)opaque;
64:
65: offset -= s->base;
66: switch (offset >> 2) {
67: case 0: /* STATUS */
68: return s->level & s->mask;
69: case 1: /* RAWSTAT */
70: return s->level;
71: case 2: /* ENABLE */
72: return s->mask;
73: case 4: /* SOFTINT */
74: return s->level & 1;
75: case 8: /* PICENABLE */
76: return s->pic_enable;
77: default:
78: printf ("vpb_sic_read: Bad register offset 0x%x\n", offset);
79: return 0;
80: }
81: }
82:
83: static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
84: uint32_t value)
85: {
86: vpb_sic_state *s = (vpb_sic_state *)opaque;
87: offset -= s->base;
88:
89: switch (offset >> 2) {
90: case 2: /* ENSET */
91: s->mask |= value;
92: break;
93: case 3: /* ENCLR */
94: s->mask &= ~value;
95: break;
96: case 4: /* SOFTINTSET */
97: if (value)
98: s->mask |= 1;
99: break;
100: case 5: /* SOFTINTCLR */
101: if (value)
102: s->mask &= ~1u;
103: break;
104: case 8: /* PICENSET */
105: s->pic_enable |= (value & 0x7fe00000);
106: vpb_sic_update_pic(s);
107: break;
108: case 9: /* PICENCLR */
109: s->pic_enable &= ~value;
110: vpb_sic_update_pic(s);
111: break;
112: default:
113: printf ("vpb_sic_write: Bad register offset 0x%x\n", offset);
114: return;
115: }
116: vpb_sic_update(s);
117: }
118:
119: static CPUReadMemoryFunc *vpb_sic_readfn[] = {
120: vpb_sic_read,
121: vpb_sic_read,
122: vpb_sic_read
123: };
124:
125: static CPUWriteMemoryFunc *vpb_sic_writefn[] = {
126: vpb_sic_write,
127: vpb_sic_write,
128: vpb_sic_write
129: };
130:
131: static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
132: {
133: vpb_sic_state *s;
134: int iomemtype;
135:
136: s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
137: if (!s)
138: return NULL;
139: s->handler = vpb_sic_set_irq;
140: s->base = base;
141: s->parent = parent;
142: s->irq = irq;
143: iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
144: vpb_sic_writefn, s);
145: cpu_register_physical_memory(base, 0x00000fff, iomemtype);
146: /* ??? Save/restore. */
147: return s;
148: }
149:
1.1.1.2 ! root 150: /* System controller. */
! 151:
! 152: typedef struct {
! 153: uint32_t base;
! 154: uint32_t leds;
! 155: uint16_t lockval;
! 156: uint32_t cfgdata1;
! 157: uint32_t cfgdata2;
! 158: uint32_t flags;
! 159: uint32_t nvflags;
! 160: uint32_t resetlevel;
! 161: } vpb_sys_state;
! 162:
! 163: static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
! 164: {
! 165: vpb_sys_state *s = (vpb_sys_state *)opaque;
! 166:
! 167: offset -= s->base;
! 168: switch (offset) {
! 169: case 0x00: /* ID */
! 170: return 0x41007004;
! 171: case 0x04: /* SW */
! 172: /* General purpose hardware switches.
! 173: We don't have a useful way of exposing these to the user. */
! 174: return 0;
! 175: case 0x08: /* LED */
! 176: return s->leds;
! 177: case 0x20: /* LOCK */
! 178: return s->lockval;
! 179: case 0x0c: /* OSC0 */
! 180: case 0x10: /* OSC1 */
! 181: case 0x14: /* OSC2 */
! 182: case 0x18: /* OSC3 */
! 183: case 0x1c: /* OSC4 */
! 184: case 0x24: /* 100HZ */
! 185: /* ??? Implement these. */
! 186: return 0;
! 187: case 0x28: /* CFGDATA1 */
! 188: return s->cfgdata1;
! 189: case 0x2c: /* CFGDATA2 */
! 190: return s->cfgdata2;
! 191: case 0x30: /* FLAGS */
! 192: return s->flags;
! 193: case 0x38: /* NVFLAGS */
! 194: return s->nvflags;
! 195: case 0x40: /* RESETCTL */
! 196: return s->resetlevel;
! 197: case 0x44: /* PCICTL */
! 198: return 1;
! 199: case 0x48: /* MCI */
! 200: return 0;
! 201: case 0x4c: /* FLASH */
! 202: return 0;
! 203: case 0x50: /* CLCD */
! 204: return 0x1000;
! 205: case 0x54: /* CLCDSER */
! 206: return 0;
! 207: case 0x58: /* BOOTCS */
! 208: return 0;
! 209: case 0x5c: /* 24MHz */
! 210: /* ??? not implemented. */
! 211: return 0;
! 212: case 0x60: /* MISC */
! 213: return 0;
! 214: case 0x64: /* DMAPSR0 */
! 215: case 0x68: /* DMAPSR1 */
! 216: case 0x6c: /* DMAPSR2 */
! 217: case 0x8c: /* OSCRESET0 */
! 218: case 0x90: /* OSCRESET1 */
! 219: case 0x94: /* OSCRESET2 */
! 220: case 0x98: /* OSCRESET3 */
! 221: case 0x9c: /* OSCRESET4 */
! 222: case 0xc0: /* SYS_TEST_OSC0 */
! 223: case 0xc4: /* SYS_TEST_OSC1 */
! 224: case 0xc8: /* SYS_TEST_OSC2 */
! 225: case 0xcc: /* SYS_TEST_OSC3 */
! 226: case 0xd0: /* SYS_TEST_OSC4 */
! 227: return 0;
! 228: default:
! 229: printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
! 230: return 0;
! 231: }
! 232: }
! 233:
! 234: static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
! 235: uint32_t val)
! 236: {
! 237: vpb_sys_state *s = (vpb_sys_state *)opaque;
! 238: offset -= s->base;
! 239:
! 240: switch (offset) {
! 241: case 0x08: /* LED */
! 242: s->leds = val;
! 243: case 0x0c: /* OSC0 */
! 244: case 0x10: /* OSC1 */
! 245: case 0x14: /* OSC2 */
! 246: case 0x18: /* OSC3 */
! 247: case 0x1c: /* OSC4 */
! 248: /* ??? */
! 249: break;
! 250: case 0x20: /* LOCK */
! 251: if (val == LOCK_VALUE)
! 252: s->lockval = val;
! 253: else
! 254: s->lockval = val & 0x7fff;
! 255: break;
! 256: case 0x28: /* CFGDATA1 */
! 257: /* ??? Need to implement this. */
! 258: s->cfgdata1 = val;
! 259: break;
! 260: case 0x2c: /* CFGDATA2 */
! 261: /* ??? Need to implement this. */
! 262: s->cfgdata2 = val;
! 263: break;
! 264: case 0x30: /* FLAGSSET */
! 265: s->flags |= val;
! 266: break;
! 267: case 0x34: /* FLAGSCLR */
! 268: s->flags &= ~val;
! 269: break;
! 270: case 0x38: /* NVFLAGSSET */
! 271: s->nvflags |= val;
! 272: break;
! 273: case 0x3c: /* NVFLAGSCLR */
! 274: s->nvflags &= ~val;
! 275: break;
! 276: case 0x40: /* RESETCTL */
! 277: if (s->lockval == LOCK_VALUE) {
! 278: s->resetlevel = val;
! 279: if (val & 0x100)
! 280: cpu_abort(cpu_single_env, "Board reset\n");
! 281: }
! 282: break;
! 283: case 0x44: /* PCICTL */
! 284: /* nothing to do. */
! 285: break;
! 286: case 0x4c: /* FLASH */
! 287: case 0x50: /* CLCD */
! 288: case 0x54: /* CLCDSER */
! 289: case 0x64: /* DMAPSR0 */
! 290: case 0x68: /* DMAPSR1 */
! 291: case 0x6c: /* DMAPSR2 */
! 292: case 0x8c: /* OSCRESET0 */
! 293: case 0x90: /* OSCRESET1 */
! 294: case 0x94: /* OSCRESET2 */
! 295: case 0x98: /* OSCRESET3 */
! 296: case 0x9c: /* OSCRESET4 */
! 297: break;
! 298: default:
! 299: printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
! 300: return;
! 301: }
! 302: }
! 303:
! 304: static CPUReadMemoryFunc *vpb_sys_readfn[] = {
! 305: vpb_sys_read,
! 306: vpb_sys_read,
! 307: vpb_sys_read
! 308: };
! 309:
! 310: static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
! 311: vpb_sys_write,
! 312: vpb_sys_write,
! 313: vpb_sys_write
! 314: };
! 315:
! 316: static vpb_sys_state *vpb_sys_init(uint32_t base)
! 317: {
! 318: vpb_sys_state *s;
! 319: int iomemtype;
! 320:
! 321: s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
! 322: if (!s)
! 323: return NULL;
! 324: s->base = base;
! 325: iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
! 326: vpb_sys_writefn, s);
! 327: cpu_register_physical_memory(base, 0x00000fff, iomemtype);
! 328: /* ??? Save/restore. */
! 329: return s;
! 330: }
! 331:
1.1 root 332: /* Board init. */
333:
334: /* The AB and PB boards both use the same core, just with different
335: peripherans and expansion busses. For now we emulate a subset of the
336: PB peripherals and just change the board ID. */
337:
338: static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
339: DisplayState *ds, const char **fd_filename, int snapshot,
340: const char *kernel_filename, const char *kernel_cmdline,
341: const char *initrd_filename, int board_id)
342: {
343: CPUState *env;
344: void *pic;
345: void *sic;
1.1.1.2 ! root 346: void *scsi_hba;
! 347: PCIBus *pci_bus;
! 348: NICInfo *nd;
! 349: int n;
! 350: int done_smc = 0;
1.1 root 351:
352: env = cpu_init();
353: cpu_arm_set_model(env, ARM_CPUID_ARM926);
354: /* ??? RAM shoud repeat to fill physical memory space. */
355: /* SDRAM at address zero. */
356: cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
357:
1.1.1.2 ! root 358: vpb_sys_init(0x10000000);
1.1 root 359: pic = arm_pic_init_cpu(env);
360: pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
361: sic = vpb_sic_init(0x10003000, pic, 31);
362: pl050_init(0x10006000, sic, 3, 0);
363: pl050_init(0x10007000, sic, 4, 1);
364:
1.1.1.2 ! root 365: pci_bus = pci_vpb_init(sic);
! 366: /* The Versatile PCI bridge does not provide access to PCI IO space,
! 367: so many of the qemu PCI devices are not useable. */
! 368: for(n = 0; n < nb_nics; n++) {
! 369: nd = &nd_table[n];
! 370: if (!nd->model)
! 371: nd->model = done_smc ? "rtl8139" : "smc91c111";
! 372: if (strcmp(nd->model, "smc91c111") == 0) {
! 373: smc91c111_init(nd, 0x10010000, sic, 25);
1.1 root 374: } else {
1.1.1.2 ! root 375: pci_nic_init(pci_bus, nd);
! 376: }
! 377: }
! 378: if (usb_enabled) {
! 379: usb_ohci_init(pci_bus, 3, -1);
! 380: }
! 381: scsi_hba = lsi_scsi_init(pci_bus, -1);
! 382: for (n = 0; n < MAX_DISKS; n++) {
! 383: if (bs_table[n]) {
! 384: lsi_scsi_attach(scsi_hba, bs_table[n], n);
1.1 root 385: }
386: }
387:
388: pl011_init(0x101f1000, pic, 12, serial_hds[0]);
389: pl011_init(0x101f2000, pic, 13, serial_hds[1]);
390: pl011_init(0x101f3000, pic, 14, serial_hds[2]);
391: pl011_init(0x10009000, sic, 6, serial_hds[3]);
392:
393: pl080_init(0x10130000, pic, 17);
394: sp804_init(0x101e2000, pic, 4);
395: sp804_init(0x101e3000, pic, 5);
396:
397: /* The versatile/PB actually has a modified Color LCD controller
398: that includes hardware cursor support from the PL111. */
399: pl110_init(ds, 0x10120000, pic, 16, 1);
400:
401: /* Memory map for Versatile/PB: */
402: /* 0x10000000 System registers. */
403: /* 0x10001000 PCI controller config registers. */
404: /* 0x10002000 Serial bus interface. */
405: /* 0x10003000 Secondary interrupt controller. */
406: /* 0x10004000 AACI (audio). */
407: /* 0x10005000 MMCI0. */
408: /* 0x10006000 KMI0 (keyboard). */
409: /* 0x10007000 KMI1 (mouse). */
410: /* 0x10008000 Character LCD Interface. */
411: /* 0x10009000 UART3. */
412: /* 0x1000a000 Smart card 1. */
413: /* 0x1000b000 MMCI1. */
414: /* 0x10010000 Ethernet. */
415: /* 0x10020000 USB. */
416: /* 0x10100000 SSMC. */
417: /* 0x10110000 MPMC. */
418: /* 0x10120000 CLCD Controller. */
419: /* 0x10130000 DMA Controller. */
420: /* 0x10140000 Vectored interrupt controller. */
421: /* 0x101d0000 AHB Monitor Interface. */
422: /* 0x101e0000 System Controller. */
423: /* 0x101e1000 Watchdog Interface. */
424: /* 0x101e2000 Timer 0/1. */
425: /* 0x101e3000 Timer 2/3. */
426: /* 0x101e4000 GPIO port 0. */
427: /* 0x101e5000 GPIO port 1. */
428: /* 0x101e6000 GPIO port 2. */
429: /* 0x101e7000 GPIO port 3. */
430: /* 0x101e8000 RTC. */
431: /* 0x101f0000 Smart card 0. */
432: /* 0x101f1000 UART0. */
433: /* 0x101f2000 UART1. */
434: /* 0x101f3000 UART2. */
435: /* 0x101f4000 SSPI. */
436:
437: arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
438: initrd_filename, board_id);
439: }
440:
441: static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
442: DisplayState *ds, const char **fd_filename, int snapshot,
443: const char *kernel_filename, const char *kernel_cmdline,
444: const char *initrd_filename)
445: {
446: versatile_init(ram_size, vga_ram_size, boot_device,
447: ds, fd_filename, snapshot,
448: kernel_filename, kernel_cmdline,
449: initrd_filename, 0x183);
450: }
451:
452: static void vab_init(int ram_size, int vga_ram_size, int boot_device,
453: DisplayState *ds, const char **fd_filename, int snapshot,
454: const char *kernel_filename, const char *kernel_cmdline,
455: const char *initrd_filename)
456: {
457: versatile_init(ram_size, vga_ram_size, boot_device,
458: ds, fd_filename, snapshot,
459: kernel_filename, kernel_cmdline,
460: initrd_filename, 0x25e);
461: }
462:
463: QEMUMachine versatilepb_machine = {
464: "versatilepb",
465: "ARM Versatile/PB (ARM926EJ-S)",
466: vpb_init,
467: };
468:
469: QEMUMachine versatileab_machine = {
470: "versatileab",
471: "ARM Versatile/AB (ARM926EJ-S)",
472: vab_init,
473: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.