versatilepb.c 13.0 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/block-backend.h"
19
#include "exec/address-spaces.h"
P
Paolo Bonzini 已提交
20
#include "hw/block/flash.h"
21
#include "qemu/error-report.h"
22 23 24 25

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

/* Primary interrupt controller.  */

29 30 31 32 33 34 35 36 37 38 39 40 41
#define TYPE_VERSATILE_PB_SIC "versatilepb_sic"
#define VERSATILE_PB_SIC(obj) \
    OBJECT_CHECK(vpb_sic_state, (obj), TYPE_VERSATILE_PB_SIC)

typedef struct vpb_sic_state {
    SysBusDevice parent_obj;

    MemoryRegion iomem;
    uint32_t level;
    uint32_t mask;
    uint32_t pic_enable;
    qemu_irq parent[32];
    int irq;
42 43
} vpb_sic_state;

P
Peter Maydell 已提交
44 45 46 47 48 49 50 51 52 53 54 55
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()
    }
};

56 57 58 59 60
static void vpb_sic_update(vpb_sic_state *s)
{
    uint32_t flags;

    flags = s->level & s->mask;
P
pbrook 已提交
61
    qemu_set_irq(s->parent[s->irq], flags != 0);
62 63 64 65 66 67 68 69 70 71 72
}

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 已提交
73
        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
74 75 76 77 78 79 80 81 82 83 84
    }
}

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 已提交
85
        qemu_set_irq(s->parent[irq], level);
86 87 88
    vpb_sic_update(s);
}

A
Avi Kivity 已提交
89
static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
A
Avi Kivity 已提交
90
                             unsigned size)
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
{
    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 已提交
106
        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
107 108 109 110
        return 0;
    }
}

A
Avi Kivity 已提交
111
static void vpb_sic_write(void *opaque, hwaddr offset,
A
Avi Kivity 已提交
112
                          uint64_t value, unsigned size)
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
{
    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 已提交
140
        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
141 142 143 144 145
        return;
    }
    vpb_sic_update(s);
}

A
Avi Kivity 已提交
146 147 148 149
static const MemoryRegionOps vpb_sic_ops = {
    .read = vpb_sic_read,
    .write = vpb_sic_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
150 151
};

152
static int vpb_sic_init(SysBusDevice *sbd)
153
{
154 155
    DeviceState *dev = DEVICE(sbd);
    vpb_sic_state *s = VERSATILE_PB_SIC(dev);
P
Paul Brook 已提交
156
    int i;
157

158
    qdev_init_gpio_in(dev, vpb_sic_set_irq, 32);
P
Paul Brook 已提交
159
    for (i = 0; i < 32; i++) {
160
        sysbus_init_irq(sbd, &s->parent[i]);
P
Paul Brook 已提交
161
    }
P
Paul Brook 已提交
162
    s->irq = 31;
163 164
    memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s,
                          "vpb-sic", 0x1000);
165
    sysbus_init_mmio(sbd, &s->iomem);
166
    return 0;
167 168 169 170
}

/* Board init.  */

171
/* The AB and PB boards both use the same core, just with different
172
   peripherals and expansion busses.  For now we emulate a subset of the
173
   PB peripherals and just change the board ID.  */
174

175 176
static struct arm_boot_info versatile_binfo;

177
static void versatile_init(MachineState *machine, int board_id)
178
{
179 180
    ObjectClass *cpu_oc;
    Object *cpuobj;
181
    ARMCPU *cpu;
A
Avi Kivity 已提交
182 183
    MemoryRegion *sysmem = get_system_memory();
    MemoryRegion *ram = g_new(MemoryRegion, 1);
P
Paul Brook 已提交
184
    qemu_irq pic[32];
P
Paul Brook 已提交
185
    qemu_irq sic[32];
186
    DeviceState *dev, *sysctl;
187
    SysBusDevice *busdev;
188
    DeviceState *pl041;
P
pbrook 已提交
189 190
    PCIBus *pci_bus;
    NICInfo *nd;
A
Andreas Färber 已提交
191
    I2CBus *i2c;
P
pbrook 已提交
192 193
    int n;
    int done_smc = 0;
194
    DriveInfo *dinfo;
195
    Error *err = NULL;
196

197 198
    if (!machine->cpu_model) {
        machine->cpu_model = "arm926";
199
    }
200 201 202

    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
    if (!cpu_oc) {
B
bellard 已提交
203 204 205
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }
206 207 208

    cpuobj = object_new(object_class_get_name(cpu_oc));

209 210 211 212 213 214 215
    /* By default ARM1176 CPUs have EL3 enabled.  This board does not
     * currently support EL3 so the CPU EL3 property is disabled before
     * realization.
     */
    if (object_property_find(cpuobj, "has_el3", NULL)) {
        object_property_set_bool(cpuobj, false, "has_el3", &err);
        if (err) {
216
            error_report_err(err);
217 218 219 220
            exit(1);
        }
    }

221 222
    object_property_set_bool(cpuobj, true, "realized", &err);
    if (err) {
223
        error_report_err(err);
224 225 226 227 228
        exit(1);
    }

    cpu = ARM_CPU(cpuobj);

229 230
    memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
                           &error_abort);
231
    vmstate_register_ram_global(ram);
T
ths 已提交
232
    /* ??? RAM should repeat to fill physical memory space.  */
233
    /* SDRAM at address zero.  */
