versatilepb.c 12.1 KB
Newer Older
1
/*
2
 * ARM Versatile Platform/Application Baseboard System emulation.
3
 *
4
 * Copyright (c) 2005-2007 CodeSourcery.
5 6
 * Written by Paul Brook
 *
M
Matthew Fernandez 已提交
7
 * This code is licensed under the GPL.
8 9
 */

10
#include "hw/sysbus.h"
11 12
#include "hw/arm/arm.h"
#include "hw/devices.h"
P
Paolo Bonzini 已提交
13
#include "net/net.h"
14
#include "sysemu/sysemu.h"
15
#include "hw/pci/pci.h"
P
Paolo Bonzini 已提交
16
#include "hw/i2c/i2c.h"
17
#include "hw/boards.h"
18
#include "sysemu/blockdev.h"
19
#include "exec/address-spaces.h"
P
Paolo Bonzini 已提交
20
#include "hw/block/flash.h"
21 22 23 24

#define VERSATILE_FLASH_ADDR 0x34000000
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
25 26 27 28 29

/* Primary interrupt controller.  */

typedef struct vpb_sic_state
{
P
Paul Brook 已提交
30
  SysBusDevice busdev;
A
Avi Kivity 已提交
31
  MemoryRegion iomem;
32 33 34
  uint32_t level;
  uint32_t mask;
  uint32_t pic_enable;
P
Paul Brook 已提交
35
  qemu_irq parent[32];
36 37 38
  int irq;
} vpb_sic_state;

P
Peter Maydell 已提交
39 40 41 42 43 44 45 46 47 48 49 50
static const VMStateDescription vmstate_vpb_sic = {
    .name = "versatilepb_sic",
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32(level, vpb_sic_state),
        VMSTATE_UINT32(mask, vpb_sic_state),
        VMSTATE_UINT32(pic_enable, vpb_sic_state),
        VMSTATE_END_OF_LIST()
    }
};

51 52 53 54 55
static void vpb_sic_update(vpb_sic_state *s)
{
    uint32_t flags;

    flags = s->level & s->mask;
P
pbrook 已提交
56
    qemu_set_irq(s->parent[s->irq], flags != 0);
57 58 59 60 61 62 63 64 65 66 67
}

static void vpb_sic_update_pic(vpb_sic_state *s)
{
    int i;
    uint32_t mask;

    for (i = 21; i <= 30; i++) {
        mask = 1u << i;
        if (!(s->pic_enable & mask))
            continue;
P
pbrook 已提交
68
        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
69 70 71 72 73 74 75 76 77 78 79
    }
}

static void vpb_sic_set_irq(void *opaque, int irq, int level)
{
    vpb_sic_state *s = (vpb_sic_state *)opaque;
    if (level)
        s->level |= 1u << irq;
    else
        s->level &= ~(1u << irq);
    if (s->pic_enable & (1u << irq))
P
pbrook 已提交
80
        qemu_set_irq(s->parent[irq], level);
81 82 83
    vpb_sic_update(s);
}

A
Avi Kivity 已提交
84
static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
A
Avi Kivity 已提交
85
                             unsigned size)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
{
    vpb_sic_state *s = (vpb_sic_state *)opaque;

    switch (offset >> 2) {
    case 0: /* STATUS */
        return s->level & s->mask;
    case 1: /* RAWSTAT */
        return s->level;
    case 2: /* ENABLE */
        return s->mask;
    case 4: /* SOFTINT */
        return s->level & 1;
    case 8: /* PICENABLE */
        return s->pic_enable;
    default:
P
pbrook 已提交
101
        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
102 103 104 105
        return 0;
    }
}

