versatilepb.c 10.3 KB
Newer Older
1
/*
2
 * ARM Versatile Platform/Application Baseboard System emulation.
3
 *
4
 * Copyright (c) 2005-2007 CodeSourcery.
5 6 7 8 9
 * Written by Paul Brook
 *
 * This code is licenced under the GPL.
 */

P
Paul Brook 已提交
10
#include "sysbus.h"
P
pbrook 已提交
11 12 13 14 15 16
#include "arm-misc.h"
#include "primecell.h"
#include "devices.h"
#include "net.h"
#include "sysemu.h"
#include "pci.h"
17
#include "usb-ohci.h"
P
pbrook 已提交
18
#include "boards.h"
B
Blue Swirl 已提交
19
#include "blockdev.h"
20 21 22 23 24

/* Primary interrupt controller.  */

typedef struct vpb_sic_state
{
P
Paul Brook 已提交
25
  SysBusDevice busdev;
26 27 28
  uint32_t level;
  uint32_t mask;
  uint32_t pic_enable;
P
Paul Brook 已提交
29
  qemu_irq parent[32];
30 31 32
  int irq;
} vpb_sic_state;

P
Peter Maydell 已提交
33 34 35 36 37 38 39 40 41 42 43 44
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()
    }
};

45 46 47 48 49
static void vpb_sic_update(vpb_sic_state *s)
{
    uint32_t flags;

    flags = s->level & s->mask;
P
pbrook 已提交
50
    qemu_set_irq(s->parent[s->irq], flags != 0);
51 52 53 54 55 56 57 58 59 60 61
}

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 已提交
62
        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
63 64 65 66 67 68 69 70 71 72 73
    }
}

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 已提交
74
        qemu_set_irq(s->parent[irq], level);
75 76 77
    vpb_sic_update(s);
}

A
Anthony Liguori 已提交
78
static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
{
    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 已提交
94
        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
95 96 97 98
        return 0;
    }
}

A
Anthony Liguori 已提交
99
static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
                          uint32_t value)
{
    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 已提交
128
        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
129 130 131 132 133
        return;
    }
    vpb_sic_update(s);
}

134
static CPUReadMemoryFunc * const vpb_sic_readfn[] = {
135 136 137 138 139
   vpb_sic_read,
   vpb_sic_read,
   vpb_sic_read
};

140
static CPUWriteMemoryFunc * const vpb_sic_writefn[] = {
141 142 143 144 145
   vpb_sic_write,
   vpb_sic_write,
   vpb_sic_write
};

146
static int vpb_sic_init(SysBusDevice *dev)
147
{
P
Paul Brook 已提交
148
    vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev);
149
    int iomemtype;
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;
157
    iomemtype = cpu_register_io_memory(vpb_sic_readfn,
158 159
                                       vpb_sic_writefn, s,
                                       DEVICE_NATIVE_ENDIAN);
P
Paul Brook 已提交
160
    sysbus_init_mmio(dev, 0x1000, iomemtype);
161
    return 0;
162 163 164 165
}

/* Board init.  */

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

170 171
static struct arm_boot_info versatile_binfo;

A
Anthony Liguori 已提交
172
static void versatile_init(ram_addr_t ram_size,
173
                     const char *boot_device,
174
                     const char *kernel_filename, const char *kernel_cmdline,
P
pbrook 已提交
175 176
                     const char *initrd_filename, const char *cpu_model,
                     int board_id)
177 178
{
    CPUState *env;
A
Anthony Liguori 已提交
179
    ram_addr_t ram_offset;
P
Paul Brook 已提交
180 181
    qemu_irq *cpu_pic;
    qemu_irq pic[32];
P
Paul Brook 已提交
182
    qemu_irq sic[32];
P
Paul Brook 已提交
183
    DeviceState *dev;
P
pbrook 已提交
184 185 186 187
    PCIBus *pci_bus;
    NICInfo *nd;
    int n;
    int done_smc = 0;
188

P
pbrook 已提交
189 190
    if (!cpu_model)
        cpu_model = "arm926";
B
bellard 已提交
191 192 193 194 195
    env = cpu_init(cpu_model);
    if (!env) {
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }
196
    ram_offset = qemu_ram_alloc(NULL, "versatile.ram", ram_size);
T
ths 已提交
197
    /* ??? RAM should repeat to fill physical memory space.  */
198
    /* SDRAM at address zero.  */
P
pbrook 已提交
199
    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
200

P
Paul Brook 已提交
201
    arm_sysctl_init(0x10000000, 0x41007004, 0x02000000);
P
Paul Brook 已提交
202 203 204 205
    cpu_pic = arm_pic_init_cpu(env);
    dev = sysbus_create_varargs("pl190", 0x10140000,
                                cpu_pic[0], cpu_pic[1], NULL);
    for (n = 0; n < 32; n++) {
P
Paul Brook 已提交
206
        pic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
207
    }
P
Paul Brook 已提交
208 209 210
    dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
    for (n = 0; n < 32; n++) {
        sysbus_connect_irq(sysbus_from_qdev(dev), n, pic[n]);
P
Paul Brook 已提交
211
        sic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
212
    }
P
Paul Brook 已提交
213 214 215

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

P
Paul Brook 已提交
217 218
    dev = sysbus_create_varargs("versatile_pci", 0x40000000,
                                sic[27], sic[28], sic[29], sic[30], NULL);
P
Paul Brook 已提交
219
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
220

P
pbrook 已提交
221 222 223 224
    /* The Versatile PCI bridge does not provide access to PCI IO space,
       so many of the qemu PCI devices are not useable.  */
    for(n = 0; n < nb_nics; n++) {
        nd = &nd_table[n];
225

226
        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
P
pbrook 已提交
227
            smc91c111_init(nd, 0x10010000, sic[25]);
228
            done_smc = 1;
229
        } else {
230
            pci_nic_init_nofail(nd, "rtl8139", NULL);
231 232
        }
    }
