Commit cdbdb648b7c2867f0bb7dce27efb1986f770dedb

Authored by pbrook
1 parent 95219897

ARM Versatile Platform Baseboard emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1804 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
@@ -339,7 +339,8 @@ VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o @@ -339,7 +339,8 @@ VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
339 endif 339 endif
340 endif 340 endif
341 ifeq ($(TARGET_BASE_ARCH), arm) 341 ifeq ($(TARGET_BASE_ARCH), arm)
342 -VL_OBJS+= integratorcp.o ps2.o smc91c111.o pl110.o 342 +VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
  343 +VL_OBJS+= pl011.o pl050.o pl080.o pl110.o pl190.o
343 endif 344 endif
344 ifdef CONFIG_GDBSTUB 345 ifdef CONFIG_GDBSTUB
345 VL_OBJS+=gdbstub.o 346 VL_OBJS+=gdbstub.o
hw/arm_pic.c 0 → 100644
  1 +/*
  2 + * Generic ARM Programmable Interrupt Controller support.
  3 + *
  4 + * Copyright (c) 2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the LGPL
  8 + */
  9 +
  10 +#include "vl.h"
  11 +#include "arm_pic.h"
  12 +
  13 +/* Stub functions for hardware that doesn't exist. */
  14 +void pic_set_irq(int irq, int level)
  15 +{
  16 + cpu_abort(cpu_single_env, "pic_set_irq");
  17 +}
  18 +
  19 +void pic_info(void)
  20 +{
  21 +}
  22 +
  23 +void irq_info(void)
  24 +{
  25 +}
  26 +
  27 +
  28 +void pic_set_irq_new(void *opaque, int irq, int level)
  29 +{
  30 + arm_pic_handler *p = (arm_pic_handler *)opaque;
  31 + /* Call the real handler. */
  32 + (*p)(opaque, irq, level);
  33 +}
  34 +
  35 +/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller.
  36 + Input 0 is IRQ and input 1 is FIQ. */
  37 +typedef struct
  38 +{
  39 + arm_pic_handler handler;
  40 + CPUState *cpu_env;
  41 +} arm_pic_cpu_state;
  42 +
  43 +static void arm_pic_cpu_handler(void *opaque, int irq, int level)
  44 +{
  45 + arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque;
  46 + switch (irq) {
  47 + case ARM_PIC_CPU_IRQ:
  48 + if (level)
  49 + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
  50 + else
  51 + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
  52 + break;
  53 + case ARM_PIC_CPU_FIQ:
  54 + if (level)
  55 + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
  56 + else
  57 + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
  58 + break;
  59 + default:
  60 + cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n",
  61 + irq);
  62 + }
  63 +}
  64 +
  65 +void *arm_pic_init_cpu(CPUState *env)
  66 +{
  67 + arm_pic_cpu_state *s;
  68 +
  69 + s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state));
  70 + s->handler = arm_pic_cpu_handler;
  71 + s->cpu_env = env;
  72 + return s;
  73 +}
hw/arm_pic.h 0 → 100644
  1 +/*
  2 + * Generic ARM Programmable Interrupt Controller support.
  3 + *
  4 + * Copyright (c) 2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the LGPL.
  8 + *
  9 + * Arm hardware uses a wide variety of interrupt handling hardware.
  10 + * This provides a generic framework for connecting interrupt sources and
  11 + * inputs.
  12 + */
  13 +
  14 +#ifndef ARM_INTERRUPT_H
  15 +#define ARM_INTERRUPT_H 1
  16 +
  17 +/* The first element of an individual PIC state structures should
  18 + be a pointer to the handler routine. */
  19 +typedef void (*arm_pic_handler)(void *opaque, int irq, int level);
  20 +
  21 +/* The CPU is also modeled as an interrupt controller. */
  22 +#define ARM_PIC_CPU_IRQ 0
  23 +#define ARM_PIC_CPU_FIQ 1
  24 +void *arm_pic_init_cpu(CPUState *env);
  25 +
  26 +#endif /* !ARM_INTERRUPT_H */
  27 +
hw/arm_timer.c 0 → 100644
  1 +/*
  2 + * ARM PrimeCell Timer modules.
  3 + *
  4 + * Copyright (c) 2005-2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +#include "arm_pic.h"
  12 +
  13 +/* Common timer implementation. */
  14 +
  15 +#define TIMER_CTRL_ONESHOT (1 << 0)
  16 +#define TIMER_CTRL_32BIT (1 << 1)
  17 +#define TIMER_CTRL_DIV1 (0 << 2)
  18 +#define TIMER_CTRL_DIV16 (1 << 2)
  19 +#define TIMER_CTRL_DIV256 (2 << 2)
  20 +#define TIMER_CTRL_IE (1 << 5)
  21 +#define TIMER_CTRL_PERIODIC (1 << 6)
  22 +#define TIMER_CTRL_ENABLE (1 << 7)
  23 +
  24 +typedef struct {
  25 + int64_t next_time;
  26 + int64_t expires;
  27 + int64_t loaded;
  28 + QEMUTimer *timer;
  29 + uint32_t control;
  30 + uint32_t count;
  31 + uint32_t limit;
  32 + int raw_freq;
  33 + int freq;
  34 + int int_level;
  35 + void *pic;
  36 + int irq;
  37 +} arm_timer_state;
  38 +
  39 +/* Calculate the new expiry time of the given timer. */
  40 +
  41 +static void arm_timer_reload(arm_timer_state *s)
  42 +{
  43 + int64_t delay;
  44 +
  45 + s->loaded = s->expires;
  46 + delay = muldiv64(s->count, ticks_per_sec, s->freq);
  47 + if (delay == 0)
  48 + delay = 1;
  49 + s->expires += delay;
  50 +}
  51 +
  52 +/* Check all active timers, and schedule the next timer interrupt. */
  53 +
  54 +static void arm_timer_update(arm_timer_state *s, int64_t now)
  55 +{
  56 + int64_t next;
  57 +
  58 + /* Ignore disabled timers. */
  59 + if ((s->control & TIMER_CTRL_ENABLE) == 0)
  60 + return;
  61 + /* Ignore expired one-shot timers. */
  62 + if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
  63 + return;
  64 + if (s->expires - now <= 0) {
  65 + /* Timer has expired. */
  66 + s->int_level = 1;
  67 + if (s->control & TIMER_CTRL_ONESHOT) {
  68 + /* One-shot. */
  69 + s->count = 0;
  70 + } else {
  71 + if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
  72 + /* Free running. */
  73 + if (s->control & TIMER_CTRL_32BIT)
  74 + s->count = 0xffffffff;
  75 + else
  76 + s->count = 0xffff;
  77 + } else {
  78 + /* Periodic. */
  79 + s->count = s->limit;
  80 + }
  81 + }
  82 + }
  83 + while (s->expires - now <= 0) {
  84 + arm_timer_reload(s);
  85 + }
  86 + /* Update interrupts. */
  87 + if (s->int_level && (s->control & TIMER_CTRL_IE)) {
  88 + pic_set_irq_new(s->pic, s->irq, 1);
  89 + } else {
  90 + pic_set_irq_new(s->pic, s->irq, 0);
  91 + }
  92 +
  93 + next = now;
  94 + if (next - s->expires < 0)
  95 + next = s->expires;
  96 +
  97 + /* Schedule the next timer interrupt. */
  98 + if (next == now) {
  99 + qemu_del_timer(s->timer);
  100 + s->next_time = 0;
  101 + } else if (next != s->next_time) {
  102 + qemu_mod_timer(s->timer, next);
  103 + s->next_time = next;
  104 + }
  105 +}
  106 +
  107 +/* Return the current value of the timer. */
  108 +static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
  109 +{
  110 + int64_t elapsed;
  111 + int64_t period;
  112 +
  113 + if (s->count == 0)
  114 + return 0;
  115 + if ((s->control & TIMER_CTRL_ENABLE) == 0)
  116 + return s->count;
  117 + elapsed = now - s->loaded;
  118 + period = s->expires - s->loaded;
  119 + /* If the timer should have expired then return 0. This can happen
  120 + when the host timer signal doesnt occur immediately. It's better to
  121 + have a timer appear to sit at zero for a while than have it wrap
  122 + around before the guest interrupt is raised. */
  123 + /* ??? Could we trigger the interrupt here? */
  124 + if (elapsed > period)
  125 + return 0;
  126 + /* We need to calculate count * elapsed / period without overfowing.
  127 + Scale both elapsed and period so they fit in a 32-bit int. */
  128 + while (period != (int32_t)period) {
  129 + period >>= 1;
  130 + elapsed >>= 1;
  131 + }
  132 + return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed)
  133 + / (int32_t)period;
  134 +}
  135 +
  136 +uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
  137 +{
  138 + arm_timer_state *s = (arm_timer_state *)opaque;
  139 +
  140 + switch (offset >> 2) {
  141 + case 0: /* TimerLoad */
  142 + case 6: /* TimerBGLoad */
  143 + return s->limit;
  144 + case 1: /* TimerValue */
  145 + return arm_timer_getcount(s, qemu_get_clock(vm_clock));
  146 + case 2: /* TimerControl */
  147 + return s->control;
  148 + case 4: /* TimerRIS */
  149 + return s->int_level;
  150 + case 5: /* TimerMIS */
  151 + if ((s->control & TIMER_CTRL_IE) == 0)
  152 + return 0;
  153 + return s->int_level;
  154 + default:
  155 + cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
  156 + return 0;
  157 + }
  158 +}
  159 +
  160 +static void arm_timer_write(void *opaque, target_phys_addr_t offset,
  161 + uint32_t value)
  162 +{
  163 + arm_timer_state *s = (arm_timer_state *)opaque;
  164 + int64_t now;
  165 +
  166 + now = qemu_get_clock(vm_clock);
  167 + switch (offset >> 2) {
  168 + case 0: /* TimerLoad */
  169 + s->limit = value;
  170 + s->count = value;
  171 + s->expires = now;
  172 + arm_timer_reload(s);
  173 + break;
  174 + case 1: /* TimerValue */
  175 + /* ??? Linux seems to want to write to this readonly register.
  176 + Ignore it. */
  177 + break;
  178 + case 2: /* TimerControl */
  179 + if (s->control & TIMER_CTRL_ENABLE) {
  180 + /* Pause the timer if it is running. This may cause some
  181 + inaccuracy dure to rounding, but avoids a whole lot of other
  182 + messyness. */
  183 + s->count = arm_timer_getcount(s, now);
  184 + }
  185 + s->control = value;
  186 + s->freq = s->raw_freq;
  187 + /* ??? Need to recalculate expiry time after changing divisor. */
  188 + switch ((value >> 2) & 3) {
  189 + case 1: s->freq >>= 4; break;
  190 + case 2: s->freq >>= 8; break;
  191 + }
  192 + if (s->control & TIMER_CTRL_ENABLE) {
  193 + /* Restart the timer if still enabled. */
  194 + s->expires = now;
  195 + arm_timer_reload(s);
  196 + }
  197 + break;
  198 + case 3: /* TimerIntClr */
  199 + s->int_level = 0;
  200 + break;
  201 + case 6: /* TimerBGLoad */
  202 + s->limit = value;
  203 + break;
  204 + default:
  205 + cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
  206 + }
  207 + arm_timer_update(s, now);
  208 +}
  209 +
  210 +static void arm_timer_tick(void *opaque)
  211 +{
  212 + int64_t now;
  213 +
  214 + now = qemu_get_clock(vm_clock);
  215 + arm_timer_update((arm_timer_state *)opaque, now);
  216 +}
  217 +
  218 +static void *arm_timer_init(uint32_t freq, void *pic, int irq)
  219 +{
  220 + arm_timer_state *s;
  221 +
  222 + s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
  223 + s->pic = pic;
  224 + s->irq = irq;
  225 + s->raw_freq = s->freq = 1000000;
  226 + s->control = TIMER_CTRL_IE;
  227 + s->count = 0xffffffff;
  228 +
  229 + s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
  230 + /* ??? Save/restore. */
  231 + return s;
  232 +}
  233 +
  234 +/* ARM PrimeCell SP804 dual timer module.
  235 + Docs for this device don't seem to be publicly available. This
  236 + implementation is based on gueswork, the linux kernel sources and the
  237 + Integrator/CP timer modules. */
  238 +
  239 +typedef struct {
  240 + /* Include a pseudo-PIC device to merge the two interrupt sources. */
  241 + arm_pic_handler handler;
  242 + void *timer[2];
  243 + int level[2];
  244 + uint32_t base;
  245 + /* The output PIC device. */
  246 + void *pic;
  247 + int irq;
  248 +} sp804_state;
  249 +
  250 +static void sp804_set_irq(void *opaque, int irq, int level)
  251 +{
  252 + sp804_state *s = (sp804_state *)opaque;
  253 +
  254 + s->level[irq] = level;
  255 + pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]);
  256 +}
  257 +
  258 +static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
  259 +{
  260 + sp804_state *s = (sp804_state *)opaque;
  261 +
  262 + /* ??? Don't know the PrimeCell ID for this device. */
  263 + offset -= s->base;
  264 + if (offset < 0x20) {
  265 + return arm_timer_read(s->timer[0], offset);
  266 + } else {
  267 + return arm_timer_read(s->timer[1], offset - 0x20);
  268 + }
  269 +}
  270 +
  271 +static void sp804_write(void *opaque, target_phys_addr_t offset,
  272 + uint32_t value)
  273 +{
  274 + sp804_state *s = (sp804_state *)opaque;
  275 +
  276 + offset -= s->base;
  277 + if (offset < 0x20) {
  278 + arm_timer_write(s->timer[0], offset, value);
  279 + } else {
  280 + arm_timer_write(s->timer[1], offset - 0x20, value);
  281 + }
  282 +}
  283 +
  284 +static CPUReadMemoryFunc *sp804_readfn[] = {
  285 + sp804_read,
  286 + sp804_read,
  287 + sp804_read
  288 +};
  289 +
  290 +static CPUWriteMemoryFunc *sp804_writefn[] = {
  291 + sp804_write,
  292 + sp804_write,
  293 + sp804_write
  294 +};
  295 +
  296 +void sp804_init(uint32_t base, void *pic, int irq)
  297 +{
  298 + int iomemtype;
  299 + sp804_state *s;
  300 +
  301 + s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
  302 + s->handler = sp804_set_irq;
  303 + s->base = base;
  304 + s->pic = pic;
  305 + s->irq = irq;
  306 + /* ??? The timers are actually configurable between 32kHz and 1MHz, but
  307 + we don't implement that. */
  308 + s->timer[0] = arm_timer_init(1000000, s, 0);
  309 + s->timer[1] = arm_timer_init(1000000, s, 1);
  310 + iomemtype = cpu_register_io_memory(0, sp804_readfn,
  311 + sp804_writefn, s);
  312 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  313 + /* ??? Save/restore. */
  314 +}
  315 +
  316 +
  317 +/* Integrator/CP timer module. */
  318 +
  319 +typedef struct {
  320 + void *timer[3];
  321 + uint32_t base;
  322 +} icp_pit_state;
  323 +
  324 +static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
  325 +{
  326 + icp_pit_state *s = (icp_pit_state *)opaque;
  327 + int n;
  328 +
  329 + /* ??? Don't know the PrimeCell ID for this device. */
  330 + offset -= s->base;
  331 + n = offset >> 8;
  332 + if (n > 3)
  333 + cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
  334 +
  335 + return arm_timer_read(s->timer[n], offset & 0xff);
  336 +}
  337 +
  338 +static void icp_pit_write(void *opaque, target_phys_addr_t offset,
  339 + uint32_t value)
  340 +{
  341 + icp_pit_state *s = (icp_pit_state *)opaque;
  342 + int n;
  343 +
  344 + offset -= s->base;
  345 + n = offset >> 8;
  346 + if (n > 3)
  347 + cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
  348 +
  349 + arm_timer_write(s->timer[n], offset & 0xff, value);
  350 +}
  351 +
  352 +
  353 +static CPUReadMemoryFunc *icp_pit_readfn[] = {
  354 + icp_pit_read,
  355 + icp_pit_read,
  356 + icp_pit_read
  357 +};
  358 +
  359 +static CPUWriteMemoryFunc *icp_pit_writefn[] = {
  360 + icp_pit_write,
  361 + icp_pit_write,
  362 + icp_pit_write
  363 +};
  364 +
  365 +void icp_pit_init(uint32_t base, void *pic, int irq)
  366 +{
  367 + int iomemtype;
  368 + icp_pit_state *s;
  369 +
  370 + s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
  371 + s->base = base;
  372 + /* Timer 0 runs at the system clock speed (40MHz). */
  373 + s->timer[0] = arm_timer_init(40000000, pic, irq);
  374 + /* The other two timers run at 1MHz. */
  375 + s->timer[1] = arm_timer_init(1000000, pic, irq + 1);
  376 + s->timer[2] = arm_timer_init(1000000, pic, irq + 2);
  377 +
  378 + iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
  379 + icp_pit_writefn, s);
  380 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  381 + /* ??? Save/restore. */
  382 +}
  383 +