A
Avi Kivity 已提交
106
static void vpb_sic_write(void *opaque, hwaddr offset,
A
Avi Kivity 已提交
107
                          uint64_t value, unsigned size)
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
{
    vpb_sic_state *s = (vpb_sic_state *)opaque;

    switch (offset >> 2) {
    case 2: /* ENSET */
        s->mask |= value;
        break;
    case 3: /* ENCLR */
        s->mask &= ~value;
        break;
    case 4: /* SOFTINTSET */
        if (value)
            s->mask |= 1;
        break;
    case 5: /* SOFTINTCLR */
        if (value)
            s->mask &= ~1u;
        break;
    case 8: /* PICENSET */
        s->pic_enable |= (value & 0x7fe00000);
        vpb_sic_update_pic(s);
        break;
    case 9: /* PICENCLR */
        s->pic_enable &= ~value;
        vpb_sic_update_pic(s);
        break;
    default:
P
pbrook 已提交
135
        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
136 137 138 139 140
        return;
    }
    vpb_sic_update(s);
}

A
Avi Kivity 已提交
141 142 143 144
static const MemoryRegionOps vpb_sic_ops = {
    .read = vpb_sic_read,
    .write = vpb_sic_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
145 146
};

147
static int vpb_sic_init(SysBusDevice *dev)
148
{
P
Paul Brook 已提交
149
    vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev);
P
Paul Brook 已提交
150
    int i;
151

P
Paul Brook 已提交
152
    qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32);
P
Paul Brook 已提交
153
    for (i = 0; i < 32; i++) {
P
Paul Brook 已提交
154
        sysbus_init_irq(dev, &s->parent[i]);
P
Paul Brook 已提交
155
    }
P
Paul Brook 已提交
156
    s->irq = 31;
157 158
    memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s,
                          "vpb-sic", 0x1000);
159
    sysbus_init_mmio(dev, &s->iomem);
160
    return 0;
161 162 163 164
}

/* Board init.  */

165
/* The AB and PB boards both use the same core, just with different
166
   peripherals and expansion busses.  For now we emulate a subset of the
167
   PB peripherals and just change the board ID.  */
168

169 170
static struct arm_boot_info versatile_binfo;

171
static void versatile_init(QEMUMachineInitArgs *args, int board_id)
172
{
173
    ARMCPU *cpu;
A
Avi Kivity 已提交
174 175
    MemoryRegion *sysmem = get_system_memory();
    MemoryRegion *ram = g_new(MemoryRegion, 1);
P
Paul Brook 已提交
176 177
    qemu_irq *cpu_pic;
    qemu_irq pic[32];
P
Paul Brook 已提交
178
    qemu_irq sic[32];
179
    DeviceState *dev, *sysctl;
180
    SysBusDevice *busdev;
181
    DeviceState *pl041;
P
pbrook 已提交
182 183
    PCIBus *pci_bus;
    NICInfo *nd;
184
    i2c_bus *i2c;
P
pbrook 已提交
185 186
    int n;
    int done_smc = 0;
187
    DriveInfo *dinfo;
188

189 190
    if (!args->cpu_model) {
        args->cpu_model = "arm926";
191
    }
192
    cpu = cpu_arm_init(args->cpu_model);
193
    if (!cpu) {
B
bellard 已提交
194 195 196
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }
197
    memory_region_init_ram(ram, NULL, "versatile.ram", args->ram_size);
198
    vmstate_register_ram_global(ram);
T
ths 已提交
199
    /* ??? RAM should repeat to fill physical memory space.  */
200
    /* SDRAM at address zero.  */
A
Avi Kivity 已提交
201
    memory_region_add_subregion(sysmem, 0, ram);
202

203 204 205
    sysctl = qdev_create(NULL, "realview_sysctl");
    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
206
    qdev_init_nofail(sysctl);
207
    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
208

209
    cpu_pic = arm_pic_init_cpu(cpu);
P
Paul Brook 已提交
210
    dev = sysbus_create_varargs("pl190", 0x10140000,
211 212
                                cpu_pic[ARM_PIC_CPU_IRQ],
                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
P
Paul Brook 已提交
213
    for (n = 0; n < 32; n++) {
P
Paul Brook 已提交
214
        pic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
215
    }
P
Paul Brook 已提交
216 217
    dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
    for (n = 0; n < 32; n++) {
218
        sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
P
Paul Brook 已提交
219
        sic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
220
    }
P
Paul Brook 已提交
221 222 223

    sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
    sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
224

225
    dev = qdev_create(NULL, "versatile_pci");
226
    busdev = SYS_BUS_DEVICE(dev);
227
    qdev_init_nofail(dev);
228 229 230 231
    sysbus_mmio_map(busdev, 0, 0x10001000); /* PCI controller regs */
    sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */
    sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */
    sysbus_mmio_map(busdev, 3, 0x43000000); /* PCI I/O */
232 233 234
    sysbus_mmio_map(busdev, 4, 0x44000000); /* PCI memory window 1 */
    sysbus_mmio_map(busdev, 5, 0x50000000); /* PCI memory window 2 */
    sysbus_mmio_map(busdev, 6, 0x60000000); /* PCI memory window 3 */
235 236 237 238
    sysbus_connect_irq(busdev, 0, sic[27]);
    sysbus_connect_irq(busdev, 1, sic[28]);
    sysbus_connect_irq(busdev, 2, sic[29]);
    sysbus_connect_irq(busdev, 3, sic[30]);
P
Paul Brook 已提交
239
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
240

P
pbrook 已提交
241 242
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
243

244
        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
P
pbrook 已提交
245
            smc91c111_init(nd, 0x10010000, sic[25]);
246
            done_smc = 1;
247
        } else {
248
            pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
249 250
        }
    }
