versatilepb.c 10.6 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
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];
183
    DeviceState *dev, *sysctl;
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

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

P
Paul Brook 已提交
207 208 209 210
    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 已提交
211
        pic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
212
    }
P
Paul Brook 已提交
213 214 215
    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 已提交
216
        sic[n] = qdev_get_gpio_in(dev, n);
P
Paul Brook 已提交
217
    }
P
Paul Brook 已提交
218 219 220

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

P
Paul Brook 已提交
222 223
    dev = sysbus_create_varargs("versatile_pci", 0x40000000,
                                sic[27], sic[28], sic[29], sic[30], NULL);
P
Paul Brook 已提交
224
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
P
Paul Brook 已提交
225

P
pbrook 已提交
226 227 228 229
    /* 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];
230

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

P
Paul Brook 已提交
247 248 249 250
    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]);
251

P
Paul Brook 已提交
252
    sysbus_create_simple("pl080", 0x10130000, pic[17]);
P
Paul Brook 已提交
253 254
    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
255 256 257

    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
258 259 260
    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));
261

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

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

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

304 305 306 307 308 309
    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);
310 311
}

A
Anthony Liguori 已提交
312
static void vpb_init(ram_addr_t ram_size,
313
                     const char *boot_device,
314
                     const char *kernel_filename, const char *kernel_cmdline,
315
                     const char *initrd_filename, const char *cpu_model)
316
{
P
Paul Brook 已提交
317
    versatile_init(ram_size,
318
                   boot_device,
319
                   kernel_filename, kernel_cmdline,
P
pbrook 已提交
320
                   initrd_filename, cpu_model, 0x183);
321 322
}

A
Anthony Liguori 已提交
323
static void vab_init(ram_addr_t ram_size,
324
                     const char *boot_device,
325
                     const char *kernel_filename, const char *kernel_cmdline,
326
                     const char *initrd_filename, const char *cpu_model)
327
{
P
Paul Brook 已提交
328
    versatile_init(ram_size,
329
                   boot_device,
330
                   kernel_filename, kernel_cmdline,
P
pbrook 已提交
331
                   initrd_filename, cpu_model, 0x25e);
332 333
}

334
static QEMUMachine versatilepb_machine = {
335 336 337 338
    .name = "versatilepb",
    .desc = "ARM Versatile/PB (ARM926EJ-S)",
    .init = vpb_init,
    .use_scsi = 1,
339
};
340

341
static QEMUMachine versatileab_machine = {
342 343 344 345
    .name = "versatileab",
    .desc = "ARM Versatile/AB (ARM926EJ-S)",
    .init = vab_init,
    .use_scsi = 1,
346
};
P
Paul Brook 已提交
347

348 349 350 351 352 353 354 355
static void versatile_machine_init(void)
{
    qemu_register_machine(&versatilepb_machine);
    qemu_register_machine(&versatileab_machine);
}

machine_init(versatile_machine_init);

P
Peter Maydell 已提交
356 357 358 359 360 361 362 363
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 已提交
364 365
static void versatilepb_register_devices(void)
{
P
Peter Maydell 已提交
366
    sysbus_register_withprop(&vpb_sic_info);
P
Paul Brook 已提交
367 368 369
}

device_init(versatilepb_register_devices)