versatilepb.c 12.2 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

/* Primary interrupt controller.  */

28 29 30 31 32 33 34 35 36 37 38 39 40
#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;
41 42
} vpb_sic_state;

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

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

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

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

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

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

A
Avi Kivity 已提交
110
static void vpb_sic_write(void *opaque, hwaddr offset,
A
Avi Kivity 已提交
111
                          uint64_t value, unsigned size)
112 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
{
    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 已提交
139
        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
140 141 142 143 144
        return;
    }
    vpb_sic_update(s);
}

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

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

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

/* Board init.  */

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

174 175
static struct arm_boot_info versatile_binfo;

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

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

207 208 209
    sysctl = qdev_create(NULL, "realview_sysctl");
    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
210
    qdev_init_nofail(sysctl);
211
    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
212

P
Paul Brook 已提交
213
    dev = sysbus_create_varargs("pl190", 0x10140000,
214 215 216
                                qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
                                qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
                                NULL);
P
Paul Brook 已提交
217
    for (n = 0; n < 32; n++) {
P
Paul Brook 已提交
218
        pic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
219
    }
220
    dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL);
P
Paul Brook 已提交
221
    for (n = 0; n < 32; n++) {
222
        sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
P
Paul Brook 已提交
223
        sic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
224
    }
P
Paul Brook 已提交
225 226 227

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

229
    dev = qdev_create(NULL, "versatile_pci");
230
    busdev = SYS_BUS_DEVICE(dev);
231
    qdev_init_nofail(dev);
232 233 234 235
    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 */
236 237 238
    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 */
239 240 241 242
    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 已提交
243
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
244

P
pbrook 已提交
245 246
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
247

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

P
Paul Brook 已提交
264 265 266 267
    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]);
268

P
Paul Brook 已提交
269
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
270 271
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
272

273 274 275 276 277
    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]);

278 279
    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
280 281 282
    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));
283

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

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

290 291 292 293
    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
    i2c_create_slave(i2c, "ds1338", 0x68);

294 295 296 297
    /* 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);
298 299
    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
300

301
    /* Memory map for Versatile/PB:  */
302 303 304 305 306
    /* 0x10000000 System registers.  */
    /* 0x10001000 PCI controller config registers.  */
    /* 0x10002000 Serial bus interface.  */
    /*  0x10003000 Secondary interrupt controller.  */
    /* 0x10004000 AACI (audio).  */
307
    /*  0x10005000 MMCI0.  */
308 309 310 311 312
    /*  0x10006000 KMI0 (keyboard).  */
    /*  0x10007000 KMI1 (mouse).  */
    /* 0x10008000 Character LCD Interface.  */
    /*  0x10009000 UART3.  */
    /* 0x1000a000 Smart card 1.  */
313
    /*  0x1000b000 MMCI1.  */
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    /*  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.  */
336 337 338 339 340 341 342 343 344 345
    /* 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");
    }
346

347 348 349 350
    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;
351
    versatile_binfo.board_id = board_id;
352
    arm_load_kernel(cpu, &versatile_binfo);
353 354
}

355
static void vpb_init(QEMUMachineInitArgs *args)
356
{
357
    versatile_init(args, 0x183);
358 359
}

360
static void vab_init(QEMUMachineInitArgs *args)
361
{
362
    versatile_init(args, 0x25e);
363 364
}

365
static QEMUMachine versatilepb_machine = {
366 367 368
    .name = "versatilepb",
    .desc = "ARM Versatile/PB (ARM926EJ-S)",
    .init = vpb_init,
369
    .block_default_type = IF_SCSI,
370
};
371

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

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

machine_init(versatile_machine_init);

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

    k->init = vpb_sic_init;
393
    dc->vmsd = &vmstate_vpb_sic;
394 395
}

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

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

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