251
    if (usb_enabled(false)) {
252
        pci_create_simple(pci_bus, -1, "pci-ohci");
P
pbrook 已提交
253
    }
P
Paul Brook 已提交
254 255 256 257
    n = drive_get_max_bus(IF_SCSI);
    while (n >= 0) {
        pci_create_simple(pci_bus, -1, "lsi53c895a");
        n--;
P
pbrook 已提交
258
    }
259

P
Paul Brook 已提交
260 261 262 263
    sysbus_create_simple("pl011", 0x101f1000, pic[12]);
    sysbus_create_simple("pl011", 0x101f2000, pic[13]);
    sysbus_create_simple("pl011", 0x101f3000, pic[14]);
    sysbus_create_simple("pl011", 0x10009000, sic[6]);
264

P
Paul Brook 已提交
265
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
266 267
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
268

269 270 271 272 273
    sysbus_create_simple("pl061", 0x101e4000, pic[6]);
    sysbus_create_simple("pl061", 0x101e5000, pic[7]);
    sysbus_create_simple("pl061", 0x101e6000, pic[8]);
    sysbus_create_simple("pl061", 0x101e7000, pic[9]);

274 275
    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
276 277 278
    dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
    /* Wire up the mux control signals from the SYS_CLCD register */
    qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
279

P
Paul Brook 已提交
280 281
    sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
    sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
282

P
pbrook 已提交
283
    /* Add PL031 Real Time Clock. */
P
Paul Brook 已提交
284
    sysbus_create_simple("pl031", 0x101e8000, pic[10]);
P
pbrook 已提交
285

286 287 288 289
    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
    i2c_create_slave(i2c, "ds1338", 0x68);

290 291 292 293
    /* Add PL041 AACI Interface to the LM4549 codec */
    pl041 = qdev_create(NULL, "pl041");
    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
    qdev_init_nofail(pl041);
294 295
    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
296

297
    /* Memory map for Versatile/PB:  */
298 299 300 301 302
    /* 0x10000000 System registers.  */
    /* 0x10001000 PCI controller config registers.  */
    /* 0x10002000 Serial bus interface.  */
    /*  0x10003000 Secondary interrupt controller.  */
    /* 0x10004000 AACI (audio).  */
303
    /*  0x10005000 MMCI0.  */
304 305 306 307 308
    /*  0x10006000 KMI0 (keyboard).  */
    /*  0x10007000 KMI1 (mouse).  */
    /* 0x10008000 Character LCD Interface.  */
    /*  0x10009000 UART3.  */
    /* 0x1000a000 Smart card 1.  */
