X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Fintegratorcp.c;h=83c6208cf1909350c105609c6e8bfd1c56e8b3a6;hb=cd346349b45ef056f138a184f660b8c34c3213cc;hp=8f91b582f6b9dfe4429cd1a0c65d7ee01d1a4d0a;hpb=242011157f0d454bf5a57541ebeba2c17611298e;p=qemu diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 8f91b58..83c6208 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1,47 +1,14 @@ -/* +/* * ARM Integrator CP System emulation. * - * Copyright (c) 2005 CodeSourcery, LLC. + * Copyright (c) 2005-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL */ -#include - -#define KERNEL_ARGS_ADDR 0x100 -#define KERNEL_LOAD_ADDR 0x00010000 -#define INITRD_LOAD_ADDR 0x00800000 - -/* Stub functions for hardware that doesn't exist. */ -void pic_set_irq(int irq, int level) -{ - cpu_abort (cpu_single_env, "pic_set_irq"); -} - -void pic_info(void) -{ -} - -void irq_info(void) -{ -} - -static void *lcd; - -void vga_update_display(void) -{ - pl110_update_display(lcd); -} - -void vga_screen_dump(const char *filename) -{ -} - -void vga_invalidate_display(void) -{ - pl110_invalidate_display(lcd); -} +#include "vl.h" +#include "arm_pic.h" void DMA_run (void) { @@ -290,7 +257,7 @@ static void integratorcm_init(int memsz, uint32_t flash_offset) iomemtype = cpu_register_io_memory(0, integratorcm_readfn, integratorcm_writefn, s); - cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype); + cpu_register_physical_memory(0x10000000, 0x00800000, iomemtype); integratorcm_do_remap(s, 1); /* ??? Save/restore. */ } @@ -304,37 +271,21 @@ typedef struct icp_pic_state uint32_t level; uint32_t irq_enabled; uint32_t fiq_enabled; - void *parent; - /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */ - int parent_irq; + qemu_irq parent_irq; + qemu_irq parent_fiq; } icp_pic_state; static void icp_pic_update(icp_pic_state *s) { - CPUState *env; - if (s->parent_irq != -1) { - uint32_t flags; + uint32_t flags; - flags = (s->level & s->irq_enabled); - pic_set_irq_new(s->parent, s->parent_irq, - flags != 0); - return; - } - /* Raise CPU interrupt. */ - env = (CPUState *)s->parent; - if (s->level & s->fiq_enabled) { - cpu_interrupt (env, CPU_INTERRUPT_FIQ); - } else { - cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ); - } - if (s->level & s->irq_enabled) { - cpu_interrupt (env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt (env, CPU_INTERRUPT_HARD); - } + flags = (s->level & s->irq_enabled); + qemu_set_irq(s->parent_irq, flags != 0); + flags = (s->level & s->fiq_enabled); + qemu_set_irq(s->parent_fiq, flags != 0); } -void pic_set_irq_new(void *opaque, int irq, int level) +static void icp_pic_set_irq(void *opaque, int irq, int level) { icp_pic_state *s = (icp_pic_state *)opaque; if (level) @@ -368,7 +319,7 @@ static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) case 5: /* INT_SOFTCLR */ case 11: /* FRQ_ENABLECLR */ default: - printf ("icp_pic_read: Bad register offset 0x%x\n", offset); + printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); return 0; } } @@ -388,11 +339,11 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset, break; case 4: /* INT_SOFTSET */ if (value & 1) - pic_set_irq_new(s, 0, 1); + icp_pic_set_irq(s, 0, 1); break; case 5: /* INT_SOFTCLR */ if (value & 1) - pic_set_irq_new(s, 0, 0); + icp_pic_set_irq(s, 0, 0); break; case 10: /* FRQ_ENABLESET */ s->fiq_enabled |= value; @@ -405,7 +356,7 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset, case 8: /* FRQ_STATUS */ case 9: /* FRQ_RAWSTAT */ default: - printf ("icp_pic_write: Bad register offset 0x%x\n", offset); + printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); return; } icp_pic_update(s); @@ -423,517 +374,25 @@ static CPUWriteMemoryFunc *icp_pic_writefn[] = { icp_pic_write }; -static icp_pic_state *icp_pic_init(uint32_t base, void *parent, - int parent_irq) +static qemu_irq *icp_pic_init(uint32_t base, + qemu_irq parent_irq, qemu_irq parent_fiq) { icp_pic_state *s; int iomemtype; + qemu_irq *qi; s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); if (!s) return NULL; - + qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32); s->base = base; - s->parent = parent; s->parent_irq = parent_irq; + s->parent_fiq = parent_fiq; iomemtype = cpu_register_io_memory(0, icp_pic_readfn, icp_pic_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - /* ??? Save/restore. */ - return s; -} - -/* Timers. */ - -/* System bus clock speed (40MHz) for timer 0. Not sure about this value. */ -#define ICP_BUS_FREQ 40000000 - -typedef struct { - int64_t next_time; - int64_t expires[3]; - int64_t loaded[3]; - QEMUTimer *timer; - icp_pic_state *pic; - uint32_t base; - uint32_t control[3]; - uint32_t count[3]; - uint32_t limit[3]; - int freq[3]; - int int_level[3]; -} icp_pit_state; - -/* Calculate the new expiry time of the given timer. */ - -static void icp_pit_reload(icp_pit_state *s, int n) -{ - int64_t delay; - - s->loaded[n] = s->expires[n]; - delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]); - if (delay == 0) - delay = 1; - s->expires[n] += delay; -} - -/* Check all active timers, and schedule the next timer interrupt. */ - -static void icp_pit_update(icp_pit_state *s, int64_t now) -{ - int n; - int64_t next; - - next = now; - for (n = 0; n < 3; n++) { - /* Ignore disabled timers. */ - if ((s->control[n] & 0x80) == 0) - continue; - /* Ignore expired one-shot timers. */ - if (s->count[n] == 0 && s->control[n] & 1) - continue; - if (s->expires[n] - now <= 0) { - /* Timer has expired. */ - s->int_level[n] = 1; - if (s->control[n] & 1) { - /* One-shot. */ - s->count[n] = 0; - } else { - if ((s->control[n] & 0x40) == 0) { - /* Free running. */ - if (s->control[n] & 2) - s->count[n] = 0xffffffff; - else - s->count[n] = 0xffff; - } else { - /* Periodic. */ - s->count[n] = s->limit[n]; - } - } - } - while (s->expires[n] - now <= 0) { - icp_pit_reload(s, n); - } - } - /* Update interrupts. */ - for (n = 0; n < 3; n++) { - if (s->int_level[n] && (s->control[n] & 0x20)) { - pic_set_irq_new(s->pic, 5 + n, 1); - } else { - pic_set_irq_new(s->pic, 5 + n, 0); - } - if (next - s->expires[n] < 0) - next = s->expires[n]; - } - /* Schedule the next timer interrupt. */ - if (next == now) { - qemu_del_timer(s->timer); - s->next_time = 0; - } else if (next != s->next_time) { - qemu_mod_timer(s->timer, next); - s->next_time = next; - } -} - -/* Return the current value of the timer. */ -static uint32_t icp_pit_getcount(icp_pit_state *s, int n, int64_t now) -{ - int64_t elapsed; - int64_t period; - - if (s->count[n] == 0) - return 0; - if ((s->control[n] & 0x80) == 0) - return s->count[n]; - elapsed = now - s->loaded[n]; - period = s->expires[n] - s->loaded[n]; - /* If the timer should have expired then return 0. This can happen - when the host timer signal doesnt occur immediately. It's better to - have a timer appear to sit at zero for a while than have it wrap - around before the guest interrupt is raised. */ - /* ??? Could we trigger the interrupt here? */ - if (elapsed > period) - return 0; - /* We need to calculate count * elapsed / period without overfowing. - Scale both elapsed and period so they fit in a 32-bit int. */ - while (period != (int32_t)period) { - period >>= 1; - elapsed >>= 1; - } - return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed) - / (int32_t)period; -} - -static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset) -{ - int n; - icp_pit_state *s = (icp_pit_state *)opaque; - - offset -= s->base; - n = offset >> 8; - if (n > 2) - cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset); - switch ((offset & 0xff) >> 2) { - case 0: /* TimerLoad */ - case 6: /* TimerBGLoad */ - return s->limit[n]; - case 1: /* TimerValue */ - return icp_pit_getcount(s, n, qemu_get_clock(vm_clock)); - case 2: /* TimerControl */ - return s->control[n]; - case 4: /* TimerRIS */ - return s->int_level[n]; - case 5: /* TimerMIS */ - if ((s->control[n] & 0x20) == 0) - return 0; - return s->int_level[n]; - default: - cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset); - return 0; - } -} - -static void icp_pit_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_pit_state *s = (icp_pit_state *)opaque; - int n; - int64_t now; - - now = qemu_get_clock(vm_clock); - offset -= s->base; - n = offset >> 8; - if (n > 2) - cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); - - switch ((offset & 0xff) >> 2) { - case 0: /* TimerLoad */ - s->limit[n] = value; - s->count[n] = value; - s->expires[n] = now; - icp_pit_reload(s, n); - break; - case 1: /* TimerValue */ - /* ??? Linux seems to want to write to this readonly register. - Ignore it. */ - break; - case 2: /* TimerControl */ - if (s->control[n] & 0x80) { - /* Pause the timer if it is running. This may cause some - inaccuracy dure to rounding, but avoids a whole lot of other - messyness. */ - s->count[n] = icp_pit_getcount(s, n, now); - } - s->control[n] = value; - if (n == 0) - s->freq[n] = ICP_BUS_FREQ; - else - s->freq[n] = 1000000; - /* ??? Need to recalculate expiry time after changing divisor. */ - switch ((value >> 2) & 3) { - case 1: s->freq[n] >>= 4; break; - case 2: s->freq[n] >>= 8; break; - } - if (s->control[n] & 0x80) { - /* Restart the timer if still enabled. */ - s->expires[n] = now; - icp_pit_reload(s, n); - } - break; - case 3: /* TimerIntClr */ - s->int_level[n] = 0; - break; - case 6: /* TimerBGLoad */ - s->limit[n] = value; - break; - default: - cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); - } - icp_pit_update(s, now); -} - -static void icp_pit_tick(void *opaque) -{ - int64_t now; - - now = qemu_get_clock(vm_clock); - icp_pit_update((icp_pit_state *)opaque, now); -} - -static CPUReadMemoryFunc *icp_pit_readfn[] = { - icp_pit_read, - icp_pit_read, - icp_pit_read -}; - -static CPUWriteMemoryFunc *icp_pit_writefn[] = { - icp_pit_write, - icp_pit_write, - icp_pit_write -}; - -static void icp_pit_init(uint32_t base, icp_pic_state *pic) -{ - int iomemtype; - icp_pit_state *s; - int n; - - s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); - s->base = base; - s->pic = pic; - s->freq[0] = ICP_BUS_FREQ; - s->freq[1] = 1000000; - s->freq[2] = 1000000; - for (n = 0; n < 3; n++) { - s->control[n] = 0x20; - s->count[n] = 0xffffffff; - } - - iomemtype = cpu_register_io_memory(0, icp_pit_readfn, - icp_pit_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s); - /* ??? Save/restore. */ -} - -/* ARM PrimeCell PL011 UART */ - -typedef struct { - uint32_t base; - uint32_t readbuff; - uint32_t flags; - uint32_t lcr; - uint32_t cr; - uint32_t dmacr; - uint32_t int_enabled; - uint32_t int_level; - uint32_t read_fifo[16]; - uint32_t ilpr; - uint32_t ibrd; - uint32_t fbrd; - uint32_t ifl; - int read_pos; - int read_count; - int read_trigger; - CharDriverState *chr; - icp_pic_state *pic; - int irq; -} pl011_state; - -#define PL011_INT_TX 0x20 -#define PL011_INT_RX 0x10 - -#define PL011_FLAG_TXFE 0x80 -#define PL011_FLAG_RXFF 0x40 -#define PL011_FLAG_TXFF 0x20 -#define PL011_FLAG_RXFE 0x10 - -static const unsigned char pl011_id[] = -{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl011_update(pl011_state *s) -{ - uint32_t flags; - - flags = s->int_level & s->int_enabled; - pic_set_irq_new(s->pic, s->irq, flags != 0); -} - -static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) -{ - pl011_state *s = (pl011_state *)opaque; - uint32_t c; - - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) { - return pl011_id[(offset - 0xfe0) >> 2]; - } - switch (offset >> 2) { - case 0: /* UARTDR */ - s->flags &= ~PL011_FLAG_RXFF; - c = s->read_fifo[s->read_pos]; - if (s->read_count > 0) { - s->read_count--; - if (++s->read_pos == 16) - s->read_pos = 0; - } - if (s->read_count == 0) { - s->flags |= PL011_FLAG_RXFE; - } - if (s->read_count == s->read_trigger - 1) - s->int_level &= ~ PL011_INT_RX; - pl011_update(s); - return c; - case 1: /* UARTCR */ - return 0; - case 6: /* UARTFR */ - return s->flags; - case 8: /* UARTILPR */ - return s->ilpr; - case 9: /* UARTIBRD */ - return s->ibrd; - case 10: /* UARTFBRD */ - return s->fbrd; - case 11: /* UARTLCR_H */ - return s->lcr; - case 12: /* UARTCR */ - return s->cr; - case 13: /* UARTIFLS */ - return s->ifl; - case 14: /* UARTIMSC */ - return s->int_enabled; - case 15: /* UARTRIS */ - return s->int_level; - case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; - case 18: /* UARTDMACR */ - return s->dmacr; - default: - cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl011_set_read_trigger(pl011_state *s) -{ -#if 0 - /* The docs say the RX interrupt is triggered when the FIFO exceeds - the threshold. However linux only reads the FIFO in response to an - interrupt. Triggering the interrupt when the FIFO is non-empty seems - to make things work. */ - if (s->lcr & 0x10) - s->read_trigger = (s->ifl >> 1) & 0x1c; - else -#endif - s->read_trigger = 1; -} - -static void pl011_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - pl011_state *s = (pl011_state *)opaque; - unsigned char ch; - - offset -= s->base; - switch (offset >> 2) { - case 0: /* UARTDR */ - /* ??? Check if transmitter is enabled. */ - ch = value; - if (s->chr) - qemu_chr_write(s->chr, &ch, 1); - s->int_level |= PL011_INT_TX; - pl011_update(s); - break; - case 1: /* UARTCR */ - s->cr = value; - break; - case 8: /* UARTUARTILPR */ - s->ilpr = value; - break; - case 9: /* UARTIBRD */ - s->ibrd = value; - break; - case 10: /* UARTFBRD */ - s->fbrd = value; - break; - case 11: /* UARTLCR_H */ - s->lcr = value; - pl011_set_read_trigger(s); - break; - case 12: /* UARTCR */ - /* ??? Need to implement the enable and loopback bits. */ - s->cr = value; - break; - case 13: /* UARTIFS */ - s->ifl = value; - pl011_set_read_trigger(s); - break; - case 14: /* UARTIMSC */ - s->int_enabled = value; - pl011_update(s); - break; - case 17: /* UARTICR */ - s->int_level &= ~value; - pl011_update(s); - break; - case 18: /* UARTDMACR */ - s->dmacr = value; - if (value & 3) - cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); - break; - default: - cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); - } -} - -static int pl011_can_recieve(void *opaque) -{ - pl011_state *s = (pl011_state *)opaque; - - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; -} - -static void pl011_recieve(void *opaque, const uint8_t *buf, int size) -{ - pl011_state *s = (pl011_state *)opaque; - int slot; - - slot = s->read_pos + s->read_count; - if (slot >= 16) - slot -= 16; - s->read_fifo[slot] = *buf; - s->read_count++; - s->flags &= ~PL011_FLAG_RXFE; - if (s->cr & 0x10 || s->read_count == 16) { - s->flags |= PL011_FLAG_RXFF; - } - if (s->read_count == s->read_trigger) { - s->int_level |= PL011_INT_RX; - pl011_update(s); - } -} - -static void pl011_event(void *opaque, int event) -{ - /* ??? Should probably implement break. */ -} - -static CPUReadMemoryFunc *pl011_readfn[] = { - pl011_read, - pl011_read, - pl011_read -}; - -static CPUWriteMemoryFunc *pl011_writefn[] = { - pl011_write, - pl011_write, - pl011_write -}; - -static void pl011_init(uint32_t base, icp_pic_state *pic, int irq, - CharDriverState *chr) -{ - int iomemtype; - pl011_state *s; - - s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); - iomemtype = cpu_register_io_memory(0, pl011_readfn, - pl011_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - s->chr = chr; - s->read_trigger = 1; - s->ifl = 0x12; - s->cr = 0x300; - s->flags = 0x90; - if (chr){ - qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); - qemu_chr_add_event_handler(chr, pl011_event); - } + cpu_register_physical_memory(base, 0x00800000, iomemtype); /* ??? Save/restore. */ + return qi; } /* CP control registers. */ @@ -995,194 +454,28 @@ static void icp_control_init(uint32_t base) s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state)); iomemtype = cpu_register_io_memory(0, icp_control_readfn, icp_control_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); + cpu_register_physical_memory(base, 0x00800000, iomemtype); s->base = base; /* ??? Save/restore. */ } -/* Keyboard/Mouse Interface. */ - -typedef struct { - void *dev; - uint32_t base; - uint32_t cr; - uint32_t clk; - uint32_t last; - icp_pic_state *pic; - int pending; - int irq; - int is_mouse; -} icp_kmi_state; - -static void icp_kmi_update(void *opaque, int level) -{ - icp_kmi_state *s = (icp_kmi_state *)opaque; - int raise; - - s->pending = level; - raise = (s->pending && (s->cr & 0x10) != 0) - || (s->cr & 0x08) != 0; - pic_set_irq_new(s->pic, s->irq, raise); -} - -static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset) -{ - icp_kmi_state *s = (icp_kmi_state *)opaque; - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) - return 0; - - switch (offset >> 2) { - case 0: /* KMICR */ - return s->cr; - case 1: /* KMISTAT */ - /* KMIC and KMID bits not implemented. */ - if (s->pending) { - return 0x10; - } else { - return 0; - } - case 2: /* KMIDATA */ - if (s->pending) - s->last = ps2_read_data(s->dev); - return s->last; - case 3: /* KMICLKDIV */ - return s->clk; - case 4: /* KMIIR */ - return s->pending | 2; - default: - cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset); - return 0; - } -} - -static void icp_kmi_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_kmi_state *s = (icp_kmi_state *)opaque; - offset -= s->base; - switch (offset >> 2) { - case 0: /* KMICR */ - s->cr = value; - icp_kmi_update(s, s->pending); - /* ??? Need to implement the enable/disable bit. */ - break; - case 2: /* KMIDATA */ - /* ??? This should toggle the TX interrupt line. */ - /* ??? This means kbd/mouse can block each other. */ - if (s->is_mouse) { - ps2_write_mouse(s->dev, value); - } else { - ps2_write_keyboard(s->dev, value); - } - break; - case 3: /* KMICLKDIV */ - s->clk = value; - return; - default: - cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset); - } -} -static CPUReadMemoryFunc *icp_kmi_readfn[] = { - icp_kmi_read, - icp_kmi_read, - icp_kmi_read -}; - -static CPUWriteMemoryFunc *icp_kmi_writefn[] = { - icp_kmi_write, - icp_kmi_write, - icp_kmi_write -}; - -static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq, - int is_mouse) -{ - int iomemtype; - icp_kmi_state *s; - - s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state)); - iomemtype = cpu_register_io_memory(0, icp_kmi_readfn, - icp_kmi_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - s->is_mouse = is_mouse; - if (is_mouse) - s->dev = ps2_mouse_init(icp_kmi_update, s); - else - s->dev = ps2_kbd_init(icp_kmi_update, s); - /* ??? Save/restore. */ -} - -/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ -static uint32_t bootloader[] = { - 0xe3a00000, /* mov r0, #0 */ - 0xe3a01013, /* mov r1, #0x13 */ - 0xe3811c01, /* orr r1, r1, #0x100 */ - 0xe59f2000, /* ldr r2, [pc, #0] */ - 0xe59ff000, /* ldr pc, [pc, #0] */ - 0, /* Address of kernel args. Set by integratorcp_init. */ - 0 /* Kernel entry point. Set by integratorcp_init. */ -}; - -static void set_kernel_args(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline) -{ - uint32_t *p; - - p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); - /* ATAG_CORE */ - stl_raw(p++, 5); - stl_raw(p++, 0x54410001); - stl_raw(p++, 1); - stl_raw(p++, 0x1000); - stl_raw(p++, 0); - /* ATAG_MEM */ - stl_raw(p++, 4); - stl_raw(p++, 0x54410002); - stl_raw(p++, ram_size); - stl_raw(p++, 0); - if (initrd_size) { - /* ATAG_INITRD2 */ - stl_raw(p++, 4); - stl_raw(p++, 0x54420005); - stl_raw(p++, INITRD_LOAD_ADDR); - stl_raw(p++, initrd_size); - } - if (kernel_cmdline && *kernel_cmdline) { - /* ATAG_CMDLINE */ - int cmdline_size; - - cmdline_size = strlen(kernel_cmdline); - memcpy (p + 2, kernel_cmdline, cmdline_size + 1); - cmdline_size = (cmdline_size >> 2) + 1; - stl_raw(p++, cmdline_size + 2); - stl_raw(p++, 0x54410009); - p += cmdline_size; - } - /* ATAG_END */ - stl_raw(p++, 0); - stl_raw(p++, 0); -} - /* Board init. */ static void integratorcp_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, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { CPUState *env; uint32_t bios_offset; - icp_pic_state *pic; - int kernel_size; - int initrd_size; - int n; + qemu_irq *pic; + qemu_irq *cpu_pic; env = cpu_init(); + if (!cpu_model) + cpu_model = "arm926"; + cpu_arm_set_model(env, cpu_model); bios_offset = ram_size + vga_ram_size; /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ /* ??? RAM shoud repeat to fill physical memory space. */ @@ -1192,56 +485,38 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); integratorcm_init(ram_size >> 20, bios_offset); - pic = icp_pic_init(0x14000000, env, -1); - icp_pic_init(0xca000000, pic, 26); - icp_pit_init(0x13000000, pic); - pl011_init(0x16000000, pic, 1, serial_hds[0]); - pl011_init(0x17000000, pic, 2, serial_hds[1]); + cpu_pic = arm_pic_init_cpu(env); + pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ]); + icp_pic_init(0xca000000, pic[26], NULL); + icp_pit_init(0x13000000, pic, 5); + pl031_init(0x15000000, pic[8]); + pl011_init(0x16000000, pic[1], serial_hds[0]); + pl011_init(0x17000000, pic[2], serial_hds[1]); icp_control_init(0xcb000000); - icp_kmi_init(0x18000000, pic, 3, 0); - icp_kmi_init(0x19000000, pic, 4, 1); + pl050_init(0x18000000, pic[3], 0); + pl050_init(0x19000000, pic[4], 1); + pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); + smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: smc91c111\n"); + exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); } } - lcd = pl110_init(ds, 0xc0000000, pic, 22); + pl110_init(ds, 0xc0000000, pic[22], 0); - /* Load the kernel. */ - if (!kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_size = 0; - } - bootloader[5] = KERNEL_ARGS_ADDR; - bootloader[6] = KERNEL_LOAD_ADDR; - for (n = 0; n < sizeof(bootloader) / 4; n++) - stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline); + arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, + initrd_filename, 0x113, 0x0); } QEMUMachine integratorcp_machine = { "integratorcp", - "ARM Integrator/CP", + "ARM Integrator/CP (ARM926EJ-S)", integratorcp_init, };