A
Avi Kivity 已提交
234
    memory_region_add_subregion(sysmem, 0, ram);
235

236 237 238
    sysctl = qdev_create(NULL, "realview_sysctl");
    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
239
    qdev_init_nofail(sysctl);
240
    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
241

P
Paul Brook 已提交
242
    dev = sysbus_create_varargs("pl190", 0x10140000,
243 244 245
                                qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
                                qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
                                NULL);
P
Paul Brook 已提交
246
    for (n = 0; n < 32; n++) {
P
Paul Brook 已提交
247
        pic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
248
    }
249
    dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL);
P
Paul Brook 已提交
250
    for (n = 0; n < 32; n++) {
251
        sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
P
Paul Brook 已提交
252
        sic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
253
    }
P
Paul Brook 已提交
254 255 256

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

258
    dev = qdev_create(NULL, "versatile_pci");
259
    busdev = SYS_BUS_DEVICE(dev);
260
    qdev_init_nofail(dev);
261 262 263 264
    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 */
265 266 267
    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 */
268 269 270 271
    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 已提交
272
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
273

P
pbrook 已提交
274 275
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
276

277
        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
P
pbrook 已提交
278
            smc91c111_init(nd, 0x10010000, sic[25]);
279
            done_smc = 1;
280
        } else {
281
            pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
282 283
        }
    }
284
    if (usb_enabled()) {
285
        pci_create_simple(pci_bus, -1, "pci-ohci");
P
pbrook 已提交
286
    }
P
Paul Brook 已提交
287 288 289 290
    n = drive_get_max_bus(IF_SCSI);
    while (n >= 0) {
        pci_create_simple(pci_bus, -1, "lsi53c895a");
        n--;
P
pbrook 已提交
291
    }
292

P
Paul Brook 已提交
293 294 295 296
    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]);
297

P
Paul Brook 已提交
298
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
299 300
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
301

302 303 304 305 306
    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]);

307 308
    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
309 310 311
    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));
312

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

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

319
    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
A
Andreas Färber 已提交
320
    i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
321 322
    i2c_create_slave(i2c, "ds1338", 0x68);

323 324 325 326
    /* 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);
327 328
    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
329

330
    /* Memory map for Versatile/PB:  */
331 332 333 334 335
    /* 0x10000000 System registers.  */
    /* 0x10001000 PCI controller config registers.  */
    /* 0x10002000 Serial bus interface.  */
    /*  0x10003000 Secondary interrupt controller.  */
    /* 0x10004000 AACI (audio).  */
336
    /*  0x10005000 MMCI0.  */
337 338 339 340 341
    /*  0x10006000 KMI0 (keyboard).  */
    /*  0x10007000 KMI1 (mouse).  */
    /* 0x10008000 Character LCD Interface.  */
    /*  0x10009000 UART3.  */
    /* 0x1000a000 Smart card 1.  */
342
    /*  0x1000b000 MMCI1.  */
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
    /*  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.  */
365 366 367 368
    /* 0x34000000 NOR Flash */

    dinfo = drive_get(IF_PFLASH, 0, 0);
    if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
369
                          VERSATILE_FLASH_SIZE,
370
                          dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
371 372 373 374 375
                          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");
    }
376

377 378 379 380
    versatile_binfo.ram_size = machine->ram_size;
    versatile_binfo.kernel_filename = machine->kernel_filename;
    versatile_binfo.kernel_cmdline = machine->kernel_cmdline;
    versatile_binfo.initrd_filename = machine->initrd_filename;
381
    versatile_binfo.board_id = board_id;
382
    arm_load_kernel(cpu, &versatile_binfo);
383 384
}

385
static void vpb_init(MachineState *machine)
386
{
387
    versatile_init(machine, 0x183);
388 389
}

390
static void vab_init(MachineState *machine)
391
{
392
    versatile_init(machine, 0x25e);
393 394
}

395
static QEMUMachine versatilepb_machine = {
396 397 398
    .name = "versatilepb",
    .desc = "ARM Versatile/PB (ARM926EJ-S)",
    .init = vpb_init,
399
    .block_default_type = IF_SCSI,
400
};
401

402
static QEMUMachine versatileab_machine = {
403 404 405
    .name = "versatileab",
    .desc = "ARM Versatile/AB (ARM926EJ-S)",
    .init = vab_init,
406
    .block_default_type = IF_SCSI,
407
};
P
Paul Brook 已提交
408

409 410 411 412 413 414 415 416
static void versatile_machine_init(void)
{
    qemu_register_machine(&versatilepb_machine);
    qemu_register_machine(&versatileab_machine);
}

machine_init(versatile_machine_init);

417 418
static void vpb_sic_class_init(ObjectClass *klass, void *data)
{
419
    DeviceClass *dc = DEVICE_CLASS(klass);
420 421 422
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = vpb_sic_init;
423
    dc->vmsd = &vmstate_vpb_sic;
424 425
}

426
static const TypeInfo vpb_sic_info = {
427
    .name          = TYPE_VERSATILE_PB_SIC,
428 429 430
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(vpb_sic_state),
    .class_init    = vpb_sic_class_init,
P
Peter Maydell 已提交
431 432
};

A
Andreas Färber 已提交
433
static void versatilepb_register_types(void)
P
Paul Brook 已提交
434
{
435
    type_register_static(&vpb_sic_info);
P
Paul Brook 已提交
436 437
}

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