hw/integratorcp.c
1 /* 1 /*
2 * ARM Integrator CP System emulation. 2 * ARM Integrator CP System emulation.
3 * 3 *
4 - * Copyright (c) 2005 CodeSourcery, LLC. 4 + * Copyright (c) 2005-2006 CodeSourcery.
5 * Written by Paul Brook 5 * Written by Paul Brook
6 * 6 *
7 * This code is licenced under the GPL 7 * This code is licenced under the GPL
8 */ 8 */
9 9
10 -#include <vl.h> 10 +#include "vl.h"
  11 +#include "arm_pic.h"
11 12
12 #define KERNEL_ARGS_ADDR 0x100 13 #define KERNEL_ARGS_ADDR 0x100
13 #define KERNEL_LOAD_ADDR 0x00010000 14 #define KERNEL_LOAD_ADDR 0x00010000
14 #define INITRD_LOAD_ADDR 0x00800000 15 #define INITRD_LOAD_ADDR 0x00800000
15 16
16 -/* Stub functions for hardware that doesn't exist. */  
17 -void pic_set_irq(int irq, int level)  
18 -{  
19 - cpu_abort (cpu_single_env, "pic_set_irq");  
20 -}  
21 -  
22 -void pic_info(void)  
23 -{  
24 -}  
25 -  
26 -void irq_info(void)  
27 -{  
28 -}  
29 -  
30 void DMA_run (void) 17 void DMA_run (void)
31 { 18 {
32 } 19 }
@@ -284,41 +271,31 @@ static void integratorcm_init(int memsz, uint32_t flash_offset) @@ -284,41 +271,31 @@ static void integratorcm_init(int memsz, uint32_t flash_offset)
284 271
285 typedef struct icp_pic_state 272 typedef struct icp_pic_state
286 { 273 {
  274 + arm_pic_handler handler;
287 uint32_t base; 275 uint32_t base;
288 uint32_t level; 276 uint32_t level;
289 uint32_t irq_enabled; 277 uint32_t irq_enabled;
290 uint32_t fiq_enabled; 278 uint32_t fiq_enabled;
291 void *parent; 279 void *parent;
292 - /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */  
293 int parent_irq; 280 int parent_irq;
  281 + int parent_fiq;
294 } icp_pic_state; 282 } icp_pic_state;
295 283
296 static void icp_pic_update(icp_pic_state *s) 284 static void icp_pic_update(icp_pic_state *s)
297 { 285 {
298 - CPUState *env;  
299 - if (s->parent_irq != -1) {  
300 - uint32_t flags; 286 + uint32_t flags;
301 287
  288 + if (s->parent_irq != -1) {
302 flags = (s->level & s->irq_enabled); 289 flags = (s->level & s->irq_enabled);
303 - pic_set_irq_new(s->parent, s->parent_irq,  
304 - flags != 0);  
305 - return; 290 + pic_set_irq_new(s->parent, s->parent_irq, flags != 0);
306 } 291 }
307 - /* Raise CPU interrupt. */  
308 - env = (CPUState *)s->parent;  
309 - if (s->level & s->fiq_enabled) {  
310 - cpu_interrupt (env, CPU_INTERRUPT_FIQ);  
311 - } else {  
312 - cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ);  
313 - }  
314 - if (s->level & s->irq_enabled) {  
315 - cpu_interrupt (env, CPU_INTERRUPT_HARD);  
316 - } else {  
317 - cpu_reset_interrupt (env, CPU_INTERRUPT_HARD); 292 + if (s->parent_fiq != -1) {
  293 + flags = (s->level & s->fiq_enabled);
  294 + pic_set_irq_new(s->parent, s->parent_fiq, flags != 0);
318 } 295 }
319 } 296 }
320 297
321 -void pic_set_irq_new(void *opaque, int irq, int level) 298 +static void icp_pic_set_irq(void *opaque, int irq, int level)
322 { 299 {
323 icp_pic_state *s = (icp_pic_state *)opaque; 300 icp_pic_state *s = (icp_pic_state *)opaque;
324 if (level) 301 if (level)
@@ -408,7 +385,7 @@ static CPUWriteMemoryFunc *icp_pic_writefn[] = { @@ -408,7 +385,7 @@ static CPUWriteMemoryFunc *icp_pic_writefn[] = {
408 }; 385 };
409 386
410 static icp_pic_state *icp_pic_init(uint32_t base, void *parent, 387 static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
411 - int parent_irq) 388 + int parent_irq, int parent_fiq)
412 { 389 {
413 icp_pic_state *s; 390 icp_pic_state *s;
414 int iomemtype; 391 int iomemtype;
@@ -416,10 +393,11 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent, @@ -416,10 +393,11 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
416 s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); 393 s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
417 if (!s) 394 if (!s)
418 return NULL; 395 return NULL;
419 - 396 + s->handler = icp_pic_set_irq;
420 s->base = base; 397 s->base = base;
421 s->parent = parent; 398 s->parent = parent;
422 s->parent_irq = parent_irq; 399 s->parent_irq = parent_irq;
  400 + s->parent_fiq = parent_fiq;
423 iomemtype = cpu_register_io_memory(0, icp_pic_readfn, 401 iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
424 icp_pic_writefn, s); 402 icp_pic_writefn, s);
425 cpu_register_physical_memory(base, 0x007fffff, iomemtype); 403 cpu_register_physical_memory(base, 0x007fffff, iomemtype);
@@ -427,499 +405,6 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent, @@ -427,499 +405,6 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
427 return s; 405 return s;
428 } 406 }
429 407
430 -/* Timers. */  
431 -  
432 -/* System bus clock speed (40MHz) for timer 0. Not sure about this value. */  
433 -#define ICP_BUS_FREQ 40000000  
434 -  
435 -typedef struct {  
436 - int64_t next_time;  
437 - int64_t expires[3];  
438 - int64_t loaded[3];  
439 - QEMUTimer *timer;  
440 - icp_pic_state *pic;  
441 - uint32_t base;  
442 - uint32_t control[3];  
443 - uint32_t count[3];  
444 - uint32_t limit[3];  
445 - int freq[3];  
446 - int int_level[3];  
447 -} icp_pit_state;  
448 -  
449 -/* Calculate the new expiry time of the given timer. */  
450 -  
451 -static void icp_pit_reload(icp_pit_state *s, int n)  
452 -{  
453 - int64_t delay;  
454 -  
455 - s->loaded[n] = s->expires[n];  
456 - delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]);  
457 - if (delay == 0)  
458 - delay = 1;  
459 - s->expires[n] += delay;  
460 -}  
461 -  
462 -/* Check all active timers, and schedule the next timer interrupt. */  
463 -  
464 -static void icp_pit_update(icp_pit_state *s, int64_t now)  
465 -{  
466 - int n;  
467 - int64_t next;  
468 -  
469 - next = now;  
470 - for (n = 0; n < 3; n++) {  
471 - /* Ignore disabled timers. */  
472 - if ((s->control[n] & 0x80) == 0)  
473 - continue;  
474 - /* Ignore expired one-shot timers. */  
475 - if (s->count[n] == 0 && s->control[n] & 1)  
476 - continue;  
477 - if (s->expires[n] - now <= 0) {  
478 - /* Timer has expired. */  
479 - s->int_level[n] = 1;  
480 - if (s->control[n] & 1) {  
481 - /* One-shot. */  
482 - s->count[n] = 0;  
483 - } else {  
484 - if ((s->control[n] & 0x40) == 0) {  
485 - /* Free running. */  
486 - if (s->control[n] & 2)  
487 - s->count[n] = 0xffffffff;  
488 - else  
489 - s->count[n] = 0xffff;  
490 - } else {  
491 - /* Periodic. */  
492 - s->count[n] = s->limit[n];  
493 - }  
494 - }  
495 - }  
496 - while (s->expires[n] - now <= 0) {  
497 - icp_pit_reload(s, n);  
498 - }  
499 - }  
500 - /* Update interrupts. */  
501 - for (n = 0; n < 3; n++) {  
502 - if (s->int_level[n] && (s->control[n] & 0x20)) {  
503 - pic_set_irq_new(s->pic, 5 + n, 1);  
504 - } else {  
505 - pic_set_irq_new(s->pic, 5 + n, 0);  
506 - }  
507 - if (next - s->expires[n] < 0)  
508 - next = s->expires[n];  
509 - }  
510 - /* Schedule the next timer interrupt. */  
511 - if (next == now) {  
512 - qemu_del_timer(s->timer);  
513 - s->next_time = 0;  
514 - } else if (next != s->next_time) {  
515 - qemu_mod_timer(s->timer, next);  
516 - s->next_time = next;  
517 - }  
518 -}  
519 -  
520 -/* Return the current value of the timer. */  
521 -static uint32_t icp_pit_getcount(icp_pit_state *s, int n, int64_t now)  
522 -{  
523 - int64_t elapsed;  
524 - int64_t period;  
525 -  
526 - if (s->count[n] == 0)  
527 - return 0;  
528 - if ((s->control[n] & 0x80) == 0)  
529 - return s->count[n];  
530 - elapsed = now - s->loaded[n];  
531 - period = s->expires[n] - s->loaded[n];  
532 - /* If the timer should have expired then return 0. This can happen  
533 - when the host timer signal doesnt occur immediately. It's better to  
534 - have a timer appear to sit at zero for a while than have it wrap  
535 - around before the guest interrupt is raised. */  
536 - /* ??? Could we trigger the interrupt here? */  
537 - if (elapsed > period)  
538 - return 0;  
539 - /* We need to calculate count * elapsed / period without overfowing.  
540 - Scale both elapsed and period so they fit in a 32-bit int. */  
541 - while (period != (int32_t)period) {  
542 - period >>= 1;  
543 - elapsed >>= 1;  
544 - }  
545 - return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed)  
546 - / (int32_t)period;  
547 -}  
548 -  
549 -static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)  
550 -{  
551 - int n;  
552 - icp_pit_state *s = (icp_pit_state *)opaque;  
553 -  
554 - offset -= s->base;  
555 - n = offset >> 8;  
556 - if (n > 2)  
557 - cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset);  
558 - switch ((offset & 0xff) >> 2) {  
559 - case 0: /* TimerLoad */  
560 - case 6: /* TimerBGLoad */  
561 - return s->limit[n];  
562 - case 1: /* TimerValue */  
563 - return icp_pit_getcount(s, n, qemu_get_clock(vm_clock));  
564 - case 2: /* TimerControl */  
565 - return s->control[n];  
566 - case 4: /* TimerRIS */  
567 - return s->int_level[n];  
568 - case 5: /* TimerMIS */  
569 - if ((s->control[n] & 0x20) == 0)  
570 - return 0;  
571 - return s->int_level[n];  
572 - default:  
573 - cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset);  
574 - return 0;  
575 - }  
576 -}  
577 -  
578 -static void icp_pit_write(void *opaque, target_phys_addr_t offset,  
579 - uint32_t value)  
580 -{  
581 - icp_pit_state *s = (icp_pit_state *)opaque;  
582 - int n;  
583 - int64_t now;  
584 -  
585 - now = qemu_get_clock(vm_clock);  
586 - offset -= s->base;  
587 - n = offset >> 8;  
588 - if (n > 2)  
589 - cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset);  
590 -  
591 - switch ((offset & 0xff) >> 2) {  
592 - case 0: /* TimerLoad */  
593 - s->limit[n] = value;  
594 - s->count[n] = value;  
595 - s->expires[n] = now;  
596 - icp_pit_reload(s, n);  
597 - break;  
598 - case 1: /* TimerValue */  
599 - /* ??? Linux seems to want to write to this readonly register.  
600 - Ignore it. */  
601 - break;  
602 - case 2: /* TimerControl */  
603 - if (s->control[n] & 0x80) {  
604 - /* Pause the timer if it is running. This may cause some  
605 - inaccuracy dure to rounding, but avoids a whole lot of other  
606 - messyness. */  
607 - s->count[n] = icp_pit_getcount(s, n, now);  
608 - }  
609 - s->control[n] = value;  
610 - if (n == 0)  
611 - s->freq[n] = ICP_BUS_FREQ;  
612 - else  
613 - s->freq[n] = 1000000;  
614 - /* ??? Need to recalculate expiry time after changing divisor. */  
615 - switch ((value >> 2) & 3) {  
616 - case 1: s->freq[n] >>= 4; break;  
617 - case 2: s->freq[n] >>= 8; break;  
618 - }  
619 - if (s->control[n] & 0x80) {  
620 - /* Restart the timer if still enabled. */  
621 - s->expires[n] = now;  
622 - icp_pit_reload(s, n);  
623 - }  
624 - break;  
625 - case 3: /* TimerIntClr */  
626 - s->int_level[n] = 0;  
627 - break;  
628 - case 6: /* TimerBGLoad */  
629 - s->limit[n] = value;  
630 - break;  
631 - default:  
632 - cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset);  
633 - }  
634 - icp_pit_update(s, now);  
635 -}  
636 -  
637 -static void icp_pit_tick(void *opaque)  
638 -{  
639 - int64_t now;  
640 -  
641 - now = qemu_get_clock(vm_clock);  
642 - icp_pit_update((icp_pit_state *)opaque, now);  
643 -}  
644 -  
645 -static CPUReadMemoryFunc *icp_pit_readfn[] = {  
646 - icp_pit_read,  
647 - icp_pit_read,  
648 - icp_pit_read  
649 -};  
650 -  
651 -static CPUWriteMemoryFunc *icp_pit_writefn[] = {  
652 - icp_pit_write,  
653 - icp_pit_write,  
654 - icp_pit_write  
655 -};  
656 -  
657 -static void icp_pit_init(uint32_t base, icp_pic_state *pic)  
658 -{  
659 - int iomemtype;  
660 - icp_pit_state *s;  
661 - int n;  
662 -  
663 - s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));  
664 - s->base = base;  
665 - s->pic = pic;  
666 - s->freq[0] = ICP_BUS_FREQ;  
667 - s->freq[1] = 1000000;  
668 - s->freq[2] = 1000000;  
669 - for (n = 0; n < 3; n++) {  
670 - s->control[n] = 0x20;  
671 - s->count[n] = 0xffffffff;  
672 - }  
673 -  
674 - iomemtype = cpu_register_io_memory(0, icp_pit_readfn,  
675 - icp_pit_writefn, s);  
676 - cpu_register_physical_memory(base, 0x007fffff, iomemtype);  
677 - s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s);  
678 - /* ??? Save/restore. */  
679 -}  
680 -  
681 -/* ARM PrimeCell PL011 UART */  
682 -  
683 -typedef struct {  
684 - uint32_t base;  
685 - uint32_t readbuff;  
686 - uint32_t flags;  
687 - uint32_t lcr;  
688 - uint32_t cr;  
689 - uint32_t dmacr;  
690 - uint32_t int_enabled;  
691 - uint32_t int_level;  
692 - uint32_t read_fifo[16];  
693 - uint32_t ilpr;  
694 - uint32_t ibrd;  
695 - uint32_t fbrd;  
696 - uint32_t ifl;  
697 - int read_pos;  
698 - int read_count;  
699 - int read_trigger;  
700 - CharDriverState *chr;  
701 - icp_pic_state *pic;  
702 - int irq;  
703 -} pl011_state;  
704 -  
705 -#define PL011_INT_TX 0x20  
706 -#define PL011_INT_RX 0x10  
707 -  
708 -#define PL011_FLAG_TXFE 0x80  
709 -#define PL011_FLAG_RXFF 0x40  
710 -#define PL011_FLAG_TXFF 0x20  
711 -#define PL011_FLAG_RXFE 0x10  
712 -  
713 -static const unsigned char pl011_id[] =  
714 -{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };  
715 -  
716 -static void pl011_update(pl011_state *s)  
717 -{  
718 - uint32_t flags;  
719 -  
720 - flags = s->int_level & s->int_enabled;  
721 - pic_set_irq_new(s->pic, s->irq, flags != 0);  
722 -}  
723 -  
724 -static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)  
725 -{  
726 - pl011_state *s = (pl011_state *)opaque;  
727 - uint32_t c;  
728 -  
729 - offset -= s->base;  
730 - if (offset >= 0xfe0 && offset < 0x1000) {  
731 - return pl011_id[(offset - 0xfe0) >> 2];  
732 - }  
733 - switch (offset >> 2) {  
734 - case 0: /* UARTDR */  
735 - s->flags &= ~PL011_FLAG_RXFF;  
736 - c = s->read_fifo[s->read_pos];  
737 - if (s->read_count > 0) {  
738 - s->read_count--;  
739 - if (++s->read_pos == 16)  
740 - s->read_pos = 0;  
741 - }  
742 - if (s->read_count == 0) {  
743 - s->flags |= PL011_FLAG_RXFE;  
744 - }  
745 - if (s->read_count == s->read_trigger - 1)  
746 - s->int_level &= ~ PL011_INT_RX;  
747 - pl011_update(s);  
748 - return c;  
749 - case 1: /* UARTCR */  
750 - return 0;  
751 - case 6: /* UARTFR */  
752 - return s->flags;  
753 - case 8: /* UARTILPR */  
754 - return s->ilpr;  
755 - case 9: /* UARTIBRD */  
756 - return s->ibrd;  
757 - case 10: /* UARTFBRD */  
758 - return s->fbrd;  
759 - case 11: /* UARTLCR_H */  
760 - return s->lcr;  
761 - case 12: /* UARTCR */  
762 - return s->cr;  
763 - case 13: /* UARTIFLS */  
764 - return s->ifl;  
765 - case 14: /* UARTIMSC */  
766 - return s->int_enabled;  
767 - case 15: /* UARTRIS */  
768 - return s->int_level;  
769 - case 16: /* UARTMIS */  
770 - return s->int_level & s->int_enabled;  
771 - case 18: /* UARTDMACR */  
772 - return s->dmacr;  
773 - default:  
774 - cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);  
775 - return 0;  
776 - }  
777 -}  
778 -  
779 -static void pl011_set_read_trigger(pl011_state *s)  
780 -{  
781 -#if 0  
782 - /* The docs say the RX interrupt is triggered when the FIFO exceeds  
783 - the threshold. However linux only reads the FIFO in response to an  
784 - interrupt. Triggering the interrupt when the FIFO is non-empty seems  
785 - to make things work. */  
786 - if (s->lcr & 0x10)  
787 - s->read_trigger = (s->ifl >> 1) & 0x1c;  
788 - else  
789 -#endif  
790 - s->read_trigger = 1;  
791 -}  
792 -  
793 -static void pl011_write(void *opaque, target_phys_addr_t offset,  
794 - uint32_t value)  
795 -{  
796 - pl011_state *s = (pl011_state *)opaque;  
797 - unsigned char ch;  
798 -  
799 - offset -= s->base;  
800 - switch (offset >> 2) {  
801 - case 0: /* UARTDR */  
802 - /* ??? Check if transmitter is enabled. */  
803 - ch = value;  
804 - if (s->chr)  
805 - qemu_chr_write(s->chr, &ch, 1);  
806 - s->int_level |= PL011_INT_TX;  
807 - pl011_update(s);  
808 - break;  
809 - case 1: /* UARTCR */  
810 - s->cr = value;  
811 - break;  
812 - case 8: /* UARTUARTILPR */  
813 - s->ilpr = value;  
814 - break;  
815 - case 9: /* UARTIBRD */  
816 - s->ibrd = value;  
817 - break;  
818 - case 10: /* UARTFBRD */  
819 - s->fbrd = value;  
820 - break;  
821 - case 11: /* UARTLCR_H */  
822 - s->lcr = value;  
823 - pl011_set_read_trigger(s);  
824 - break;  
825 - case 12: /* UARTCR */  
826 - /* ??? Need to implement the enable and loopback bits. */  
827 - s->cr = value;  
828 - break;  
829 - case 13: /* UARTIFS */  
830 - s->ifl = value;  
831 - pl011_set_read_trigger(s);  
832 - break;  
833 - case 14: /* UARTIMSC */  
834 - s->int_enabled = value;  
835 - pl011_update(s);  
836 - break;  
837 - case 17: /* UARTICR */  
838 - s->int_level &= ~value;  
839 - pl011_update(s);  
840 - break;  
841 - case 18: /* UARTDMACR */  
842 - s->dmacr = value;  
843 - if (value & 3)  
844 - cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");  
845 - break;  
846 - default:  
847 - cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);  
848 - }  
849 -}  
850 -  
851 -static int pl011_can_recieve(void *opaque)  
852 -{  
853 - pl011_state *s = (pl011_state *)opaque;  
854 -  
855 - if (s->lcr & 0x10)  
856 - return s->read_count < 16;  
857 - else  
858 - return s->read_count < 1;  
859 -}  
860 -  
861 -static void pl011_recieve(void *opaque, const uint8_t *buf, int size)  
862 -{  
863 - pl011_state *s = (pl011_state *)opaque;  
864 - int slot;  
865 -  
866 - slot = s->read_pos + s->read_count;  
867 - if (slot >= 16)  
868 - slot -= 16;  
869 - s->read_fifo[slot] = *buf;  
870 - s->read_count++;  
871 - s->flags &= ~PL011_FLAG_RXFE;  
872 - if (s->cr & 0x10 || s->read_count == 16) {  
873 - s->flags |= PL011_FLAG_RXFF;  
874 - }  
875 - if (s->read_count == s->read_trigger) {  
876 - s->int_level |= PL011_INT_RX;  
877 - pl011_update(s);  
878 - }  
879 -}  
880 -  
881 -static void pl011_event(void *opaque, int event)  
882 -{  
883 - /* ??? Should probably implement break. */  
884 -}  
885 -  
886 -static CPUReadMemoryFunc *pl011_readfn[] = {  
887 - pl011_read,  
888 - pl011_read,  
889 - pl011_read  
890 -};  
891 -  
892 -static CPUWriteMemoryFunc *pl011_writefn[] = {  
893 - pl011_write,  
894 - pl011_write,  
895 - pl011_write  
896 -};  
897 -  
898 -static void pl011_init(uint32_t base, icp_pic_state *pic, int irq,  
899 - CharDriverState *chr)  
900 -{  
901 - int iomemtype;  
902 - pl011_state *s;  
903 -  
904 - s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));  
905 - iomemtype = cpu_register_io_memory(0, pl011_readfn,  
906 - pl011_writefn, s);  
907 - cpu_register_physical_memory(base, 0x007fffff, iomemtype);  
908 - s->base = base;  
909 - s->pic = pic;  
910 - s->irq = irq;  
911 - s->chr = chr;  
912 - s->read_trigger = 1;  
913 - s->ifl = 0x12;  
914 - s->cr = 0x300;  
915 - s->flags = 0x90;  
916 - if (chr){  
917 - qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);  
918 - qemu_chr_add_event_handler(chr, pl011_event);  
919 - }  
920 - /* ??? Save/restore. */  
921 -}  
922 -  
923 /* CP control registers. */ 408 /* CP control registers. */
924 typedef struct { 409 typedef struct {
925 uint32_t base; 410 uint32_t base;
@@ -985,122 +470,6 @@ static void icp_control_init(uint32_t base) @@ -985,122 +470,6 @@ static void icp_control_init(uint32_t base)
985 } 470 }
986 471
987 472
988 -/* Keyboard/Mouse Interface. */  
989 -  
990 -typedef struct {  
991 - void *dev;  
992 - uint32_t base;  
993 - uint32_t cr;  
994 - uint32_t clk;  
995 - uint32_t last;  
996 - icp_pic_state *pic;  
997 - int pending;  
998 - int irq;  
999 - int is_mouse;  
1000 -} icp_kmi_state;  
1001 -  
1002 -static void icp_kmi_update(void *opaque, int level)  
1003 -{  
1004 - icp_kmi_state *s = (icp_kmi_state *)opaque;  
1005 - int raise;  
1006 -  
1007 - s->pending = level;  
1008 - raise = (s->pending && (s->cr & 0x10) != 0)  
1009 - || (s->cr & 0x08) != 0;  
1010 - pic_set_irq_new(s->pic, s->irq, raise);  
1011 -}  
1012 -  
1013 -static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset)  
1014 -{  
1015 - icp_kmi_state *s = (icp_kmi_state *)opaque;  
1016 - offset -= s->base;  
1017 - if (offset >= 0xfe0 && offset < 0x1000)  
1018 - return 0;  
1019 -  
1020 - switch (offset >> 2) {  
1021 - case 0: /* KMICR */  
1022 - return s->cr;  
1023 - case 1: /* KMISTAT */  
1024 - /* KMIC and KMID bits not implemented. */  
1025 - if (s->pending) {  
1026 - return 0x10;  
1027 - } else {  
1028 - return 0;  
1029 - }  
1030 - case 2: /* KMIDATA */  
1031 - if (s->pending)  
1032 - s->last = ps2_read_data(s->dev);  
1033 - return s->last;  
1034 - case 3: /* KMICLKDIV */  
1035 - return s->clk;  
1036 - case 4: /* KMIIR */  
1037 - return s->pending | 2;  
1038 - default:  
1039 - cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset);  
1040 - return 0;  
1041 - }  
1042 -}  
1043 -  
1044 -static void icp_kmi_write(void *opaque, target_phys_addr_t offset,  
1045 - uint32_t value)  
1046 -{  
1047 - icp_kmi_state *s = (icp_kmi_state *)opaque;  
1048 - offset -= s->base;  
1049 - switch (offset >> 2) {  
1050 - case 0: /* KMICR */  
1051 - s->cr = value;  
1052 - icp_kmi_update(s, s->pending);  
1053 - /* ??? Need to implement the enable/disable bit. */  
1054 - break;  
1055 - case 2: /* KMIDATA */  
1056 - /* ??? This should toggle the TX interrupt line. */  
1057 - /* ??? This means kbd/mouse can block each other. */  
1058 - if (s->is_mouse) {  
1059 - ps2_write_mouse(s->dev, value);  
1060 - } else {  
1061 - ps2_write_keyboard(s->dev, value);  
1062 - }  
1063 - break;  
1064 - case 3: /* KMICLKDIV */  
1065 - s->clk = value;  
1066 - return;  
1067 - default:  
1068 - cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset);  
1069 - }  
1070 -}  
1071 -static CPUReadMemoryFunc *icp_kmi_readfn[] = {  
1072 - icp_kmi_read,  
1073 - icp_kmi_read,  
1074 - icp_kmi_read  
1075 -};  
1076 -  
1077 -static CPUWriteMemoryFunc *icp_kmi_writefn[] = {  
1078 - icp_kmi_write,  
1079 - icp_kmi_write,  
1080 - icp_kmi_write  
1081 -};  
1082 -  
1083 -static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq,  
1084 - int is_mouse)  
1085 -{  
1086 - int iomemtype;  
1087 - icp_kmi_state *s;  
1088 -  
1089 - s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state));  
1090 - iomemtype = cpu_register_io_memory(0, icp_kmi_readfn,  
1091 - icp_kmi_writefn, s);  
1092 - cpu_register_physical_memory(base, 0x007fffff, iomemtype);  
1093 - s->base = base;  
1094 - s->pic = pic;  
1095 - s->irq = irq;  
1096 - s->is_mouse = is_mouse;  
1097 - if (is_mouse)  
1098 - s->dev = ps2_mouse_init(icp_kmi_update, s);  
1099 - else  
1100 - s->dev = ps2_kbd_init(icp_kmi_update, s);  
1101 - /* ??? Save/restore. */  
1102 -}  
1103 -  
1104 /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ 473 /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
1105 static uint32_t bootloader[] = { 474 static uint32_t bootloader[] = {
1106 0xe3a00000, /* mov r0, #0 */ 475 0xe3a00000, /* mov r0, #0 */
@@ -1162,6 +531,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, @@ -1162,6 +531,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
1162 CPUState *env; 531 CPUState *env;
1163 uint32_t bios_offset; 532 uint32_t bios_offset;
1164 icp_pic_state *pic; 533 icp_pic_state *pic;
  534 + void *cpu_pic;
1165 int kernel_size; 535 int kernel_size;
1166 int initrd_size; 536 int initrd_size;
1167 int n; 537 int n;
@@ -1177,14 +547,15 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, @@ -1177,14 +547,15 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
1177 cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); 547 cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM);
1178 548
1179 integratorcm_init(ram_size >> 20, bios_offset); 549 integratorcm_init(ram_size >> 20, bios_offset);
1180 - pic = icp_pic_init(0x14000000, env, -1);  
1181 - icp_pic_init(0xca000000, pic, 26);  
1182 - icp_pit_init(0x13000000, pic); 550 + cpu_pic = arm_pic_init_cpu(env);
  551 + pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
  552 + icp_pic_init(0xca000000, pic, 26, -1);
  553 + icp_pit_init(0x13000000, pic, 5);
