versatilepb.c 13.3 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
 */

P
Peter Maydell 已提交
10
#include "qemu/osdep.h"
11
#include "qapi/error.h"
12 13
#include "qemu-common.h"
#include "cpu.h"
14
#include "hw/sysbus.h"
15 16
#include "hw/arm/arm.h"
#include "hw/devices.h"
P
Paolo Bonzini 已提交
17
#include "net/net.h"
18
#include "sysemu/sysemu.h"
19
#include "hw/pci/pci.h"
P
Paolo Bonzini 已提交
20
#include "hw/i2c/i2c.h"
21
#include "hw/boards.h"
22
#include "sysemu/block-backend.h"
23
#include "exec/address-spaces.h"
P
Paolo Bonzini 已提交
24
#include "hw/block/flash.h"
25
#include "qemu/error-report.h"
26 27 28 29

#define VERSATILE_FLASH_ADDR 0x34000000
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
30 31 32

/* Primary interrupt controller.  */

33 34 35 36 37 38 39 40 41 42 43 44 45
#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;
46 47
} vpb_sic_state;

P
Peter Maydell 已提交
48 49 50 51 52 53 54 55 56 57 58 59
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()
    }
};

60 61 62 63 64
static void vpb_sic_update(vpb_sic_state *s)
{
    uint32_t flags;

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

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

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 已提交
89
        qemu_set_irq(s->parent[irq], level);
90 91 92
    vpb_sic_update(s);
}

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

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

A
Avi Kivity 已提交
150 151 152 153
static const MemoryRegionOps vpb_sic_ops = {
    .read = vpb_sic_read,
    .write = vpb_sic_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
154 155
};

156
static int vpb_sic_init(SysBusDevice *sbd)
157
{
158 159
    DeviceState *dev = DEVICE(sbd);
    vpb_sic_state *s = VERSATILE_PB_SIC(dev);
P
Paul Brook 已提交
160
    int i;
161

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

/* Board init.  */

175
/* The AB and PB boards both use the same core, just with different
176
   peripherals and expansion busses.  For now we emulate a subset of the
177
   PB peripherals and just change the board ID.  */
178

179 180
static struct arm_boot_info versatile_binfo;

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

200 201
    if (!machine->cpu_model) {
        machine->cpu_model = "arm926";
202
    }
203 204 205

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

    cpuobj = object_new(object_class_get_name(cpu_oc));

212 213 214 215 216
    /* 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)) {
217
        object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
218 219
    }

220
    object_property_set_bool(cpuobj, true, "realized", &error_fatal);
221 222 223

    cpu = ARM_CPU(cpuobj);

224 225
    memory_region_allocate_system_memory(ram, NULL, "versatile.ram",
                                         machine->ram_size);
T
ths 已提交
226
    /* ??? RAM should repeat to fill physical memory space.  */
227
    /* SDRAM at address zero.  */
A
Avi Kivity 已提交
228
    memory_region_add_subregion(sysmem, 0, ram);
229

230 231 232
    sysctl = qdev_create(NULL, "realview_sysctl");
    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
233
    qdev_init_nofail(sysctl);
234
    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
235

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

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

252
    dev = qdev_create(NULL, "versatile_pci");
253
    busdev = SYS_BUS_DEVICE(dev);
254
    qdev_init_nofail(dev);
255 256 257 258
    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 */
259 260 261
    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 */
262 263 264 265
    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 已提交
266
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
267

P
pbrook 已提交
268 269
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
270

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

P
Paul Brook 已提交
287 288 289 290
    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]);
291

P
Paul Brook 已提交
292
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
293 294
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
295

296 297 298 299 300
    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]);

301 302
    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
303 304 305
    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));
306

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

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

313
    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
A
Andreas Färber 已提交
314
    i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
315 316
    i2c_create_slave(i2c, "ds1338", 0x68);

317 318 319 320
    /* 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);
321 322
    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
323

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

    dinfo = drive_get(IF_PFLASH, 0, 0);
    if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
363
                          VERSATILE_FLASH_SIZE,
364
                          dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
365 366 367 368 369
                          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");
    }
370

371 372 373 374
    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;
375
    versatile_binfo.board_id = board_id;
376
    arm_load_kernel(cpu, &versatile_binfo);
377 378
}

379
static void vpb_init(MachineState *machine)
380
{
381
    versatile_init(machine, 0x183);
382 383
}

384
static void vab_init(MachineState *machine)
385
{
386
    versatile_init(machine, 0x25e);
387 388
}

389
static void versatilepb_class_init(ObjectClass *oc, void *data)
390
{
391 392
    MachineClass *mc = MACHINE_CLASS(oc);

393 394 395 396
    mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
    mc->init = vpb_init;
    mc->block_default_type = IF_SCSI;
}
397

398 399 400 401 402
static const TypeInfo versatilepb_type = {
    .name = MACHINE_TYPE_NAME("versatilepb"),
    .parent = TYPE_MACHINE,
    .class_init = versatilepb_class_init,
};
P
Paul Brook 已提交
403

404
static void versatileab_class_init(ObjectClass *oc, void *data)
405
{
406 407
    MachineClass *mc = MACHINE_CLASS(oc);

408 409 410
    mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
    mc->init = vab_init;
    mc->block_default_type = IF_SCSI;
411 412
}

413 414 415 416 417 418 419 420 421 422 423 424
static const TypeInfo versatileab_type = {
    .name = MACHINE_TYPE_NAME("versatileab"),
    .parent = TYPE_MACHINE,
    .class_init = versatileab_class_init,
};

static void versatile_machine_init(void)
{
    type_register_static(&versatilepb_type);
    type_register_static(&versatileab_type);
}

425
type_init(versatile_machine_init)
426

427 428
static void vpb_sic_class_init(ObjectClass *klass, void *data)
{
429
    DeviceClass *dc = DEVICE_CLASS(klass);
430 431 432
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = vpb_sic_init;
433
    dc->vmsd = &vmstate_vpb_sic;
434 435
}

436
static const TypeInfo vpb_sic_info = {
437
    .name          = TYPE_VERSATILE_PB_SIC,
438 439 440
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(vpb_sic_state),
    .class_init    = vpb_sic_class_init,
P
Peter Maydell 已提交
441 442
};

A
Andreas Färber 已提交
443
static void versatilepb_register_types(void)
P
Paul Brook 已提交
444
{
445
    type_register_static(&vpb_sic_info);
P
Paul Brook 已提交
446 447
}

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