versatilepb.c 13.7 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"
X
xiaoqiang zhao 已提交
26
#include "hw/char/pl011.h"
27 28 29 30

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

/* Primary interrupt controller.  */

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

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

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

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

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

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

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

A
Avi Kivity 已提交
116
static void vpb_sic_write(void *opaque, hwaddr offset,
A
Avi Kivity 已提交
117
                          uint64_t value, unsigned size)
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 144
{
    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 已提交
145
        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
146 147 148 149 150
        return;
    }
    vpb_sic_update(s);
}

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

X
xiaoqiang.zhao 已提交
157
static void vpb_sic_init(Object *obj)
158
{
X
xiaoqiang.zhao 已提交
159 160 161
    DeviceState *dev = DEVICE(obj);
    vpb_sic_state *s = VERSATILE_PB_SIC(obj);
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
P
Paul Brook 已提交
162
    int i;
163

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

/* Board init.  */

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

180 181
static struct arm_boot_info versatile_binfo;

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

201 202 203 204 205 206 207 208 209
    if (machine->ram_size > 0x10000000) {
        /* Device starting at address 0x10000000,
         * and memory cannot overlap with devices.
         * Refuse to run rather than behaving very confusingly.
         */
        error_report("versatilepb: memory size must not exceed 256MB");
        exit(1);
    }

210 211
    if (!machine->cpu_model) {
        machine->cpu_model = "arm926";
212
    }
213 214 215

    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
    if (!cpu_oc) {
B
bellard 已提交
216 217 218
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }
219 220 221

    cpuobj = object_new(object_class_get_name(cpu_oc));

222 223 224 225 226
    /* 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)) {
227
        object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
228 229
    }

230
    object_property_set_bool(cpuobj, true, "realized", &error_fatal);
231 232 233

    cpu = ARM_CPU(cpuobj);

234 235
    memory_region_allocate_system_memory(ram, NULL, "versatile.ram",
                                         machine->ram_size);
T
ths 已提交
236
    /* ??? RAM should repeat to fill physical memory space.  */
237
    /* SDRAM at address zero.  */
A
Avi Kivity 已提交
238
    memory_region_add_subregion(sysmem, 0, ram);
239

240 241 242
    sysctl = qdev_create(NULL, "realview_sysctl");
    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
243
    qdev_init_nofail(sysctl);
244
    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
245

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

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

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

P
pbrook 已提交
278 279
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
280

281
        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
P
pbrook 已提交
282
            smc91c111_init(nd, 0x10010000, sic[25]);
283
            done_smc = 1;
284
        } else {
285
            pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
286 287
        }
    }
E
Eduardo Habkost 已提交
288
    if (machine_usb(machine)) {
289
        pci_create_simple(pci_bus, -1, "pci-ohci");
P
pbrook 已提交
290
    }
P
Paul Brook 已提交
291 292
    n = drive_get_max_bus(IF_SCSI);
    while (n >= 0) {
293
        lsi53c895a_create(pci_bus);
P
Paul Brook 已提交
294
        n--;
P
pbrook 已提交
295
    }
296

X
xiaoqiang zhao 已提交
297 298 299 300
    pl011_create(0x101f1000, pic[12], serial_hds[0]);
    pl011_create(0x101f2000, pic[13], serial_hds[1]);
    pl011_create(0x101f3000, pic[14], serial_hds[2]);
    pl011_create(0x10009000, sic[6], serial_hds[3]);
301

P
Paul Brook 已提交
302
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
303 304
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
305

306 307 308 309 310
    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]);

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

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

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

323
    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
A
Andreas Färber 已提交
324
    i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
325 326
    i2c_create_slave(i2c, "ds1338", 0x68);

327 328 329 330
    /* 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);
331 332
    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
333

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

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

381 382 383 384
    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;
385
    versatile_binfo.board_id = board_id;
386
    arm_load_kernel(cpu, &versatile_binfo);
387 388
}

389
static void vpb_init(MachineState *machine)
390
{
391
    versatile_init(machine, 0x183);
392 393
}

394
static void vab_init(MachineState *machine)
395
{
396
    versatile_init(machine, 0x25e);
397 398
}

399
static void versatilepb_class_init(ObjectClass *oc, void *data)
400
{
401 402
    MachineClass *mc = MACHINE_CLASS(oc);

403 404 405
    mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
    mc->init = vpb_init;
    mc->block_default_type = IF_SCSI;
406
    mc->ignore_memory_transaction_failures = true;
407
}
408

409 410 411 412 413
static const TypeInfo versatilepb_type = {
    .name = MACHINE_TYPE_NAME("versatilepb"),
    .parent = TYPE_MACHINE,
    .class_init = versatilepb_class_init,
};
P
Paul Brook 已提交
414

415
static void versatileab_class_init(ObjectClass *oc, void *data)
416
{
417 418
    MachineClass *mc = MACHINE_CLASS(oc);

419 420 421
    mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
    mc->init = vab_init;
    mc->block_default_type = IF_SCSI;
422
    mc->ignore_memory_transaction_failures = true;
423 424
}

425 426 427 428 429 430 431 432 433 434 435 436
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);
}

437
type_init(versatile_machine_init)
438

439 440
static void vpb_sic_class_init(ObjectClass *klass, void *data)
{
441
    DeviceClass *dc = DEVICE_CLASS(klass);
442

443
    dc->vmsd = &vmstate_vpb_sic;
444 445
}

446
static const TypeInfo vpb_sic_info = {
447
    .name          = TYPE_VERSATILE_PB_SIC,
448 449
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(vpb_sic_state),
X
xiaoqiang.zhao 已提交
450
    .instance_init = vpb_sic_init,
451
    .class_init    = vpb_sic_class_init,
P
Peter Maydell 已提交
452 453
};

A
Andreas Färber 已提交
454
static void versatilepb_register_types(void)
P
Paul Brook 已提交
455
{
456
    type_register_static(&vpb_sic_info);
P
Paul Brook 已提交
457 458
}

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