1183 pl011_init(0x16000000, pic, 1, serial_hds[0]); 554 pl011_init(0x16000000, pic, 1, serial_hds[0]);
1184 pl011_init(0x17000000, pic, 2, serial_hds[1]); 555 pl011_init(0x17000000, pic, 2, serial_hds[1]);
1185 icp_control_init(0xcb000000); 556 icp_control_init(0xcb000000);
1186 - icp_kmi_init(0x18000000, pic, 3, 0);  
1187 - icp_kmi_init(0x19000000, pic, 4, 1); 557 + pl050_init(0x18000000, pic, 3, 0);
  558 + pl050_init(0x19000000, pic, 4, 1);
1188 if (nd_table[0].vlan) { 559 if (nd_table[0].vlan) {
1189 if (nd_table[0].model == NULL 560 if (nd_table[0].model == NULL
1190 || strcmp(nd_table[0].model, "smc91c111") == 0) { 561 || strcmp(nd_table[0].model, "smc91c111") == 0) {
hw/pl011.c 0 → 100644
  1 +/*
  2 + * Arm PrimeCell PL011 UART
  3 + *
  4 + * Copyright (c) 2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +
  12 +typedef struct {
  13 + uint32_t base;
  14 + uint32_t readbuff;
  15 + uint32_t flags;
  16 + uint32_t lcr;
  17 + uint32_t cr;
  18 + uint32_t dmacr;
  19 + uint32_t int_enabled;
  20 + uint32_t int_level;
  21 + uint32_t read_fifo[16];
  22 + uint32_t ilpr;
  23 + uint32_t ibrd;
  24 + uint32_t fbrd;
  25 + uint32_t ifl;
  26 + int read_pos;
  27 + int read_count;
  28 + int read_trigger;
  29 + CharDriverState *chr;
  30 + void *pic;
  31 + int irq;
  32 +} pl011_state;
  33 +
  34 +#define PL011_INT_TX 0x20
  35 +#define PL011_INT_RX 0x10
  36 +
  37 +#define PL011_FLAG_TXFE 0x80
  38 +#define PL011_FLAG_RXFF 0x40
  39 +#define PL011_FLAG_TXFF 0x20
  40 +#define PL011_FLAG_RXFE 0x10
  41 +
  42 +static const unsigned char pl011_id[] =
  43 +{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
  44 +
  45 +static void pl011_update(pl011_state *s)
  46 +{
  47 + uint32_t flags;
  48 +
  49 + flags = s->int_level & s->int_enabled;
  50 + pic_set_irq_new(s->pic, s->irq, flags != 0);
  51 +}
  52 +
  53 +static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
  54 +{
  55 + pl011_state *s = (pl011_state *)opaque;
  56 + uint32_t c;
  57 +
  58 + offset -= s->base;
  59 + if (offset >= 0xfe0 && offset < 0x1000) {
  60 + return pl011_id[(offset - 0xfe0) >> 2];
  61 + }
  62 + switch (offset >> 2) {
  63 + case 0: /* UARTDR */
  64 + s->flags &= ~PL011_FLAG_RXFF;
  65 + c = s->read_fifo[s->read_pos];
  66 + if (s->read_count > 0) {
  67 + s->read_count--;
  68 + if (++s->read_pos == 16)
  69 + s->read_pos = 0;
  70 + }
  71 + if (s->read_count == 0) {
  72 + s->flags |= PL011_FLAG_RXFE;
  73 + }
  74 + if (s->read_count == s->read_trigger - 1)
  75 + s->int_level &= ~ PL011_INT_RX;
  76 + pl011_update(s);
  77 + return c;
  78 + case 1: /* UARTCR */
  79 + return 0;
  80 + case 6: /* UARTFR */
  81 + return s->flags;
  82 + case 8: /* UARTILPR */
  83 + return s->ilpr;
  84 + case 9: /* UARTIBRD */
  85 + return s->ibrd;
  86 + case 10: /* UARTFBRD */
  87 + return s->fbrd;
  88 + case 11: /* UARTLCR_H */
  89 + return s->lcr;
  90 + case 12: /* UARTCR */
  91 + return s->cr;
  92 + case 13: /* UARTIFLS */
  93 + return s->ifl;
  94 + case 14: /* UARTIMSC */
  95 + return s->int_enabled;
  96 + case 15: /* UARTRIS */
  97 + return s->int_level;
  98 + case 16: /* UARTMIS */
  99 + return s->int_level & s->int_enabled;
  100 + case 18: /* UARTDMACR */
  101 + return s->dmacr;
  102 + default:
  103 + cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
  104 + return 0;
  105 + }
  106 +}
  107 +
  108 +static void pl011_set_read_trigger(pl011_state *s)
  109 +{
  110 +#if 0
  111 + /* The docs say the RX interrupt is triggered when the FIFO exceeds
  112 + the threshold. However linux only reads the FIFO in response to an
  113 + interrupt. Triggering the interrupt when the FIFO is non-empty seems
  114 + to make things work. */
  115 + if (s->lcr & 0x10)
  116 + s->read_trigger = (s->ifl >> 1) & 0x1c;
  117 + else
  118 +#endif
  119 + s->read_trigger = 1;
  120 +}
  121 +
  122 +static void pl011_write(void *opaque, target_phys_addr_t offset,
  123 + uint32_t value)
  124 +{
  125 + pl011_state *s = (pl011_state *)opaque;
  126 + unsigned char ch;
  127 +
  128 + offset -= s->base;
  129 + switch (offset >> 2) {
  130 + case 0: /* UARTDR */
  131 + /* ??? Check if transmitter is enabled. */
  132 + ch = value;
  133 + if (s->chr)
  134 + qemu_chr_write(s->chr, &ch, 1);
  135 + s->int_level |= PL011_INT_TX;
  136 + pl011_update(s);
  137 + break;
  138 + case 1: /* UARTCR */
  139 + s->cr = value;
  140 + break;
  141 + case 8: /* UARTUARTILPR */
  142 + s->ilpr = value;
  143 + break;
  144 + case 9: /* UARTIBRD */
  145 + s->ibrd = value;
  146 + break;
  147 + case 10: /* UARTFBRD */
  148 + s->fbrd = value;
  149 + break;
  150 + case 11: /* UARTLCR_H */
  151 + s->lcr = value;
  152 + pl011_set_read_trigger(s);
  153 + break;
  154 + case 12: /* UARTCR */
  155 + /* ??? Need to implement the enable and loopback bits. */
  156 + s->cr = value;
  157 + break;
  158 + case 13: /* UARTIFS */
  159 + s->ifl = value;
  160 + pl011_set_read_trigger(s);
  161 + break;
  162 + case 14: /* UARTIMSC */
  163 + s->int_enabled = value;
  164 + pl011_update(s);
  165 + break;
  166 + case 17: /* UARTICR */
  167 + s->int_level &= ~value;
  168 + pl011_update(s);
  169 + break;
  170 + case 18: /* UARTDMACR */
  171 + s->dmacr = value;
  172 + if (value & 3)
  173 + cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
  174 + break;
  175 + default:
  176 + cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
  177 + }
  178 +}
  179 +
  180 +static int pl011_can_recieve(void *opaque)
  181 +{
  182 + pl011_state *s = (pl011_state *)opaque;
  183 +
  184 + if (s->lcr & 0x10)
  185 + return s->read_count < 16;
  186 + else
  187 + return s->read_count < 1;
  188 +}
  189 +
  190 +static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
  191 +{
  192 + pl011_state *s = (pl011_state *)opaque;
  193 + int slot;
  194 +
  195 + slot = s->read_pos + s->read_count;
  196 + if (slot >= 16)
  197 + slot -= 16;
  198 + s->read_fifo[slot] = *buf;
  199 + s->read_count++;
  200 + s->flags &= ~PL011_FLAG_RXFE;
  201 + if (s->cr & 0x10 || s->read_count == 16) {
  202 + s->flags |= PL011_FLAG_RXFF;
  203 + }
  204 + if (s->read_count == s->read_trigger) {
  205 + s->int_level |= PL011_INT_RX;
  206 + pl011_update(s);
  207 + }
  208 +}
  209 +
  210 +static void pl011_event(void *opaque, int event)
  211 +{
  212 + /* ??? Should probably implement break. */
  213 +}
  214 +
  215 +static CPUReadMemoryFunc *pl011_readfn[] = {
  216 + pl011_read,
  217 + pl011_read,
  218 + pl011_read
  219 +};
  220 +
  221 +static CPUWriteMemoryFunc *pl011_writefn[] = {
  222 + pl011_write,
  223 + pl011_write,
  224 + pl011_write
  225 +};
  226 +
  227 +void pl011_init(uint32_t base, void *pic, int irq,
  228 + CharDriverState *chr)
  229 +{
  230 + int iomemtype;
  231 + pl011_state *s;
  232 +
  233 + s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
  234 + iomemtype = cpu_register_io_memory(0, pl011_readfn,
  235 + pl011_writefn, s);
  236 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  237 + s->base = base;
  238 + s->pic = pic;
  239 + s->irq = irq;
  240 + s->chr = chr;
  241 + s->read_trigger = 1;
  242 + s->ifl = 0x12;
  243 + s->cr = 0x300;
  244 + s->flags = 0x90;
  245 + if (chr){
  246 + qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
  247 + qemu_chr_add_event_handler(chr, pl011_event);
  248 + }
  249 + /* ??? Save/restore. */
  250 +}
  251 +
hw/pl050.c 0 → 100644
  1 +/*
  2 + * Arm PrimeCell PL050 Kyeboard / Mouse Interface
  3 + *
  4 + * Copyright (c) 2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +
  12 +typedef struct {
  13 + void *dev;
  14 + uint32_t base;
  15 + uint32_t cr;
  16 + uint32_t clk;
  17 + uint32_t last;
  18 + void *pic;
  19 + int pending;
  20 + int irq;
  21 + int is_mouse;
  22 +} pl050_state;
  23 +
  24 +static const unsigned char pl050_id[] =
  25 +{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
  26 +
  27 +static void pl050_update(void *opaque, int level)
  28 +{
  29 + pl050_state *s = (pl050_state *)opaque;
  30 + int raise;
  31 +
  32 + s->pending = level;
  33 + raise = (s->pending && (s->cr & 0x10) != 0)
  34 + || (s->cr & 0x08) != 0;
  35 + pic_set_irq_new(s->pic, s->irq, raise);
  36 +}
  37 +
  38 +static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
  39 +{
  40 + pl050_state *s = (pl050_state *)opaque;
  41 + offset -= s->base;
  42 + if (offset >= 0xfe0 && offset < 0x1000)
  43 + return pl050_id[(offset - 0xfe0) >> 2];
  44 +
  45 + switch (offset >> 2) {
  46 + case 0: /* KMICR */
  47 + return s->cr;
  48 + case 1: /* KMISTAT */
  49 + /* KMIC and KMID bits not implemented. */
  50 + if (s->pending) {
  51 + return 0x10;
  52 + } else {
  53 + return 0;
  54 + }
  55 + case 2: /* KMIDATA */
  56 + if (s->pending)
  57 + s->last = ps2_read_data(s->dev);
  58 + return s->last;
  59 + case 3: /* KMICLKDIV */
  60 + return s->clk;
  61 + case 4: /* KMIIR */
  62 + return s->pending | 2;
  63 + default:
  64 + cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset);
  65 + return 0;
  66 + }
  67 +}
  68 +
  69 +static void pl050_write(void *opaque, target_phys_addr_t offset,
  70 + uint32_t value)
  71 +{
  72 + pl050_state *s = (pl050_state *)opaque;
  73 + offset -= s->base;
  74 + switch (offset >> 2) {
  75 + case 0: /* KMICR */
  76 + s->cr = value;
  77 + pl050_update(s, s->pending);
  78 + /* ??? Need to implement the enable/disable bit. */
  79 + break;
  80 + case 2: /* KMIDATA */
  81 + /* ??? This should toggle the TX interrupt line. */
  82 + /* ??? This means kbd/mouse can block each other. */
  83 + if (s->is_mouse) {
  84 + ps2_write_mouse(s->dev, value);
  85 + } else {
  86 + ps2_write_keyboard(s->dev, value);
  87 + }
  88 + break;
  89 + case 3: /* KMICLKDIV */
  90 + s->clk = value;
  91 + return;
  92 + default:
  93 + cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset);
  94 + }
  95 +}
  96 +static CPUReadMemoryFunc *pl050_readfn[] = {
  97 + pl050_read,
  98 + pl050_read,
  99 + pl050_read
  100 +};
  101 +
  102 +static CPUWriteMemoryFunc *pl050_writefn[] = {
  103 + pl050_write,
  104 + pl050_write,
  105 + pl050_write
  106 +};
  107 +
  108 +void pl050_init(uint32_t base, void *pic, int irq, int is_mouse)
  109 +{
  110 + int iomemtype;
  111 + pl050_state *s;
  112 +
  113 + s = (pl050_state *)qemu_mallocz(sizeof(pl050_state));
  114 + iomemtype = cpu_register_io_memory(0, pl050_readfn,
  115 + pl050_writefn, s);
  116 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  117 + s->base = base;
  118 + s->pic = pic;
  119 + s->irq = irq;
  120 + s->is_mouse = is_mouse;
  121 + if (is_mouse)
  122 + s->dev = ps2_mouse_init(pl050_update, s);
  123 + else
  124 + s->dev = ps2_kbd_init(pl050_update, s);
  125 + /* ??? Save/restore. */
  126 +}
  127 +