P
pbrook 已提交
233
    if (usb_enabled) {
P
Paul Brook 已提交
234
        usb_ohci_init_pci(pci_bus, -1);
P
pbrook 已提交
235
    }
P
Paul Brook 已提交
236 237 238 239
    n = drive_get_max_bus(IF_SCSI);
    while (n >= 0) {
        pci_create_simple(pci_bus, -1, "lsi53c895a");
        n--;
P
pbrook 已提交
240
    }
241

P
Paul Brook 已提交
242 243 244 245
    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]);
246

P
Paul Brook 已提交
247
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
248 249
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
250 251 252

    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
P
Paul Brook 已提交
253
    sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
254

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

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

261
    /* Memory map for Versatile/PB:  */
262 263 264 265 266
    /* 0x10000000 System registers.  */
    /* 0x10001000 PCI controller config registers.  */
    /* 0x10002000 Serial bus interface.  */
    /*  0x10003000 Secondary interrupt controller.  */
    /* 0x10004000 AACI (audio).  */
267
    /*  0x10005000 MMCI0.  */
268 269 270 271 272
    /*  0x10006000 KMI0 (keyboard).  */
    /*  0x10007000 KMI1 (mouse).  */
    /* 0x10008000 Character LCD Interface.  */
    /*  0x10009000 UART3.  */
    /* 0x1000a000 Smart card 1.  */
273
    /*  0x1000b000 MMCI1.  */
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    /*  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.  */

297 298 299 300 301 302
    versatile_binfo.ram_size = ram_size;
    versatile_binfo.kernel_filename = kernel_filename;
    versatile_binfo.kernel_cmdline = kernel_cmdline;
    versatile_binfo.initrd_filename = initrd_filename;
    versatile_binfo.board_id = board_id;
    arm_load_kernel(env, &versatile_binfo);
303 304
}

A
Anthony Liguori 已提交
305
static void vpb_init(ram_addr_t ram_size,
306
                     const char *boot_device,
307
                     const char *kernel_filename, const char *kernel_cmdline,
308
                     const char *initrd_filename, const char *cpu_model)
309
{
P
Paul Brook 已提交
310
    versatile_init(ram_size,
311
                   boot_device,
312
                   kernel_filename, kernel_cmdline,
P
pbrook 已提交
313
                   initrd_filename, cpu_model, 0x183);
314 315
}

A
Anthony Liguori 已提交
316
static void vab_init(ram_addr_t ram_size,
317
                     const char *boot_device,
318
                     const char *kernel_filename, const char *kernel_cmdline,
319
                     const char *initrd_filename, const char *cpu_model)
320
{
P
Paul Brook 已提交
321
    versatile_init(ram_size,
322
                   boot_device,
323
                   kernel_filename, kernel_cmdline,
P
pbrook 已提交
324
                   initrd_filename, cpu_model, 0x25e);
325 326
}

327
static QEMUMachine versatilepb_machine = {
328 329 330 331
    .name = "versatilepb",
    .desc = "ARM Versatile/PB (ARM926EJ-S)",
    .init = vpb_init,
    .use_scsi = 1,
332
};
333

334
static QEMUMachine versatileab_machine = {
335 336 337 338
    .name = "versatileab",
    .desc = "ARM Versatile/AB (ARM926EJ-S)",
    .init = vab_init,
    .use_scsi = 1,
339
};
P
Paul Brook 已提交
340

341 342 343 344 345 346 347 348
static void versatile_machine_init(void)
{
    qemu_register_machine(&versatilepb_machine);
    qemu_register_machine(&versatileab_machine);
}

machine_init(versatile_machine_init);

P
Peter Maydell 已提交
349 350 351 352 353 354 355 356
static SysBusDeviceInfo vpb_sic_info = {
    .init = vpb_sic_init,
    .qdev.name = "versatilepb_sic",
    .qdev.size = sizeof(vpb_sic_state),
    .qdev.vmsd = &vmstate_vpb_sic,
    .qdev.no_user = 1,
};

P
Paul Brook 已提交
357 358
static void versatilepb_register_devices(void)
{
P
Peter Maydell 已提交
359
    sysbus_register_withprop(&vpb_sic_info);
P
Paul Brook 已提交
360 361 362
}

device_init(versatilepb_register_devices)