diff options
Diffstat (limited to 'hw/versatilepb.c')
-rw-r--r-- | hw/versatilepb.c | 206 |
1 files changed, 199 insertions, 7 deletions
diff --git a/hw/versatilepb.c b/hw/versatilepb.c index e198a518ea..8a821d42d6 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -10,6 +10,8 @@ #include "vl.h" #include "arm_pic.h" +#define LOCK_VALUE 0xa05f + /* Primary interrupt controller. */ typedef struct vpb_sic_state @@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) return s; } +/* System controller. */ + +typedef struct { + uint32_t base; + uint32_t leds; + uint16_t lockval; + uint32_t cfgdata1; + uint32_t cfgdata2; + uint32_t flags; + uint32_t nvflags; + uint32_t resetlevel; +} vpb_sys_state; + +static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* ID */ + return 0x41007004; + case 0x04: /* SW */ + /* General purpose hardware switches. + We don't have a useful way of exposing these to the user. */ + return 0; + case 0x08: /* LED */ + return s->leds; + case 0x20: /* LOCK */ + return s->lockval; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + case 0x24: /* 100HZ */ + /* ??? Implement these. */ + return 0; + case 0x28: /* CFGDATA1 */ + return s->cfgdata1; + case 0x2c: /* CFGDATA2 */ + return s->cfgdata2; + case 0x30: /* FLAGS */ + return s->flags; + case 0x38: /* NVFLAGS */ + return s->nvflags; + case 0x40: /* RESETCTL */ + return s->resetlevel; + case 0x44: /* PCICTL */ + return 1; + case 0x48: /* MCI */ + return 0; + case 0x4c: /* FLASH */ + return 0; + case 0x50: /* CLCD */ + return 0x1000; + case 0x54: /* CLCDSER */ + return 0; + case 0x58: /* BOOTCS */ + return 0; + case 0x5c: /* 24MHz */ + /* ??? not implemented. */ + return 0; + case 0x60: /* MISC */ + return 0; + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + case 0xc0: /* SYS_TEST_OSC0 */ + case 0xc4: /* SYS_TEST_OSC1 */ + case 0xc8: /* SYS_TEST_OSC2 */ + case 0xcc: /* SYS_TEST_OSC3 */ + case 0xd0: /* SYS_TEST_OSC4 */ + return 0; + default: + printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void vpb_sys_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + offset -= s->base; + + switch (offset) { + case 0x08: /* LED */ + s->leds = val; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + /* ??? */ + break; + case 0x20: /* LOCK */ + if (val == LOCK_VALUE) + s->lockval = val; + else + s->lockval = val & 0x7fff; + break; + case 0x28: /* CFGDATA1 */ + /* ??? Need to implement this. */ + s->cfgdata1 = val; + break; + case 0x2c: /* CFGDATA2 */ + /* ??? Need to implement this. */ + s->cfgdata2 = val; + break; + case 0x30: /* FLAGSSET */ + s->flags |= val; + break; + case 0x34: /* FLAGSCLR */ + s->flags &= ~val; + break; + case 0x38: /* NVFLAGSSET */ + s->nvflags |= val; + break; + case 0x3c: /* NVFLAGSCLR */ + s->nvflags &= ~val; + break; + case 0x40: /* RESETCTL */ + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x100) + cpu_abort(cpu_single_env, "Board reset\n"); + } + break; + case 0x44: /* PCICTL */ + /* nothing to do. */ + break; + case 0x4c: /* FLASH */ + case 0x50: /* CLCD */ + case 0x54: /* CLCDSER */ + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + break; + default: + printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); + return; + } +} + +static CPUReadMemoryFunc *vpb_sys_readfn[] = { + vpb_sys_read, + vpb_sys_read, + vpb_sys_read +}; + +static CPUWriteMemoryFunc *vpb_sys_writefn[] = { + vpb_sys_write, + vpb_sys_write, + vpb_sys_write +}; + +static vpb_sys_state *vpb_sys_init(uint32_t base) +{ + vpb_sys_state *s; + int iomemtype; + + s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); + if (!s) + return NULL; + s->base = base; + iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, + vpb_sys_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ + return s; +} + /* Board init. */ /* The AB and PB boards both use the same core, just with different @@ -159,6 +343,10 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, CPUState *env; void *pic; void *sic; + PCIBus *pci_bus; + NICInfo *nd; + int n; + int done_smc = 0; env = cpu_init(); cpu_arm_set_model(env, ARM_CPUID_ARM926); @@ -166,20 +354,24 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + vpb_sys_init(0x10000000); pic = arm_pic_init_cpu(env); pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); sic = vpb_sic_init(0x10003000, pic, 31); pl050_init(0x10006000, sic, 3, 0); pl050_init(0x10007000, sic, 4, 1); - /* TODO: Init PCI NICs. */ - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0x10010000, sic, 25); + pci_bus = pci_vpb_init(sic); + /* The Versatile PCI bridge does not provide access to PCI IO space, + so many of the qemu PCI devices are not useable. */ + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (!nd->model) + nd->model = done_smc ? "rtl8139" : "smc91c111"; + if (strcmp(nd->model, "smc91c111") == 0) { + smc91c111_init(nd, 0x10010000, sic, 25); } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); + pci_nic_init(pci_bus, nd); } } |