versatilepb.c 8.3 KB
Newer Older
1
/* 
2
 * ARM Versatile Platform/Application Baseboard System emulation.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
 *
 * Copyright (c) 2005-2006 CodeSourcery.
 * Written by Paul Brook
 *
 * This code is licenced under the GPL.
 */

#include "vl.h"
#include "arm_pic.h"

/* Primary interrupt controller.  */

typedef struct vpb_sic_state
{
  arm_pic_handler handler;
  uint32_t base;
  uint32_t level;
  uint32_t mask;
  uint32_t pic_enable;
  void *parent;
  int irq;
} vpb_sic_state;

static void vpb_sic_update(vpb_sic_state *s)
{
    uint32_t flags;

    flags = s->level & s->mask;
    pic_set_irq_new(s->parent, s->irq, flags != 0);
}

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;
        pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
    }
}

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))
        pic_set_irq_new(s->parent, irq, level);
    vpb_sic_update(s);
}

static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
{
    vpb_sic_state *s = (vpb_sic_state *)opaque;

    offset -= s->base;
    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 已提交
76
        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
        return 0;
    }
}

static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
                          uint32_t value)
{
    vpb_sic_state *s = (vpb_sic_state *)opaque;
    offset -= s->base;

    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 已提交
111
        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
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 139 140 141 142 143 144 145 146 147 148 149
        return;
    }
    vpb_sic_update(s);
}

static CPUReadMemoryFunc *vpb_sic_readfn[] = {
   vpb_sic_read,
   vpb_sic_read,
   vpb_sic_read
};

static CPUWriteMemoryFunc *vpb_sic_writefn[] = {
   vpb_sic_write,
   vpb_sic_write,
   vpb_sic_write
};

static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
{
    vpb_sic_state *s;
    int iomemtype;

    s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
    if (!s)
        return NULL;
    s->handler = vpb_sic_set_irq;
    s->base = base;
    s->parent = parent;
    s->irq = irq;
    iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
                                       vpb_sic_writefn, s);
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
    /* ??? Save/restore.  */
    return s;
}

/* Board init.  */

150 151 152
/* 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.  */
153

154
static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
155 156
                     DisplayState *ds, const char **fd_filename, int snapshot,
                     const char *kernel_filename, const char *kernel_cmdline,
P
pbrook 已提交
157 158
                     const char *initrd_filename, const char *cpu_model,
                     int board_id)
159 160 161 162
{
    CPUState *env;
    void *pic;
    void *sic;
P
pbrook 已提交
163
    void *scsi_hba;
P
pbrook 已提交
164 165 166 167
    PCIBus *pci_bus;
    NICInfo *nd;
    int n;
    int done_smc = 0;
168 169

    env = cpu_init();
P
pbrook 已提交
170 171 172
    if (!cpu_model)
        cpu_model = "arm926";
    cpu_arm_set_model(env, cpu_model);
173 174 175 176
    /* ??? RAM shoud repeat to fill physical memory space.  */
    /* SDRAM at address zero.  */
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);

P
pbrook 已提交
177
    arm_sysctl_init(0x10000000, 0x41007004);
178 179 180 181 182 183
    pic = arm_pic_init_cpu(env);
    pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
    sic = vpb_sic_init(0x10003000, pic, 31);
    pl050_init(0x10006000, sic, 3, 0);
    pl050_init(0x10007000, sic, 4, 1);

P
pbrook 已提交
184
    pci_bus = pci_vpb_init(sic, 27, 0);
P
pbrook 已提交
185 186 187 188 189 190 191 192
    /* 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];
        if (!nd->model)
            nd->model = done_smc ? "rtl8139" : "smc91c111";
        if (strcmp(nd->model, "smc91c111") == 0) {
            smc91c111_init(nd, 0x10010000, sic, 25);
193
        } else {
194
            pci_nic_init(pci_bus, nd, -1);
195 196
        }
    }
P
pbrook 已提交
197 198 199
    if (usb_enabled) {
        usb_ohci_init(pci_bus, 3, -1);
    }
P
pbrook 已提交
200 201 202 203 204 205
    scsi_hba = lsi_scsi_init(pci_bus, -1);
    for (n = 0; n < MAX_DISKS; n++) {
        if (bs_table[n]) {
            lsi_scsi_attach(scsi_hba, bs_table[n], n);
        }
    }
206 207 208 209 210 211

    pl011_init(0x101f1000, pic, 12, serial_hds[0]);
    pl011_init(0x101f2000, pic, 13, serial_hds[1]);
    pl011_init(0x101f3000, pic, 14, serial_hds[2]);
    pl011_init(0x10009000, sic, 6, serial_hds[3]);

P
pbrook 已提交
212
    pl080_init(0x10130000, pic, 17, 8);
213 214 215 216 217 218 219
    sp804_init(0x101e2000, pic, 4);
    sp804_init(0x101e3000, pic, 5);

    /* The versatile/PB actually has a modified Color LCD controller
       that includes hardware cursor support from the PL111.  */
    pl110_init(ds, 0x10120000, pic, 16, 1);

220
    /* Memory map for Versatile/PB:  */
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
    /* 0x10000000 System registers.  */
    /* 0x10001000 PCI controller config registers.  */
    /* 0x10002000 Serial bus interface.  */
    /*  0x10003000 Secondary interrupt controller.  */
    /* 0x10004000 AACI (audio).  */
    /* 0x10005000 MMCI0.  */
    /*  0x10006000 KMI0 (keyboard).  */
    /*  0x10007000 KMI1 (mouse).  */
    /* 0x10008000 Character LCD Interface.  */
    /*  0x10009000 UART3.  */
    /* 0x1000a000 Smart card 1.  */
    /* 0x1000b000 MMCI1.  */
    /*  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.  */

P
pbrook 已提交
256
    arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
257 258 259 260 261 262
                    initrd_filename, board_id);
}

static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
                     DisplayState *ds, const char **fd_filename, int snapshot,
                     const char *kernel_filename, const char *kernel_cmdline,
263
                     const char *initrd_filename, const char *cpu_model)
264 265 266 267
{
    versatile_init(ram_size, vga_ram_size, boot_device,
                   ds, fd_filename, snapshot,
                   kernel_filename, kernel_cmdline,
P
pbrook 已提交
268
                   initrd_filename, cpu_model, 0x183);
269 270 271 272 273
}

static void vab_init(int ram_size, int vga_ram_size, int boot_device,
                     DisplayState *ds, const char **fd_filename, int snapshot,
                     const char *kernel_filename, const char *kernel_cmdline,
274
                     const char *initrd_filename, const char *cpu_model)
275 276 277 278
{
    versatile_init(ram_size, vga_ram_size, boot_device,
                   ds, fd_filename, snapshot,
                   kernel_filename, kernel_cmdline,
P
pbrook 已提交
279
                   initrd_filename, cpu_model, 0x25e);
280 281 282 283 284 285 286
}

QEMUMachine versatilepb_machine = {
    "versatilepb",
    "ARM Versatile/PB (ARM926EJ-S)",
    vpb_init,
};
287 288 289 290 291 292

QEMUMachine versatileab_machine = {
    "versatileab",
    "ARM Versatile/AB (ARM926EJ-S)",
    vab_init,
};