versatilepb.c 11.9 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;
A
Avi Kivity 已提交
157
    memory_region_init_io(&s->iomem, &vpb_sic_ops, s, "vpb-sic", 0x1000);
158
    sysbus_init_mmio(dev, &s->iomem);
159
    return 0;
160 161 162 163
}

/* Board init.  */

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

168 169
static struct arm_boot_info versatile_binfo;

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

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

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

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

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

224
    dev = qdev_create(NULL, "versatile_pci");
225
    busdev = SYS_BUS_DEVICE(dev);
226
    qdev_init_nofail(dev);
227 228 229 230
    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 */
231 232 233 234
    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 已提交
235
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
236

P
pbrook 已提交
237 238
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
239

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

P
Paul Brook 已提交
256 257 258 259
    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]);
260

P
Paul Brook 已提交
261
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
262 263
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
264

265 266 267 268 269
    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]);

270 271
    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
272 273 274
    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));
275

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

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

282 283 284 285
    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
    i2c_create_slave(i2c, "ds1338", 0x68);

286 287 288 289
    /* 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);
290 291
    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
292

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

339 340 341 342
    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;
343
    versatile_binfo.board_id = board_id;
344
    arm_load_kernel(cpu, &versatile_binfo);
345 346
}

347
static void vpb_init(QEMUMachineInitArgs *args)
348
{
349
    versatile_init(args, 0x183);
350 351
}

352
static void vab_init(QEMUMachineInitArgs *args)
353
{
354
    versatile_init(args, 0x25e);
355 356
}

357
static QEMUMachine versatilepb_machine = {
358 359 360
    .name = "versatilepb",
    .desc = "ARM Versatile/PB (ARM926EJ-S)",
    .init = vpb_init,
361
    .block_default_type = IF_SCSI,
362
    DEFAULT_MACHINE_OPTIONS,
363
};
364

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

373 374 375 376 377 378 379 380
static void versatile_machine_init(void)
{
    qemu_register_machine(&versatilepb_machine);
    qemu_register_machine(&versatileab_machine);
}

machine_init(versatile_machine_init);

381 382
static void vpb_sic_class_init(ObjectClass *klass, void *data)
{
383
    DeviceClass *dc = DEVICE_CLASS(klass);
384 385 386
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = vpb_sic_init;
387 388
    dc->no_user = 1;
    dc->vmsd = &vmstate_vpb_sic;
389 390
}

391
static const TypeInfo vpb_sic_info = {
392 393 394 395
    .name          = "versatilepb_sic",
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(vpb_sic_state),
    .class_init    = vpb_sic_class_init,
P
Peter Maydell 已提交
396 397
};

A
Andreas Färber 已提交
398
static void versatilepb_register_types(void)
P
Paul Brook 已提交
399
{
400
    type_register_static(&vpb_sic_info);
P
Paul Brook 已提交
401 402
}

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