hw/pl080.c 0 → 100644
  1 +/*
  2 + * Arm PrimeCell PL080 DMA controller
  3 + *
  4 + * Copyright (c) 2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +
  12 +#define PL080_NUM_CHANNELS 8
  13 +#define PL080_CONF_E 0x1
  14 +#define PL080_CONF_M1 0x2
  15 +#define PL080_CONF_M2 0x4
  16 +
  17 +#define PL080_CCONF_H 0x40000
  18 +#define PL080_CCONF_A 0x20000
  19 +#define PL080_CCONF_L 0x10000
  20 +#define PL080_CCONF_ITC 0x08000
  21 +#define PL080_CCONF_IE 0x04000
  22 +#define PL080_CCONF_E 0x00001
  23 +
  24 +#define PL080_CCTRL_I 0x80000000
  25 +#define PL080_CCTRL_DI 0x08000000
  26 +#define PL080_CCTRL_SI 0x04000000
  27 +#define PL080_CCTRL_D 0x02000000
  28 +#define PL080_CCTRL_S 0x01000000
  29 +
  30 +typedef struct {
  31 + uint32_t src;
  32 + uint32_t dest;
  33 + uint32_t lli;
  34 + uint32_t ctrl;
  35 + uint32_t conf;
  36 +} pl080_channel;
  37 +
  38 +typedef struct {
  39 + uint32_t base;
  40 + uint8_t tc_int;
  41 + uint8_t tc_mask;
  42 + uint8_t err_int;
  43 + uint8_t err_mask;
  44 + uint32_t conf;
  45 + uint32_t sync;
  46 + uint32_t req_single;
  47 + uint32_t req_burst;
  48 + pl080_channel chan[PL080_NUM_CHANNELS];
  49 + /* Flag to avoid recursive DMA invocations. */
  50 + int running;
  51 + void *pic;
  52 + int irq;
  53 +} pl080_state;
  54 +
  55 +static const unsigned char pl080_id[] =
  56 +{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
  57 +
  58 +static void pl080_update(pl080_state *s)
  59 +{
  60 + if ((s->tc_int & s->tc_mask)
  61 + || (s->err_int & s->err_mask))
  62 + pic_set_irq_new(s->pic, s->irq, 1);
  63 + else
  64 + pic_set_irq_new(s->pic, s->irq, 1);
  65 +}
  66 +
  67 +static void pl080_run(pl080_state *s)
  68 +{
  69 + int c;
  70 + int flow;
  71 + pl080_channel *ch;
  72 + int swidth;
  73 + int dwidth;
  74 + int xsize;
  75 + int n;
  76 + int src_id;
  77 + int dest_id;
  78 + int size;
  79 + char buff[4];
  80 + uint32_t req;
  81 +
  82 + s->tc_mask = 0;
  83 + for (c = 0; c < PL080_NUM_CHANNELS; c++) {
  84 + if (s->chan[c].conf & PL080_CCONF_ITC)
  85 + s->tc_mask |= 1 << c;
  86 + if (s->chan[c].conf & PL080_CCONF_IE)
  87 + s->err_mask |= 1 << c;
  88 + }
  89 +
  90 + if ((s->conf & PL080_CONF_E) == 0)
  91 + return;
  92 +
  93 +cpu_abort(cpu_single_env, "DMA active\n");
  94 + /* If we are already in the middle of a DMA operation then indicate that
  95 + there may be new DMA requests and return immediately. */
  96 + if (s->running) {
  97 + s->running++;
  98 + return;
  99 + }
  100 + s->running = 1;
  101 + while (s->running) {
  102 + for (c = 0; c < PL080_NUM_CHANNELS; c++) {
  103 + ch = &s->chan[c];
  104 +again:
  105 + /* Test if thiws channel has any pending DMA requests. */
  106 + if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
  107 + != PL080_CCONF_E)
  108 + continue;
  109 + flow = (ch->conf >> 11) & 7;
  110 + if (flow >= 4) {
  111 + cpu_abort(cpu_single_env,
  112 + "pl080_run: Peripheral flow control not implemented\n");
  113 + }
  114 + src_id = (ch->conf >> 1) & 0x1f;
  115 + dest_id = (ch->conf >> 6) & 0x1f;
  116 + size = ch->ctrl & 0xfff;
  117 + req = s->req_single | s->req_burst;
  118 + switch (flow) {
  119 + case 0:
  120 + break;
  121 + case 1:
  122 + if ((req & (1u << dest_id)) == 0)
  123 + size = 0;
  124 + break;
  125 + case 2:
  126 + if ((req & (1u << src_id)) == 0)
  127 + size = 0;
  128 + break;
  129 + case 3:
  130 + if ((req & (1u << src_id)) == 0
  131 + || (req & (1u << dest_id)) == 0)
  132 + size = 0;
  133 + break;
  134 + }
  135 + if (!size)
  136 + continue;
  137 +
  138 + /* Transfer one element. */
  139 + /* ??? Should transfer multiple elements for a burst request. */
  140 + /* ??? Unclear what the proper behavior is when source and
  141 + destination widths are different. */
  142 + swidth = 1 << ((ch->ctrl >> 18) & 7);
  143 + dwidth = 1 << ((ch->ctrl >> 21) & 7);
  144 + for (n = 0; n < dwidth; n+= swidth) {
  145 + cpu_physical_memory_read(ch->src, buff + n, swidth);
  146 + if (ch->ctrl & PL080_CCTRL_SI)
  147 + ch->src += swidth;
  148 + }
  149 + xsize = (dwidth < swidth) ? swidth : dwidth;
  150 + /* ??? This may pad the value incorrectly for dwidth < 32. */
  151 + for (n = 0; n < xsize; n += dwidth) {
  152 + cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
  153 + if (ch->ctrl & PL080_CCTRL_DI)
  154 + ch->dest += swidth;
  155 + }
  156 +
  157 + size--;
  158 + ch->ctrl = (ch->ctrl & 0xfffff000) | size;
  159 + if (size == 0) {
  160 + /* Transfer complete. */
  161 + if (ch->lli) {
  162 + ch->src = ldl_phys(ch->lli);
  163 + ch->dest = ldl_phys(ch->lli + 4);
  164 + ch->ctrl = ldl_phys(ch->lli + 12);
  165 + ch->lli = ldl_phys(ch->lli + 8);
  166 + } else {
  167 + ch->conf &= ~PL080_CCONF_E;
  168 + }
  169 + if (ch->ctrl & PL080_CCTRL_I) {
  170 + s->tc_int |= 1 << c;
  171 + }
  172 + }
  173 + goto again;
  174 + }
  175 + if (--s->running)
  176 + s->running = 1;
  177 + }
  178 +}
  179 +
  180 +static uint32_t pl080_read(void *opaque, target_phys_addr_t offset)
  181 +{
  182 + pl080_state *s = (pl080_state *)opaque;
  183 + uint32_t i;
  184 + uint32_t mask;
  185 +
  186 + offset -= s->base;
  187 + if (offset >= 0xfe0 && offset < 0x1000) {
  188 + return pl080_id[(offset - 0xfe0) >> 2];
  189 + }
  190 + if (offset >= 0x100 && offset < 0x200) {
  191 + i = (offset & 0xe0) >> 5;
  192 + switch (offset >> 2) {
  193 + case 0: /* SrcAddr */
  194 + return s->chan[i].src;
  195 + case 1: /* DestAddr */
  196 + return s->chan[i].dest;
  197 + case 2: /* LLI */
  198 + return s->chan[i].lli;
  199 + case 3: /* Control */
  200 + return s->chan[i].ctrl;
  201 + case 4: /* Configuration */
  202 + return s->chan[i].conf;
  203 + default:
  204 + goto bad_offset;
  205 + }
  206 + }
  207 + switch (offset >> 2) {
  208 + case 0: /* IntStatus */
  209 + return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
  210 + case 1: /* IntTCStatus */
  211 + return (s->tc_int & s->tc_mask);
  212 + case 3: /* IntErrorStatus */
  213 + return (s->err_int & s->err_mask);
  214 + case 5: /* RawIntTCStatus */
  215 + return s->tc_int;
  216 + case 6: /* RawIntErrorStatus */
  217 + return s->err_int;
  218 + case 7: /* EnbldChns */
  219 + mask = 0;
  220 + for (i = 0; i < PL080_NUM_CHANNELS; i++) {
  221 + if (s->chan[i].conf & PL080_CCONF_E)
  222 + mask |= 1 << i;
  223 + }
  224 + return mask;
  225 + case 8: /* SoftBReq */
  226 + case 9: /* SoftSReq */
  227 + case 10: /* SoftLBReq */
  228 + case 11: /* SoftLSReq */
  229 + /* ??? Implement these. */
  230 + return 0;
  231 + case 12: /* Configuration */
  232 + return s->conf;
  233 + case 13: /* Sync */
  234 + return s->sync;
  235 + default:
  236 + bad_offset:
  237 + cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", offset);
  238 + return 0;
  239 + }
  240 +}
  241 +
  242 +static void pl080_write(void *opaque, target_phys_addr_t offset,
  243 + uint32_t value)
  244 +{
  245 + pl080_state *s = (pl080_state *)opaque;
  246 + int i;
  247 +
  248 + offset -= s->base;
  249 + if (offset >= 0x100 && offset < 0x200) {
  250 + i = (offset & 0xe0) >> 5;
  251 + switch (offset >> 2) {
  252 + case 0: /* SrcAddr */
  253 + s->chan[i].src = value;
  254 + break;
  255 + case 1: /* DestAddr */
  256 + s->chan[i].dest = value;
  257 + break;
  258 + case 2: /* LLI */
  259 + s->chan[i].lli = value;
  260 + break;
  261 + case 3: /* Control */
  262 + s->chan[i].ctrl = value;
  263 + break;
  264 + case 4: /* Configuration */
  265 + s->chan[i].conf = value;
  266 + pl080_run(s);
  267 + break;
  268 + }
  269 + }
  270 + switch (offset >> 2) {
  271 + case 2: /* IntTCClear */
  272 + s->tc_int &= ~value;
  273 + break;
  274 + case 4: /* IntErrorClear */
  275 + s->err_int &= ~value;
  276 + break;
  277 + case 8: /* SoftBReq */
  278 + case 9: /* SoftSReq */
  279 + case 10: /* SoftLBReq */
  280 + case 11: /* SoftLSReq */
  281 + /* ??? Implement these. */
  282 + cpu_abort(cpu_single_env, "pl080_write: Soft DMA not implemented\n");
  283 + break;
  284 + case 12: /* Configuration */
  285 + s->conf = value;
  286 + if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
  287 + cpu_abort(cpu_single_env,
  288 + "pl080_write: Big-endian DMA not implemented\n");
  289 + }
  290 + pl080_run(s);
  291 + break;
  292 + case 13: /* Sync */
  293 + s->sync = value;
  294 + break;
  295 + default:
  296 + cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset);
  297 + }
  298 + pl080_update(s);
  299 +}
  300 +
  301 +static CPUReadMemoryFunc *pl080_readfn[] = {
  302 + pl080_read,
  303 + pl080_read,
  304 + pl080_read
  305 +};
  306 +
  307 +static CPUWriteMemoryFunc *pl080_writefn[] = {
  308 + pl080_write,
  309 + pl080_write,
  310 + pl080_write
  311 +};
  312 +
  313 +void *pl080_init(uint32_t base, void *pic, int irq)
  314 +{
  315 + int iomemtype;
  316 + pl080_state *s;
  317 +
  318 + s = (pl080_state *)qemu_mallocz(sizeof(pl080_state));
  319 + iomemtype = cpu_register_io_memory(0, pl080_readfn,
  320 + pl080_writefn, s);
  321 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  322 + s->base = base;
  323 + s->pic = pic;
  324 + s->irq = irq;
  325 + /* ??? Save/restore. */
  326 + return s;
  327 +}
  328 +
