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 339 endif
340 340 endif
341 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 344 endif
344 345 ifdef CONFIG_GDBSTUB
345 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 2 * ARM Integrator CP System emulation.
3 3 *
4   - * Copyright (c) 2005 CodeSourcery, LLC.
  4 + * Copyright (c) 2005-2006 CodeSourcery.
5 5 * Written by Paul Brook
6 6 *
7 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 13 #define KERNEL_ARGS_ADDR 0x100
13 14 #define KERNEL_LOAD_ADDR 0x00010000
14 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 17 void DMA_run (void)
31 18 {
32 19 }
... ... @@ -284,41 +271,31 @@ static void integratorcm_init(int memsz, uint32_t flash_offset)
284 271  
285 272 typedef struct icp_pic_state
286 273 {
  274 + arm_pic_handler handler;
287 275 uint32_t base;
288 276 uint32_t level;
289 277 uint32_t irq_enabled;
290 278 uint32_t fiq_enabled;
291 279 void *parent;
292   - /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */
293 280 int parent_irq;
  281 + int parent_fiq;
294 282 } icp_pic_state;
295 283  
296 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 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 300 icp_pic_state *s = (icp_pic_state *)opaque;
324 301 if (level)
... ... @@ -408,7 +385,7 @@ static CPUWriteMemoryFunc *icp_pic_writefn[] = {
408 385 };
409 386  
410 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 390 icp_pic_state *s;
414 391 int iomemtype;
... ... @@ -416,10 +393,11 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
416 393 s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
417 394 if (!s)
418 395 return NULL;
419   -
  396 + s->handler = icp_pic_set_irq;
420 397 s->base = base;
421 398 s->parent = parent;
422 399 s->parent_irq = parent_irq;
  400 + s->parent_fiq = parent_fiq;
423 401 iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
424 402 icp_pic_writefn, s);
425 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 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 408 /* CP control registers. */
924 409 typedef struct {
925 410 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 473 /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
1105 474 static uint32_t bootloader[] = {
1106 475 0xe3a00000, /* mov r0, #0 */
... ... @@ -1162,6 +531,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
1162 531 CPUState *env;
1163 532 uint32_t bios_offset;
1164 533 icp_pic_state *pic;
  534 + void *cpu_pic;
1165 535 int kernel_size;
1166 536 int initrd_size;
1167 537 int n;
... ... @@ -1177,14 +547,15 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
1177 547 cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM);
1178 548  
1179 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 554 pl011_init(0x16000000, pic, 1, serial_hds[0]);
1184 555 pl011_init(0x17000000, pic, 2, serial_hds[1]);
1185 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 559 if (nd_table[0].vlan) {
1189 560 if (nd_table[0].model == NULL
1190 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 2 * Arm PrimeCell PL110 Color LCD Controller
3 3 *
4   - * Copyright (c) 2005 CodeSourcery, LLC.
  4 + * Copyright (c) 2005-2006 CodeSourcery.
5 5 * Written by Paul Brook
6 6 *
7 7 * This code is licenced under the GNU LGPL
... ... @@ -27,6 +27,8 @@ enum pl110_bppmode
27 27 typedef struct {
28 28 uint32_t base;
29 29 DisplayState *ds;
  30 + /* The Versatile/PB uses a slightly modified PL110 controller. */
  31 + int versatile;
30 32 void *pic;
31 33 uint32_t timing[4];
32 34 uint32_t cr;
... ... @@ -46,6 +48,15 @@ typedef struct {
46 48 static const unsigned char pl110_id[] =
47 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 60 static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
50 61 {
51 62 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
... ... @@ -101,7 +112,7 @@ static void pl110_update_display(void *opaque)
101 112 int src_width;
102 113 uint8_t *dest;
103 114 uint8_t *src;
104   - int first, last;
  115 + int first, last = 0;
105 116 int dirty, new_dirty;
106 117 int i;
107 118  
... ... @@ -269,7 +280,10 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
269 280  
270 281 offset -= s->base;
271 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 288 if (offset >= 0x200 && offset < 0x400) {
275 289 return s->raw_pallette[(offset - 0x200) >> 2];
... ... @@ -347,10 +361,16 @@ static void pl110_write(void *opaque, target_phys_addr_t offset,
347 361 s->lpbase = val;
348 362 break;
349 363 case 6: /* LCDIMSC */
  364 + if (s->versatile)
  365 + goto control;
  366 + imsc:
350 367 s->int_mask = val;
351 368 pl110_update(s);
352 369 break;
353 370 case 7: /* LCDControl */
  371 + if (s->versatile)
  372 + goto imsc;
  373 + control:
354 374 s->cr = val;
355 375 s->bpp = (val >> 1) & 7;
356 376 if (pl110_enabled(s)) {
... ... @@ -390,6 +410,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq,
390 410 cpu_register_physical_memory(base, 0x00000fff, iomemtype);
391 411 s->base = base;
392 412 s->ds = ds;
  413 + s->versatile = versatile;
393 414 s->pic = pic;
394 415 s->irq = irq;
395 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 4436 #elif defined(TARGET_ARM)
4437 4437 qemu_register_machine(&integratorcp926_machine);
4438 4438 qemu_register_machine(&integratorcp1026_machine);
  4439 + qemu_register_machine(&versatilepb_machine);
4439 4440 #else
4440 4441 #error unsupported CPU
4441 4442 #endif
... ...
... ... @@ -966,6 +966,9 @@ void usb_info(void);
966 966 extern QEMUMachine integratorcp926_machine;
967 967 extern QEMUMachine integratorcp1026_machine;
968 968  
  969 +/* versatilepb.c */
  970 +extern QEMUMachine versatilepb_machine;
  971 +
969 972 /* ps2.c */
970 973 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
971 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 984 /* pl110.c */
982 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 1003 #endif /* defined(QEMU_TOOL) */
985 1004  
986 1005 /* monitor.c */
... ...