309
    /*  0x1000b000 MMCI1.  */
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    /*  0x10010000 Ethernet.  */
    /* 0x10020000 USB.  */
    /* 0x10100000 SSMC.  */
    /* 0x10110000 MPMC.  */
    /*  0x10120000 CLCD Controller.  */
    /*  0x10130000 DMA Controller.  */
    /*  0x10140000 Vectored interrupt controller.  */
    /* 0x101d0000 AHB Monitor Interface.  */
    /* 0x101e0000 System Controller.  */
    /* 0x101e1000 Watchdog Interface.  */
    /* 0x101e2000 Timer 0/1.  */
    /* 0x101e3000 Timer 2/3.  */
    /* 0x101e4000 GPIO port 0.  */
    /* 0x101e5000 GPIO port 1.  */
    /* 0x101e6000 GPIO port 2.  */
    /* 0x101e7000 GPIO port 3.  */
    /* 0x101e8000 RTC.  */
    /* 0x101f0000 Smart card 0.  */
    /*  0x101f1000 UART0.  */
    /*  0x101f2000 UART1.  */
    /*  0x101f3000 UART2.  */
    /* 0x101f4000 SSPI.  */
332 333 334 335 336 337 338 339 340 341
    /* 0x34000000 NOR Flash */

    dinfo = drive_get(IF_PFLASH, 0, 0);
    if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
                          VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
                          VERSATILE_FLASH_SECT_SIZE,
                          VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
                          4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
        fprintf(stderr, "qemu: Error registering flash memory.\n");
    }
342

343 344 345 346
    versatile_binfo.ram_size = args->ram_size;
    versatile_binfo.kernel_filename = args->kernel_filename;
    versatile_binfo.kernel_cmdline = args->kernel_cmdline;
    versatile_binfo.initrd_filename = args->initrd_filename;
347
    versatile_binfo.board_id = board_id;
348
    arm_load_kernel(cpu, &versatile_binfo);
349 350
}

351
static void vpb_init(QEMUMachineInitArgs *args)
352
{
353
    versatile_init(args, 0x183);
354 355
}

356
static void vab_init(QEMUMachineInitArgs *args)
357
{
358
    versatile_init(args, 0x25e);
359 360
}

361
static QEMUMachine versatilepb_machine = {
362 363 364
    .name = "versatilepb",
    .desc = "ARM Versatile/PB (ARM926EJ-S)",
    .init = vpb_init,
365
    .block_default_type = IF_SCSI,
366
    DEFAULT_MACHINE_OPTIONS,
367
};
368

369
static QEMUMachine versatileab_machine = {
370 371 372
    .name = "versatileab",
    .desc = "ARM Versatile/AB (ARM926EJ-S)",
    .init = vab_init,
373
    .block_default_type = IF_SCSI,
374
    DEFAULT_MACHINE_OPTIONS,
375
};
P
Paul Brook 已提交
376

377 378 379 380 381 382 383 384
static void versatile_machine_init(void)
{
    qemu_register_machine(&versatilepb_machine);
    qemu_register_machine(&versatileab_machine);
}

machine_init(versatile_machine_init);

385 386
static void vpb_sic_class_init(ObjectClass *klass, void *data)
{
387
    DeviceClass *dc = DEVICE_CLASS(klass);
388 389 390
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = vpb_sic_init;
391 392
    dc->no_user = 1;
    dc->vmsd = &vmstate_vpb_sic;
393 394
}

395
static const TypeInfo vpb_sic_info = {
396 397 398 399
    .name          = "versatilepb_sic",
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(vpb_sic_state),
    .class_init    = vpb_sic_class_init,
P
Peter Maydell 已提交
400 401
};

A
Andreas Färber 已提交
402
static void versatilepb_register_types(void)
P
Paul Brook 已提交
403
{
404
    type_register_static(&vpb_sic_info);
P
Paul Brook 已提交
405 406
}

A
Andreas Färber 已提交
407
type_init(versatilepb_register_types)