Index: qemu/hw/pxa255_dma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_dma.c 2006-11-21 15:53:32.000000000 +0800 @@ -0,0 +1,217 @@ +/* + * Intel XScale PXA255 DMA controller + * + * Copyright (c) 2006 Thorsten Zitterell + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +#define PXA255_DMA_NUM_CHANNELS 16 + +#define PXA255_DMA_RUN 0x80000000 +#define PXA255_DMA_REQPEND 0x00000100 +#define PXA255_DMA_STOPSTATE 0x00000008 + +#define PXA255_DMA_INCSRCADDR 0x80000000 +#define PXA255_DMA_INCTRGADDR 0x40000000 + +typedef struct { + uint32_t next; + uint32_t src; + uint32_t dest; + uint32_t cmd; + uint32_t state; +} pxa255_dma_channel; + +typedef struct { + uint32_t base; + uint8_t tc_int; + uint8_t tc_mask; + uint8_t err_int; + uint8_t err_mask; + uint32_t conf; + uint32_t sync; + uint32_t req_single; + uint32_t req_burst; + pxa255_dma_channel chan[PXA255_DMA_NUM_CHANNELS]; + /* Flag to avoid recursive DMA invocations. */ + int running; + void *pic; + int irq; +} pxa255_dma_state; + +static const unsigned char pxa255_dma_id[] = + { 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pxa255_dma_update(pxa255_dma_state * s) +{ + if ((s->tc_int & s->tc_mask) || (s->err_int & s->err_mask)) + pic_set_irq_new(s->pic, s->irq, 1); + else + pic_set_irq_new(s->pic, s->irq, 1); +} + +static void pxa255_dma_run(pxa255_dma_state * s) +{ + int c, n; + int size; + int width; + int length; + char buffer[32]; + pxa255_dma_channel *ch; + + for (c = 0; c < PXA255_DMA_NUM_CHANNELS; c++) { + /* test for pending requests */ + ch = &s->chan[c]; + + if (!(ch->state & PXA255_DMA_RUN) + || (ch->state & PXA255_DMA_STOPSTATE)) + continue; + length = ch->cmd & 0x1fff; + size = 0x8 << (((ch->cmd >> 16) & 0x3) - 1); + width = 0x1 << (((ch->cmd >> 14) & 0x3) - 1); + + + while (length) { + size = (size > length ? length : size); +/* printf + ("Copying from 0x%x to 0x%x bytes of width 0x%x with burst 0x%x remaining 0x%x\n", + ch->src, ch->dest, width, size, length); */ + + for (n = 0; n < size; n += width) { + cpu_physical_memory_read(ch->src, + buffer + n, + width); + + if (ch->cmd & PXA255_DMA_INCSRCADDR) + ch->src += width; + } + + for (n = 0; n < size; n += width) { + cpu_physical_memory_write(ch->dest, + buffer + n, + width); + + if (ch->cmd & PXA255_DMA_INCTRGADDR) + ch->dest += width; + } + length -= size; + + ch->cmd = (ch->cmd & 0xffffe000) | length; + /* Is transfer complete? */ + if (!length) { + ch->state |= PXA255_DMA_STOPSTATE; + } + } + } +// pxa255_dma_update(s); +} + +static uint32_t pxa255_dma_read(void *opaque, target_phys_addr_t offset) +{ + pxa255_dma_state *s = (pxa255_dma_state *) opaque; + uint32_t channel; + uint32_t mask; + offset -= s->base; + if (offset >= 0x0 && offset < 0x40) { // DMA Control / Status register + channel = offset >> 2; +/* printf("Read DMA Status Register Channel 0x%x\n", channel); */ + return s->chan[channel].state; + } else if (offset == 0xf0) { // DMA Interrupt Register +/* printf("Read DMA INT Register\n"); */ + } else if (offset >= 0x200 && offset < 0x300) { // DMA Target / Command /Descriptor / Source +/* printf("Read DMA Target / Command /Descriptor / Source\n"); */ + channel = (offset - 0x200) >> 4; +/* printf("Channel 0x%x, code 0x%x\n", channel, + offset & 0x0f); */ + switch (offset & 0x0f) { + case 0x0: + return s->chan[channel].next; + break; + case 0x4: + return s->chan[channel].src; + break; + case 0x8: + return s->chan[channel].dest; + break; + case 0xc: + return s->chan[channel].cmd; + break; + } + } else { + cpu_abort(cpu_single_env, + "pxa255_dma_read: Bad offset 0x%x\n", offset); + } + + return 0; +} + +static void pxa255_dma_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + pxa255_dma_state *s = (pxa255_dma_state *) opaque; + int channel; + offset -= s->base; + if (offset >= 0x0 && offset < 0x40) { // DMA Control / Status register + channel = offset >> 2; +/* printf + ("Write DMA Status Register Channel 0x%x value 0x%x\n", + channel, value); */ + s->chan[channel].state = value & 0xe0000007; + } else if (offset == 0xf0) { // DMA Interrupt Register +/* printf("DMA INT Register\n"); */ + } else if (offset >= 0x200 && offset < 0x300) { // DMA Target / Command /Descriptor / Source +/* printf + ("Write DMA Target / Command /Descriptor / Source\n"); */ + channel = (offset - 0x200) >> 4; +/* printf("Channel 0x%x, code 0x%x, value 0x%x\n", + channel, offset & 0x0f, value); */ + switch (offset & 0x0f) { + case 0x0: + s->chan[channel].next = value; + break; + case 0x4: + s->chan[channel].src = value; + break; + case 0x8: + s->chan[channel].dest = value; + break; + case 0xc: + s->chan[channel].cmd = value; + break; + } + } else { + cpu_abort(cpu_single_env, + "pxa255_dma_write: Bad offset 0x%x\n", offset); + } + + pxa255_dma_run(s); +} + +static CPUReadMemoryFunc *pxa255_dma_readfn[] = { + pxa255_dma_read, + pxa255_dma_read, + pxa255_dma_read +}; +static CPUWriteMemoryFunc *pxa255_dma_writefn[] = { + pxa255_dma_write, + pxa255_dma_write, + pxa255_dma_write +}; +void *pxa255_dma_init(uint32_t base, void *pic, int irq) +{ + int iomemtype; + pxa255_dma_state *s; + s = (pxa255_dma_state *) + qemu_mallocz(sizeof(pxa255_dma_state)); + iomemtype = + cpu_register_io_memory(0, pxa255_dma_readfn, + pxa255_dma_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + return s; +} Index: qemu/hw/pxa255_dma.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_dma.h 2006-11-21 22:21:20.000000000 +0800 @@ -0,0 +1,15 @@ +/* + * Generic PIX255 DMA support. + * + * Copyright (c) 2006 Thorsten Zitterell. + * + * This code is licenced under the LGPL. + * + */ + +#ifndef PXA255_DMA_H +#define PXA255_DMA_H 1 + +void *pxa255_dma_init(uint32_t base, void *pic, int irq); + +#endif /* PXA255_DMA_H */ Index: qemu/hw/pxa255_gpio.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_gpio.c 2006-11-21 15:55:08.000000000 +0800 @@ -0,0 +1,280 @@ +/* + * Intel XScale PXA255 GPIO + * + * Copyright (c) 2006 Thorsten Zitterell + * + * This code is licenced under the GPL. +*/ + +#include "vl.h" +#include "pxa255_gpio.h" + +#define GPLR0 0x0000 +#define GPLR1 0x0004 +#define GPLR2 0x0008 + +#define GPDR0 0x000c +#define GPDR1 0x0010 +#define GPDR2 0x0014 + +#define GPSR0 0x0018 +#define GPSR1 0x001c +#define GPSR2 0x0020 +#define GPCR0 0x0024 +#define GPCR1 0x0028 +#define GPCR2 0x002c + +#define GRER0 0x0030 +#define GRER1 0x0034 +#define GRER2 0x0038 + +#define GFER0 0x003c +#define GFER1 0x0040 +#define GFER2 0x0044 + +#define GEDR0 0x0048 +#define GEDR1 0x004c +#define GEDR2 0x0050 + +#define GAFR0_L 0x0054 +#define GAFR0_U 0x0058 +#define GAFR1_L 0x005c +#define GAFR1_U 0x0060 +#define GAFR2_L 0x0064 +#define GAFR2_U 0x0068 + +void pxa255_gpio_irq_update(void *opaque) { + pxa255_gpio_info *s = (pxa255_gpio_info *)opaque; + + if (s->gedr0 || s->gedr1 || s->gedr2) + pxa255_pic_set_irq(s->pic,s->irq,1); + else + pxa255_pic_set_irq(s->pic,s->irq,0); +} + +void pxa255_set_gpio(void *opaque, int line, int level) { + + pxa255_gpio_info *s = (pxa255_gpio_info *)opaque; + int raise = 0; + int fall = 0; + int edge = 0; + uint32_t gedr0, gedr1, gedr2; + + gedr0 = s->gedr0; + gedr1 = s->gedr1; + gedr2 = s->gedr2; + + if (line < 32) { + raise = !(s->gplr0 & (1 << line)) && level; + fall = (s->gplr0 & (1 << line)) && !level; + + if (level) s->gplr0 |= (1 << line); + else s->gplr0 &= ~(1 << line); + + if (((s->grer0 & (1 << line)) && raise) || + ((s->gfer0 & (1 << line)) && fall)) { + s->gedr0 |= (1 << line); + } + + } else if (line < 64) { + line -= 32; + raise = !(s->gplr1 & (1 << line)) && level; + fall = (s->gplr1 & (1 << line)) && !level; + + if (level) s->gplr1 |= (1 << line); + else s->gplr1 &= ~(1 << line); + + if (((s->grer1 & (1 << line)) && raise) || + ((s->gfer1 & (1 << line)) && fall)){ + s->gedr1 |= (1 << line); + } + + } else if (line < 92) { + line -= 64; + raise = !(s->gplr2 & (1 << line)) && level; + fall = (s->gplr2 & (1 << line)) && !level; + + if (level) s->gplr2 |= (1 << line); + else s->gplr2 &= ~(1 << line); + + if (((s->grer2 & (1 << line)) && raise) || + ((s->gfer2 & (1 << line)) && fall)) { + s->gedr2 |= (1 << line); + } + + } + + pxa255_gpio_irq_update(opaque); +} + +static uint32_t pxa255_gpio_read(void *opaque, target_phys_addr_t offset) +{ + pxa255_gpio_info *s = (pxa255_gpio_info *)opaque; + + offset -= s->base; + +// printf("Read GPIO Offset %x base %x\n",offset,s->base); + + switch(offset) { + case(GPLR0): + return s->gplr0; + case(GPLR1): + return s->gplr1; + case(GPLR2): + return s->gplr2; + case(GPDR0): + return s->gpdr0; + case(GPDR1): + return s->gpdr1; + case(GPDR2): + return s->gpdr2; + case(GRER0): + return s->grer0; + case(GRER1): + return s->grer1; + case(GRER2): + return s->grer2; + case(GEDR0): + return s->gedr0; + case(GEDR1): + return s->gedr1; + case(GEDR2): + return s->gedr2; + case(GAFR0_L): + return s->gafr0_l; + case(GAFR0_U): + return s->gafr0_u; + case(GAFR1_L): + return s->gafr1_l; + case(GAFR1_U): + return s->gafr1_u; + case(GAFR2_L): + return s->gafr2_l; + case(GAFR2_U): + return s->gafr2_u; + default: + cpu_abort (cpu_single_env, "pxa255_gpio_read: Bad offset %x\n", offset); + } + + return 0; +} + +static void pxa255_gpio_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + pxa255_gpio_info *s = (pxa255_gpio_info *)opaque; + + offset -= s->base; + +// printf("Write GPIO Offset 0x%x value 0x%x\n",offset,value); + + switch(offset) { + case(GPDR0): + s->gpdr0 = value; + break; + case(GPDR1): + s->gpdr1 = value; + break; + case(GPDR2): + s->gpdr2 = value; + break; + case(GPSR0): + s->gpsr0 = value; + break; + case(GPSR1): + s->gpsr1 = value; + break; + case(GPSR2): + s->gpsr2 = value; + break; + case(GPCR0): + s->gpsr0 &= ~value; + break; + case(GPCR1): + s->gpsr1 &= ~value; + break; + case(GPCR2): + s->gpsr2 &= ~value; + break; + + case(GRER0): + s->grer0 = value; + break; + case(GRER1): + s->grer1 = value; + break; + case(GRER2): + s->grer2 = value; + break; + + case(GFER0): + s->gfer0 = value; + break; + case(GFER1): + s->gfer1 = value; + break; + case(GFER2): + s->gfer2 = value; + break; + + case(GEDR0): + case(GEDR1): + case(GEDR2): + s->gedr0 &= ~value; + s->gedr1 &= ~value; + s->gedr2 &= ~value; + pxa255_gpio_irq_update(opaque); + break; + case(GAFR0_L): + s->gafr0_l &= ~value; + break; + case(GAFR0_U): + s->gafr0_u &= ~value; + break; + case(GAFR1_L): + s->gafr1_l &= ~value; + break; + case(GAFR1_U): + s->gafr1_u &= ~value; + break; + case(GAFR2_L): + s->gafr2_l &= ~value; + break; + case(GAFR2_U): + s->gafr2_u &= ~value; + break; + default: + cpu_abort (cpu_single_env, "pxa255_gpio_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *pxa255_gpio_readfn[] = { + pxa255_gpio_read, + pxa255_gpio_read, + pxa255_gpio_read +}; + +static CPUWriteMemoryFunc *pxa255_gpio_writefn[] = { + pxa255_gpio_write, + pxa255_gpio_write, + pxa255_gpio_write +}; + + +pxa255_gpio_info * pxa255_gpio_init(uint32_t base, void *pic, int irq) +{ + int i; + int iomemtype; + pxa255_gpio_info *s; + + s = (pxa255_gpio_info *) qemu_mallocz(sizeof(pxa255_gpio_info)); + s->base = base; + s->pic = pic; + s->irq = irq; + + iomemtype = cpu_register_io_memory(0, pxa255_gpio_readfn, + pxa255_gpio_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + + return s; + +} Index: qemu/hw/pxa255_gpio.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_gpio.h 2006-11-21 15:55:35.000000000 +0800 @@ -0,0 +1,57 @@ +/* + * Generic PIX255 Programmable Interrupt Controller support. + * + * Copyright (c) 2006 Thorsten Zitterell. + * + * This code is licenced under the LGPL. + * + * Arm hardware uses a wide variety of interrupt handling hardware. + * This provides a generic framework for connecting interrupt sources and + * inputs. + */ + +#ifndef PXA255_GPIO_H +#define PXA255_GPIO_H 1 + +void pxa255_set_gpio(void *opaque, int line, int level); + +typedef struct { + uint32_t base; + int irq; + void *pic; + + uint32_t gplr0; + uint32_t gplr1; + uint32_t gplr2; + + uint32_t gpsr0; + uint32_t gpsr1; + uint32_t gpsr2; + + uint32_t gpdr0; + uint32_t gpdr1; + uint32_t gpdr2; + + uint32_t gedr0; + uint32_t gedr1; + uint32_t gedr2; + + uint32_t grer0; + uint32_t grer1; + uint32_t grer2; + + uint32_t gfer0; + uint32_t gfer1; + uint32_t gfer2; + + uint32_t gafr0_l; + uint32_t gafr0_u; + uint32_t gafr1_l; + uint32_t gafr1_u; + uint32_t gafr2_l; + uint32_t gafr2_u; +} pxa255_gpio_info; + +pxa255_gpio_info *pxa255_gpio_init(uint32_t base, void *pic, int irq); + +#endif /* !PXA255_GPIO_H */ Index: qemu/hw/pxa255_pic.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_pic.c 2006-11-21 15:55:52.000000000 +0800 @@ -0,0 +1,159 @@ +/* + * Intel XScale PXA255 Interrupt Controller + * + * Copyright (c) 2006 Thorsten Zitterell + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "pxa255_pic.h" + +#define ICIP 0x00 /* Interrupt Controller IRQ Pending Register */ +#define ICMR 0x04 /* Interrupt Controller Mask Register */ +#define ICLR 0x08 /* Interrupt Controller Level Register */ +#define ICFP 0x0C /* Interrupt Controller FIQ Pending Register */ +#define ICPR 0x10 /* Interrupt Controller Pending Register */ +#define ICCR 0x14 /* Interrupt Controller Control Register */ + + +void pxa255_set_irq_new(void *opaque, int irq, int level) +{ + pxa255_pic_state *s = (pxa255_pic_state *) opaque; + /* Call the real handler. */ + (*s->handler)(opaque, irq, level); +} + + +static void pxa255_pic_update(void *opaque) +{ + pxa255_pic_state *s = (pxa255_pic_state *)opaque; + + /* fixme: consider idle mode */ + + if (s->irq_pending & s->is_fiq & s->irq_enabled) { + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + } + + if (s->irq_pending & ~s->is_fiq & s->irq_enabled) { + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + } + +} + +void pxa255_pic_set_irq(void *opaque, int irq, int level) +{ + pxa255_pic_state *s = (pxa255_pic_state *)opaque; + + if (level) { + s->irq_pending |= 1 << irq; + } else { + s->irq_pending &= ~(1 << irq); + } + + pxa255_pic_update(opaque); +} + + +static uint32_t pxa255_pic_read(void *opaque, target_phys_addr_t offset) +{ + pxa255_pic_state *s = (pxa255_pic_state *)opaque; + offset -= s->base; + + switch (offset) { + case ICIP: /* irq pending register */ + return (s->irq_pending & ~s->is_fiq & s->irq_enabled); + break; + case ICMR: /* mask register */ + return s->irq_enabled; + break; + case ICLR: /* level register */ + return s->is_fiq; + break; + case ICCR: /* idle mask */ + return s->idle; + break; + case ICFP: /* fiq pending register */ + return (s->irq_pending & s->is_fiq & s->irq_enabled); + break; + case ICPR: /* pending register */ + return s->irq_pending; + break; + default: + printf ("pxa255_pic_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void pxa255_pic_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pxa255_pic_state *s = (pxa255_pic_state *)opaque; + offset -= s->base; + + switch (offset) { + case ICIP: /* irq pending register */ + s->irq_pending &= ~value; + break; + case ICMR: /* mask register */ + s->irq_enabled = value; + break; + case ICLR: /* level register */ + s->is_fiq = value; + break; + case ICCR: /* idle mask */ + s->idle = value; + break; + case ICFP: /* fiq pending register */ + s->fiq_pending &= ~value; + break; + case ICPR: /* pending register */ + break; + default: + printf ("pxa255_pic_write: Bad register offset 0x%x\n", offset); + return; + } + pxa255_pic_update(opaque); +} + +static CPUReadMemoryFunc *pxa255_pic_readfn[] = { + pxa255_pic_read, + pxa255_pic_read, + pxa255_pic_read +}; + +static CPUWriteMemoryFunc *pxa255_pic_writefn[] = { + pxa255_pic_write, + pxa255_pic_write, + pxa255_pic_write +}; + +pxa255_pic_state *pxa255_pic_init(uint32_t base, CPUState *env, + int parent_irq, int parent_fiq) +{ + pxa255_pic_state *s; + int iomemtype; + + s = (pxa255_pic_state *)qemu_mallocz(sizeof(pxa255_pic_state)); + if (!s) + return NULL; + + s->cpu_env = env; + s->base = base; + + s->irq_pending = 0; + s->fiq_pending = 0; + s->irq_enabled = 0; + s->is_fiq = 0; + s->handler = pxa255_pic_set_irq; + + iomemtype = cpu_register_io_memory(0, pxa255_pic_readfn, + pxa255_pic_writefn, s); + cpu_register_physical_memory(base, 0x000fffff, iomemtype); + + return s; +} Index: qemu/hw/pxa255_pic.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_pic.h 2006-11-21 15:56:42.000000000 +0800 @@ -0,0 +1,46 @@ +/* + * Generic PIX255 Programmable Interrupt Controller support. + * + * Copyright (c) 2006 Thorsten Zitterell. + * + * This code is licenced under the LGPL. + * + * Arm hardware uses a wide variety of interrupt handling hardware. + * This provides a generic framework for connecting interrupt sources and + * inputs. + */ + +#ifndef PXA255_INTERRUPT_H +#define PXA255_INTERRUPT_H 1 + +/* The first element of an individual PIC state structures should + be a pointer to the handler routine. */ +typedef void (*pxa255_pic_handler)(void *opaque, int irq, int level); + +/* The CPU is also modeled as an interrupt controller. */ +#define PXA255_PIC_CPU_IRQ 0 +#define PXA255_PIC_CPU_FIQ 1 +void *pxa255_pic_init_cpu(CPUState *env); + +typedef struct icp_pic_state +{ + pxa255_pic_handler handler; + CPUState *cpu_env; + uint32_t base; + uint32_t irq_enabled; + uint32_t is_fiq; + uint32_t idle; + uint32_t irq_pending; + uint32_t fiq_pending; + void *parent; + int parent_irq; + int parent_fiq; +} pxa255_pic_state; + +pxa255_pic_state *pxa255_pic_init(uint32_t base, CPUState *env, + int parent_irq, int parent_fiq); + +void pxa255_pic_set_irq(void *opaque, int irq, int level); +/* void pic_set_irq_new(void *opaque, int irq, int level); */ + +#endif /* !PXA255_INTERRUPT_H */ Index: qemu/hw/pxa255_timer.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_timer.c 2006-11-21 15:57:08.000000000 +0800 @@ -0,0 +1,199 @@ +/* + * Intel XScale PXA255 OS Timer + * + * Copyright (c) 2006 Thorsten Zitterell + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "pxa255_pic.h" + +#define OSMR0 0x00 +#define OSMR1 0x04 +#define OSMR2 0x08 +#define OSMR3 0x0c +#define OSMR4 0x80 +#define OSCR 0x10 /* OS Timer Count */ +#define OSCR4 0x40 +#define OMCR4 0xc0 +#define OSSR 0x14 /* Timer status register */ +#define OWER 0x18 +#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0*/ + + +typedef struct { + pxa255_pic_handler handler; + uint64_t value; + int level; + int irq; + void *pic; + QEMUTimer *qtimer; + int num; + void *info; +} pxa255_timer; + +typedef struct { + uint32_t base; + int32_t clock; + int32_t oldclock; + uint64_t lastload; + uint32_t freq; + pxa255_timer timer[4]; + uint32_t events; + uint32_t irq_enabled; + uint32_t reset3; + CPUState *cpustate; +} pxa255_timer_info; + + +static void pxa255_timer_update(void *opaque,uint64_t nowqemu) +{ + pxa255_timer_info *s = (pxa255_timer_info *)opaque; + int i; + uint32_t oldvalue; + uint64_t diff_ticks; + uint64_t now_ticks; + uint64_t newalarm; + + diff_ticks = muldiv64(nowqemu - s->lastload,s->freq,ticks_per_sec); + now_ticks = s->clock + diff_ticks; + + for (i = 0; i < 4; i++) + { + oldvalue = s->timer[i].value; + newalarm = nowqemu + muldiv64((oldvalue - now_ticks),ticks_per_sec,s->freq); + qemu_mod_timer(s->timer[i].qtimer, newalarm); + } +} + +static uint32_t pxa255_timer_read(void *opaque, target_phys_addr_t offset) +{ + pxa255_timer_info *s = (pxa255_timer_info *)opaque; + + offset -= s->base; + + switch(offset) { + case(OSMR0): + case(OSMR1): + case(OSMR2): + case(OSMR3): + return s->timer[offset >> 2].value; + case(OSCR): + return s->clock + muldiv64(qemu_get_clock(vm_clock) - s->lastload,s->freq,ticks_per_sec); + case(OIER): + return s->irq_enabled; + case(OWER): + return s->reset3; + default: + cpu_abort (cpu_single_env, "pxa255_timer_read: Bad offset %x\n", offset); + } + + return 0; +} + +static void pxa255_timer_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + int i; + pxa255_timer_info *s = (pxa255_timer_info *)opaque; + + offset -= s->base; + + switch(offset) { + case(OSMR0): + case(OSMR1): + case(OSMR2): + case(OSMR3): + s->timer[offset >> 2].value = value; + pxa255_timer_update(s,qemu_get_clock(vm_clock)); + break; + case(OSCR): + s->oldclock = s->clock; + s->lastload = qemu_get_clock(vm_clock); + s->clock = value; + pxa255_timer_update(s,s->lastload); + break; + case(OIER): + s->irq_enabled = value; + break; + case(OSSR): /* status register */ + s->events &= ~value; + for (i = 0; i < 4; i++) { + if (s->timer[i].level && (value & (1 << i))) { + s->timer[i].level = 0; + pxa255_pic_set_irq(s->timer[i].pic,s->timer[i].irq,0); + } + } + break; + case(OWER): /* reset on OSMR3 match? */ + s->reset3 = value; + break; + default: + cpu_abort (cpu_single_env, "pxa255_timer_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *pxa255_timer_readfn[] = { + pxa255_timer_read, + pxa255_timer_read, + pxa255_timer_read +}; + +static CPUWriteMemoryFunc *pxa255_timer_writefn[] = { + pxa255_timer_write, + pxa255_timer_write, + pxa255_timer_write +}; + +static void pxa255_timer_tick(void *opaque) +{ + pxa255_timer *t = (pxa255_timer *)opaque; + pxa255_timer_info *i = (pxa255_timer_info *) t->info; + + if (i->irq_enabled & (1 << t->num)) { + t->level = 1; + pxa255_pic_set_irq(t->pic,t->irq,1); + } + + if (t->num == 3) { + if (i->reset3 & 0x1) { + printf("Do reset\n"); + cpu_reset(i->cpustate); + i->reset3 = 0; + } + } +} + + +void pxa255_timer_init(uint32_t base, void *pic, int irq, CPUState *cpustate) +{ + int i; + int iomemtype; + pxa255_timer_info *s; + + s = (pxa255_timer_info *)qemu_mallocz(sizeof(pxa255_timer_info)); + s->base = base; + s->irq_enabled = 0; + s->oldclock = 0; + s->clock = 0; + s->freq = 3686400; + s->lastload = qemu_get_clock(vm_clock); + s->reset3 = 0; + s->cpustate = cpustate; + + for (i = 0; i < 4; i++) { + s->timer[i].value = 0; + s->timer[i].irq = irq+i; + s->timer[i].pic = pic; + s->timer[i].info = s; + s->timer[i].num = i; + s->timer[i].level = 0; + s->timer[i].qtimer = qemu_new_timer(vm_clock, pxa255_timer_tick, &s->timer[i]); + } + + iomemtype = cpu_register_io_memory(0, pxa255_timer_readfn, + pxa255_timer_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + +} Index: qemu/hw/pxa255_timer.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/pxa255_timer.h 2006-11-21 22:21:08.000000000 +0800 @@ -0,0 +1,18 @@ +/* + * Generic PIX255 Programmable Interrupt Controller support. + * + * Copyright (c) 2006 Thorsten Zitterell. + * + * This code is licenced under the LGPL. + * + * Arm hardware uses a wide variety of interrupt handling hardware. + * This provides a generic framework for connecting interrupt sources and + * inputs. + */ + +#ifndef PXA255_TIMER_H +#define PXA255_TIMER_H 1 + +void pxa255_timer_init(uint32_t base, void *pic, int irq, CPUState *cpustate); + +#endif /* !PXA255_TIMER_H */ Index: qemu/Makefile.target =================================================================== --- qemu.orig/Makefile.target 2006-11-21 14:20:04.000000000 +0800 +++ qemu/Makefile.target 2006-11-21 22:18:08.000000000 +0800 @@ -376,6 +376,7 @@ VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o VL_OBJS+= versatile_pci.o +VL_OBJS+= pxa255_pic.o pxa255_gpio.o pxa255_timer.o pxa255_dma.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o endif ifeq ($(TARGET_BASE_ARCH), sh4)