hw/pl110.c
1 /* 1 /*
2 * Arm PrimeCell PL110 Color LCD Controller 2 * Arm PrimeCell PL110 Color LCD Controller
3 * 3 *
4 - * Copyright (c) 2005 CodeSourcery, LLC. 4 + * Copyright (c) 2005-2006 CodeSourcery.
5 * Written by Paul Brook 5 * Written by Paul Brook
6 * 6 *
7 * This code is licenced under the GNU LGPL 7 * This code is licenced under the GNU LGPL
@@ -27,6 +27,8 @@ enum pl110_bppmode @@ -27,6 +27,8 @@ enum pl110_bppmode
27 typedef struct { 27 typedef struct {
28 uint32_t base; 28 uint32_t base;
29 DisplayState *ds; 29 DisplayState *ds;
  30 + /* The Versatile/PB uses a slightly modified PL110 controller. */
  31 + int versatile;
30 void *pic; 32 void *pic;
31 uint32_t timing[4]; 33 uint32_t timing[4];
32 uint32_t cr; 34 uint32_t cr;
@@ -46,6 +48,15 @@ typedef struct { @@ -46,6 +48,15 @@ typedef struct {
46 static const unsigned char pl110_id[] = 48 static const unsigned char pl110_id[] =
47 { 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 49 { 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
48 50
  51 +/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
  52 + has a different ID. However Linux only looks for the normal ID. */
  53 +#if 0
  54 +static const unsigned char pl110_versatile_id[] =
  55 +{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
  56 +#else
  57 +#define pl110_versatile_id pl110_id
  58 +#endif
  59 +
49 static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) 60 static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
50 { 61 {
51 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); 62 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
@@ -101,7 +112,7 @@ static void pl110_update_display(void *opaque) @@ -101,7 +112,7 @@ static void pl110_update_display(void *opaque)
101 int src_width; 112 int src_width;
102 uint8_t *dest; 113 uint8_t *dest;
103 uint8_t *src; 114 uint8_t *src;
104 - int first, last; 115 + int first, last = 0;
105 int dirty, new_dirty; 116 int dirty, new_dirty;
106 int i; 117 int i;
107 118
@@ -269,7 +280,10 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) @@ -269,7 +280,10 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
269 280
270 offset -= s->base; 281 offset -= s->base;
271 if (offset >= 0xfe0 && offset < 0x1000) { 282 if (offset >= 0xfe0 && offset < 0x1000) {
272 - return pl110_id[(offset - 0xfe0) >> 2]; 283 + if (s->versatile)
  284 + return pl110_versatile_id[(offset - 0xfe0) >> 2];
  285 + else
  286 + return pl110_id[(offset - 0xfe0) >> 2];
273 } 287 }
274 if (offset >= 0x200 && offset < 0x400) { 288 if (offset >= 0x200 && offset < 0x400) {
275 return s->raw_pallette[(offset - 0x200) >> 2]; 289 return s->raw_pallette[(offset - 0x200) >> 2];
@@ -347,10 +361,16 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, @@ -347,10 +361,16 @@ static void pl110_write(void *opaque, target_phys_addr_t offset,
347 s->lpbase = val; 361 s->lpbase = val;
348 break; 362 break;
349 case 6: /* LCDIMSC */ 363 case 6: /* LCDIMSC */
  364 + if (s->versatile)
  365 + goto control;
  366 + imsc:
350 s->int_mask = val; 367 s->int_mask = val;
351 pl110_update(s); 368 pl110_update(s);
352 break; 369 break;
353 case 7: /* LCDControl */ 370 case 7: /* LCDControl */
  371 + if (s->versatile)
  372 + goto imsc;
  373 + control:
354 s->cr = val; 374 s->cr = val;
355 s->bpp = (val >> 1) & 7; 375 s->bpp = (val >> 1) & 7;
356 if (pl110_enabled(s)) { 376 if (pl110_enabled(s)) {
@@ -390,6 +410,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, @@ -390,6 +410,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq,
390 cpu_register_physical_memory(base, 0x00000fff, iomemtype); 410 cpu_register_physical_memory(base, 0x00000fff, iomemtype);
391 s->base = base; 411 s->base = base;
392 s->ds = ds; 412 s->ds = ds;
  413 + s->versatile = versatile;
393 s->pic = pic; 414 s->pic = pic;
394 s->irq = irq; 415 s->irq = irq;
395 graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, 416 graphic_console_init(ds, pl110_update_display, pl110_invalidate_display,
hw/pl190.c 0 → 100644
  1 +/*
  2 + * Arm PrimeCell PL190 Vector Interrupt Controller
  3 + *
  4 + * Copyright (c) 2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +#include "arm_pic.h"
  12 +
  13 +/* The number of virtual priority levels. 16 user vectors plus the
  14 + unvectored IRQ. Chained interrupts would require an additional level
  15 + if implemented. */
  16 +
  17 +#define PL190_NUM_PRIO 17
  18 +
  19 +typedef struct {
  20 + arm_pic_handler handler;
  21 + uint32_t base;
  22 + DisplayState *ds;
  23 + uint32_t level;
  24 + uint32_t soft_level;
  25 + uint32_t irq_enable;
  26 + uint32_t fiq_select;
  27 + uint32_t default_addr;
  28 + uint8_t vect_control[16];
  29 + uint32_t vect_addr[PL190_NUM_PRIO];
  30 + /* Mask containing interrupts with higher priority than this one. */
  31 + uint32_t prio_mask[PL190_NUM_PRIO + 1];
  32 + int protected;
  33 + /* Current priority level. */
  34 + int priority;
  35 + int prev_prio[PL190_NUM_PRIO];
  36 + void *parent;
  37 + int irq;
  38 + int fiq;
  39 +} pl190_state;
  40 +
  41 +static const unsigned char pl190_id[] =
  42 +{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 };
  43 +
  44 +static inline uint32_t pl190_irq_level(pl190_state *s)
  45 +{
  46 + return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select;
  47 +}
  48 +
  49 +/* Update interrupts. */
  50 +static void pl190_update(pl190_state *s)
  51 +{
  52 + uint32_t level = pl190_irq_level(s);
  53 + int set;
  54 +
  55 + set = (level & s->prio_mask[s->priority]) != 0;
  56 + pic_set_irq_new(s->parent, s->irq, set);
  57 + set = ((s->level | s->soft_level) & s->fiq_select) != 0;
  58 + pic_set_irq_new(s->parent, s->fiq, set);
  59 +}
  60 +
  61 +static void pl190_set_irq(void *opaque, int irq, int level)
  62 +{
  63 + pl190_state *s = (pl190_state *)opaque;
  64 +
  65 + if (level)
  66 + s->level |= 1u << irq;
  67 + else
  68 + s->level &= ~(1u << irq);
  69 + pl190_update(s);
  70 +}
  71 +
  72 +static void pl190_update_vectors(pl190_state *s)
  73 +{
  74 + uint32_t mask;
  75 + int i;
  76 + int n;
  77 +
  78 + mask = 0;
  79 + for (i = 0; i < 16; i++)
  80 + {
  81 + s->prio_mask[i] = mask;
  82 + if (s->vect_control[i] & 0x20)
  83 + {
  84 + n = s->vect_control[i] & 0x1f;
  85 + mask |= 1 << n;
  86 + }
  87 + }
  88 + s->prio_mask[16] = mask;
  89 + pl190_update(s);
  90 +}
  91 +
  92 +static uint32_t pl190_read(void *opaque, target_phys_addr_t offset)
  93 +{
  94 + pl190_state *s = (pl190_state *)opaque;
  95 + int i;
  96 +
  97 + offset -= s->base;
  98 + if (offset >= 0xfe0 && offset < 0x1000) {
  99 + return pl190_id[(offset - 0xfe0) >> 2];
  100 + }
  101 + if (offset >= 0x100 && offset < 0x140) {
  102 + return s->vect_addr[(offset - 0x100) >> 2];
  103 + }
  104 + if (offset >= 0x200 && offset < 0x240) {
  105 + return s->vect_control[(offset - 0x200) >> 2];
  106 + }
  107 + switch (offset >> 2) {
  108 + case 0: /* IRQSTATUS */
  109 + return pl190_irq_level(s);
  110 + case 1: /* FIQSATUS */
  111 + return (s->level | s->soft_level) & s->fiq_select;
  112 + case 2: /* RAWINTR */
  113 + return s->level | s->soft_level;
  114 + case 3: /* INTSELECT */
  115 + return s->fiq_select;
  116 + case 4: /* INTENABLE */
  117 + return s->irq_enable;
  118 + case 6: /* SOFTINT */
  119 + return s->soft_level;
  120 + case 8: /* PROTECTION */
  121 + return s->protected;
  122 + case 12: /* VECTADDR */
  123 + /* Read vector address at the start of an ISR. Increases the
  124 + current priority level to that of the current interrupt. */
  125 + for (i = 0; i < s->priority; i++)
  126 + {
  127 + if ((s->level | s->soft_level) & s->prio_mask[i])
  128 + break;
  129 + }
  130 + /* Reading this value with no pending interrupts is undefined.
  131 + We return the default address. */
  132 + if (i == PL190_NUM_PRIO)
  133 + return s->vect_addr[16];
  134 + if (i < s->priority)
  135 + {
  136 + s->prev_prio[i] = s->priority;
  137 + s->priority = i;
  138 + pl190_update(s);
  139 + }
  140 + return s->vect_addr[s->priority];
  141 + case 13: /* DEFVECTADDR */
  142 + return s->vect_addr[16];
  143 + default:
  144 + cpu_abort (cpu_single_env, "pl190_read: Bad offset %x\n", offset);
  145 + return 0;
  146 + }
  147 +}
  148 +
  149 +static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val)
  150 +{
  151 + pl190_state *s = (pl190_state *)opaque;
  152 +
  153 + offset -= s->base;
  154 + if (offset >= 0x100 && offset < 0x140) {
  155 + s->vect_addr[(offset - 0x100) >> 2] = val;
  156 + pl190_update_vectors(s);
  157 + return;
  158 + }
  159 + if (offset >= 0x200 && offset < 0x240) {
  160 + s->vect_control[(offset - 0x200) >> 2] = val;
  161 + pl190_update_vectors(s);
  162 + return;
  163 + }
  164 + switch (offset >> 2) {
  165 + case 0: /* SELECT */
  166 + /* This is a readonly register, but linux tries to write to it
  167 + anyway. Ignore the write. */
  168 + break;
  169 + case 3: /* INTSELECT */
  170 + s->fiq_select = val;
  171 + break;
  172 + case 4: /* INTENABLE */
  173 + s->irq_enable |= val;
  174 + break;
  175 + case 5: /* INTENCLEAR */
  176 + s->irq_enable &= ~val;
  177 + break;
  178 + case 6: /* SOFTINT */
  179 + s->soft_level |= val;
  180 + break;
  181 + case 7: /* SOFTINTCLEAR */
  182 + s->soft_level &= ~val;
  183 + break;
  184 + case 8: /* PROTECTION */
  185 + /* TODO: Protection (supervisor only access) is not implemented. */
  186 + s->protected = val & 1;
  187 + break;
  188 + case 12: /* VECTADDR */
  189 + /* Restore the previous priority level. The value written is
  190 + ignored. */
  191 + if (s->priority < PL190_NUM_PRIO)
  192 + s->priority = s->prev_prio[s->priority];
  193 + break;
  194 + case 13: /* DEFVECTADDR */
  195 + s->default_addr = val;
  196 + break;
  197 + case 0xc0: /* ITCR */
  198 + if (val)
  199 + cpu_abort(cpu_single_env, "pl190: Test mode not implemented\n");
  200 + break;
  201 + default:
  202 + cpu_abort(cpu_single_env, "pl190_write: Bad offset %x\n", offset);
  203 + return;
  204 + }
  205 + pl190_update(s);
  206 +}
  207 +
  208 +static CPUReadMemoryFunc *pl190_readfn[] = {
  209 + pl190_read,
  210 + pl190_read,
  211 + pl190_read
  212 +};
  213 +
  214 +static CPUWriteMemoryFunc *pl190_writefn[] = {
  215 + pl190_write,
  216 + pl190_write,
  217 + pl190_write
  218 +};
  219 +
  220 +void pl190_reset(pl190_state *s)
  221 +{
  222 + int i;
  223 +
  224 + for (i = 0; i < 16; i++)
  225 + {
  226 + s->vect_addr[i] = 0;
  227 + s->vect_control[i] = 0;
  228 + }
  229 + s->vect_addr[16] = 0;
  230 + s->prio_mask[17] = 0xffffffff;
  231 + s->priority = PL190_NUM_PRIO;
  232 + pl190_update_vectors(s);
  233 +}
  234 +
  235 +void *pl190_init(uint32_t base, void *parent, int irq, int fiq)
  236 +{
  237 + pl190_state *s;
  238 + int iomemtype;
  239 +
  240 + s = (pl190_state *)qemu_mallocz(sizeof(pl190_state));
  241 + iomemtype = cpu_register_io_memory(0, pl190_readfn,
  242 + pl190_writefn, s);
  243 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  244 + s->handler = pl190_set_irq;
  245 + s->base = base;
  246 + s->parent = parent;
  247 + s->irq = irq;
  248 + s->fiq = fiq;
  249 + pl190_reset(s);
  250 + /* ??? Save/restore. */
  251 + return s;
  252 +}
hw/versatilepb.c 0 → 100644
  1 +/*
  2 + * ARM Versatile Platform Baseboard System emulation.
  3 + *
  4 + * Copyright (c) 2005-2006 CodeSourcery.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +#include "arm_pic.h"
  12 +
  13 +#define KERNEL_ARGS_ADDR 0x100
  14 +#define KERNEL_LOAD_ADDR 0x00010000
  15 +#define INITRD_LOAD_ADDR 0x00800000
  16 +
  17 +/* Primary interrupt controller. */
  18 +
  19 +typedef struct vpb_sic_state
  20 +{
  21 + arm_pic_handler handler;
  22 + uint32_t base;
  23 + uint32_t level;
  24 + uint32_t mask;
  25 + uint32_t pic_enable;
  26 + void *parent;
  27 + int irq;
  28 +} vpb_sic_state;
  29 +
  30 +static void vpb_sic_update(vpb_sic_state *s)
  31 +{
  32 + uint32_t flags;
  33 +
  34 + flags = s->level & s->mask;
  35 + pic_set_irq_new(s->parent, s->irq, flags != 0);
  36 +}
  37 +
  38 +static void vpb_sic_update_pic(vpb_sic_state *s)
  39 +{
  40 + int i;
  41 + uint32_t mask;
  42 +
  43 + for (i = 21; i <= 30; i++) {
  44 + mask = 1u << i;
  45 + if (!(s->pic_enable & mask))
  46 + continue;
  47 + pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
  48 + }
  49 +}
  50 +
  51 +static void vpb_sic_set_irq(void *opaque, int irq, int level)
  52 +{
  53 + vpb_sic_state *s = (vpb_sic_state *)opaque;
  54 + if (level)
  55 + s->level |= 1u << irq;
  56 + else
  57 + s->level &= ~(1u << irq);
  58 + if (s->pic_enable & (1u << irq))
  59 + pic_set_irq_new(s->parent, irq, level);
  60 + vpb_sic_update(s);
  61 +}
  62 +
  63 +static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
  64 +{
  65 + vpb_sic_state *s = (vpb_sic_state *)opaque;
  66 +
  67 + offset -= s->base;
  68 + switch (offset >> 2) {
  69 + case 0: /* STATUS */
  70 + return s->level & s->mask;
  71 + case 1: /* RAWSTAT */
  72 + return s->level;
  73 + case 2: /* ENABLE */
  74 + return s->mask;
  75 + case 4: /* SOFTINT */
  76 + return s->level & 1;
  77 + case 8: /* PICENABLE */
  78 + return s->pic_enable;
  79 + default:
  80 + printf ("vpb_sic_read: Bad register offset 0x%x\n", offset);
  81 + return 0;
  82 + }
  83 +}
  84 +
  85 +static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
  86 + uint32_t value)
  87 +{
  88 + vpb_sic_state *s = (vpb_sic_state *)opaque;
  89 + offset -= s->base;
  90 +
  91 + switch (offset >> 2) {
  92 + case 2: /* ENSET */
  93 + s->mask |= value;
  94 + break;
  95 + case 3: /* ENCLR */
  96 + s->mask &= ~value;
  97 + break;
  98 + case 4: /* SOFTINTSET */
  99 + if (value)
  100 + s->mask |= 1;
  101 + break;
  102 + case 5: /* SOFTINTCLR */
  103 + if (value)
  104 + s->mask &= ~1u;
  105 + break;
  106 + case 8: /* PICENSET */
  107 + s->pic_enable |= (value & 0x7fe00000);
  108 + vpb_sic_update_pic(s);
  109 + break;
  110 + case 9: /* PICENCLR */
  111 + s->pic_enable &= ~value;
  112 + vpb_sic_update_pic(s);
  113 + break;
  114 + default:
  115 + printf ("vpb_sic_write: Bad register offset 0x%x\n", offset);
  116 + return;
  117 + }
  118 + vpb_sic_update(s);
  119 +}
  120 +
  121 +static CPUReadMemoryFunc *vpb_sic_readfn[] = {
  122 + vpb_sic_read,
  123 + vpb_sic_read,
  124 + vpb_sic_read
  125 +};
  126 +
  127 +static CPUWriteMemoryFunc *vpb_sic_writefn[] = {
  128 + vpb_sic_write,
  129 + vpb_sic_write,
  130 + vpb_sic_write
  131 +};
  132 +
  133 +static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
  134 +{
  135 + vpb_sic_state *s;
  136 + int iomemtype;
  137 +
  138 + s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
  139 + if (!s)
  140 + return NULL;
  141 + s->handler = vpb_sic_set_irq;
  142 + s->base = base;
  143 + s->parent = parent;
  144 + s->irq = irq;
  145 + iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
  146 + vpb_sic_writefn, s);
  147 + cpu_register_physical_memory(base, 0x00000fff, iomemtype);
  148 + /* ??? Save/restore. */
  149 + return s;
  150 +}
  151 +
  152 +/* Board init. */
  153 +
  154 +/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
  155 +static uint32_t bootloader[] = {
  156 + 0xe3a00000, /* mov r0, #0 */
  157 + 0xe3a01083, /* mov r1, #0x83 */
  158 + 0xe3811c01, /* orr r1, r1, #0x100 */
  159 + 0xe59f2000, /* ldr r2, [pc, #0] */
  160 + 0xe59ff000, /* ldr pc, [pc, #0] */
  161 + 0, /* Address of kernel args. Set by integratorcp_init. */
  162 + 0 /* Kernel entry point. Set by integratorcp_init. */
  163 +};
  164 +
  165 +static void set_kernel_args(uint32_t ram_size, int initrd_size,
  166 + const char *kernel_cmdline)
  167 +{
  168 + uint32_t *p;
  169 +
  170 + p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
  171 + /* ATAG_CORE */
  172 + stl_raw(p++, 5);
  173 + stl_raw(p++, 0x54410001);
  174 + stl_raw(p++, 1);
  175 + stl_raw(p++, 0x1000);
  176 + stl_raw(p++, 0);
  177 + /* ATAG_MEM */
  178 + stl_raw(p++, 4);
  179 + stl_raw(p++, 0x54410002);
  180 + stl_raw(p++, ram_size);
  181 + stl_raw(p++, 0);
  182 + if (initrd_size) {
  183 + /* ATAG_INITRD2 */
  184 + stl_raw(p++, 4);
  185 + stl_raw(p++, 0x54420005);
  186 + stl_raw(p++, INITRD_LOAD_ADDR);
  187 + stl_raw(p++, initrd_size);
  188 + }
  189 + if (kernel_cmdline && *kernel_cmdline) {
  190 + /* ATAG_CMDLINE */
  191 + int cmdline_size;
  192 +
  193 + cmdline_size = strlen(kernel_cmdline);
  194 + memcpy (p + 2, kernel_cmdline, cmdline_size + 1);
  195 + cmdline_size = (cmdline_size >> 2) + 1;
  196 + stl_raw(p++, cmdline_size + 2);
  197 + stl_raw(p++, 0x54410009);
  198 + p += cmdline_size;
  199 + }
  200 + /* ATAG_END */
  201 + stl_raw(p++, 0);
  202 + stl_raw(p++, 0);
  203 +}
  204 +
  205 +static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
  206 + DisplayState *ds, const char **fd_filename, int snapshot,
  207 + const char *kernel_filename, const char *kernel_cmdline,
  208 + const char *initrd_filename)
  209 +{
  210 + CPUState *env;
  211 + int kernel_size;
  212 + int initrd_size;
  213 + int n;
  214 + void *pic;
  215 + void *sic;
  216 +
  217 + env = cpu_init();
  218 + cpu_arm_set_model(env, ARM_CPUID_ARM926);
  219 + /* ??? RAM shoud repeat to fill physical memory space. */
  220 + /* SDRAM at address zero. */
  221 + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
  222 +
  223 + pic = arm_pic_init_cpu(env);
  224 + pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
  225 + sic = vpb_sic_init(0x10003000, pic, 31);
  226 + pl050_init(0x10006000, sic, 3, 0);
  227 + pl050_init(0x10007000, sic, 4, 1);
  228 +
  229 + /* TODO: Init PCI NICs. */
  230 + if (nd_table[0].vlan) {
  231 + if (nd_table[0].model == NULL
  232 + || strcmp(nd_table[0].model, "smc91c111") == 0) {
  233 + smc91c111_init(&nd_table[0], 0x10010000, sic, 25);
  234 + } else {
  235 + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
  236 + exit (1);
  237 + }
  238 + }
  239 +
  240 + pl011_init(0x101f1000, pic, 12, serial_hds[0]);
  241 + pl011_init(0x101f2000, pic, 13, serial_hds[1]);
  242 + pl011_init(0x101f3000, pic, 14, serial_hds[2]);
  243 + pl011_init(0x10009000, sic, 6, serial_hds[3]);
  244 +
  245 + pl080_init(0x10130000, pic, 17);
  246 + sp804_init(0x101e2000, pic, 4);
  247 + sp804_init(0x101e3000, pic, 5);
  248 +
  249 + /* The versatile/PB actually has a modified Color LCD controller
  250 + that includes hardware cursor support from the PL111. */
  251 + pl110_init(ds, 0x10120000, pic, 16, 1);
  252 +
  253 + /* 0x10000000 System registers. */
  254 + /* 0x10001000 PCI controller config registers. */
  255 + /* 0x10002000 Serial bus interface. */
  256 + /* 0x10003000 Secondary interrupt controller. */
  257 + /* 0x10004000 AACI (audio). */
  258 + /* 0x10005000 MMCI0. */
  259 + /* 0x10006000 KMI0 (keyboard). */
  260 + /* 0x10007000 KMI1 (mouse). */
  261 + /* 0x10008000 Character LCD Interface. */
  262 + /* 0x10009000 UART3. */
  263 + /* 0x1000a000 Smart card 1. */
  264 + /* 0x1000b000 MMCI1. */
  265 + /* 0x10010000 Ethernet. */
  266 + /* 0x10020000 USB. */
  267 + /* 0x10100000 SSMC. */
  268 + /* 0x10110000 MPMC. */
  269 + /* 0x10120000 CLCD Controller. */
  270 + /* 0x10130000 DMA Controller. */
  271 + /* 0x10140000 Vectored interrupt controller. */
  272 + /* 0x101d0000 AHB Monitor Interface. */
  273 + /* 0x101e0000 System Controller. */
  274 + /* 0x101e1000 Watchdog Interface. */
  275 + /* 0x101e2000 Timer 0/1. */
  276 + /* 0x101e3000 Timer 2/3. */
  277 + /* 0x101e4000 GPIO port 0. */
  278 + /* 0x101e5000 GPIO port 1. */
  279 + /* 0x101e6000 GPIO port 2. */
  280 + /* 0x101e7000 GPIO port 3. */
  281 + /* 0x101e8000 RTC. */
  282 + /* 0x101f0000 Smart card 0. */
  283 + /* 0x101f1000 UART0. */
  284 + /* 0x101f2000 UART1. */
  285 + /* 0x101f3000 UART2. */
  286 + /* 0x101f4000 SSPI. */
  287 +
  288 + /* Load the kernel. */
  289 + if (!kernel_filename) {
  290 + fprintf(stderr, "Kernel image must be specified\n");
  291 + exit(1);
  292 + }
  293 + kernel_size = load_image(kernel_filename,
  294 + phys_ram_base + KERNEL_LOAD_ADDR);
  295 + if (kernel_size < 0) {
  296 + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
  297 + exit(1);
  298 + }
  299 + if (initrd_filename) {
  300 + initrd_size = load_image(initrd_filename,
  301 + phys_ram_base + INITRD_LOAD_ADDR);
  302 + if (initrd_size < 0) {
  303 + fprintf(stderr, "qemu: could not load initrd '%s'\n",
  304 + initrd_filename);
  305 + exit(1);
  306 + }
  307 + } else {
  308 + initrd_size = 0;
  309 + }
  310 + bootloader[5] = KERNEL_ARGS_ADDR;
  311 + bootloader[6] = KERNEL_LOAD_ADDR;
  312 + for (n = 0; n < sizeof(bootloader) / 4; n++)
  313 + stl_raw(phys_ram_base + (n * 4), bootloader[n]);
  314 + set_kernel_args(ram_size, initrd_size, kernel_cmdline);
  315 +}
  316 +
  317 +QEMUMachine versatilepb_machine = {
  318 + "versatilepb",
  319 + "ARM Versatile/PB (ARM926EJ-S)",
  320 + vpb_init,
  321 +};
@@ -4436,6 +4436,7 @@ void register_machines(void) @@ -4436,6 +4436,7 @@ void register_machines(void)
4436 #elif defined(TARGET_ARM) 4436 #elif defined(TARGET_ARM)
4437 qemu_register_machine(&integratorcp926_machine); 4437 qemu_register_machine(&integratorcp926_machine);
4438 qemu_register_machine(&integratorcp1026_machine); 4438 qemu_register_machine(&integratorcp1026_machine);
  4439 + qemu_register_machine(&versatilepb_machine);
4439 #else 4440 #else
4440 #error unsupported CPU 4441 #error unsupported CPU
4441 #endif 4442 #endif
@@ -966,6 +966,9 @@ void usb_info(void); @@ -966,6 +966,9 @@ void usb_info(void);
966 extern QEMUMachine integratorcp926_machine; 966 extern QEMUMachine integratorcp926_machine;
967 extern QEMUMachine integratorcp1026_machine; 967 extern QEMUMachine integratorcp1026_machine;
968 968
  969 +/* versatilepb.c */
  970 +extern QEMUMachine versatilepb_machine;
  971 +
969 /* ps2.c */ 972 /* ps2.c */
970 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); 973 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
971 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); 974 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
@@ -981,6 +984,22 @@ void smc91c111_init(NICInfo *, uint32_t, void *, int); @@ -981,6 +984,22 @@ void smc91c111_init(NICInfo *, uint32_t, void *, int);
981 /* pl110.c */ 984 /* pl110.c */
982 void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int); 985 void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int);
983 986
  987 +/* pl011.c */
  988 +void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr);
  989 +
  990 +/* pl050.c */
  991 +void pl050_init(uint32_t base, void *pic, int irq, int is_mouse);
  992 +
  993 +/* pl080.c */
  994 +void *pl080_init(uint32_t base, void *pic, int irq);
  995 +
  996 +/* pl190.c */
  997 +void *pl190_init(uint32_t base, void *parent, int irq, int fiq);
  998 +
  999 +/* arm-timer.c */
  1000 +void sp804_init(uint32_t base, void *pic, int irq);
  1001 +void icp_pit_init(uint32_t base, void *pic, int irq);
  1002 +
984 #endif /* defined(QEMU_TOOL) */ 1003 #endif /* defined(QEMU_TOOL) */
985 1004
986 /* monitor.c */ 1005 /* monitor.c */