]> Git Repo - qemu.git/commitdiff
Core features of ARM XScale processors. Main PXA270 and PXA255 peripherals.
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 30 Apr 2007 01:26:42 +0000 (01:26 +0000)
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 30 Apr 2007 01:26:42 +0000 (01:26 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2749 c046a42c-6fe2-441c-8c8c-71466251a162

hw/pxa.h [new file with mode: 0644]
hw/pxa2xx.c [new file with mode: 0644]
hw/pxa2xx_dma.c [new file with mode: 0644]
hw/pxa2xx_gpio.c [new file with mode: 0644]
hw/pxa2xx_pic.c [new file with mode: 0644]
target-arm/cpu.h
target-arm/exec.h
target-arm/helper.c
target-arm/op.c
target-arm/translate.c
vl.h

diff --git a/hw/pxa.h b/hw/pxa.h
new file mode 100644 (file)
index 0000000..8a4ffa8
--- /dev/null
+++ b/hw/pxa.h
@@ -0,0 +1,176 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <[email protected]>
+ *
+ * This code is licenced under the GPL.
+ */
+#ifndef PXA_H
+# define PXA_H                 "pxa.h"
+
+/* Interrupt numbers */
+# define PXA2XX_PIC_SSP3       0
+# define PXA2XX_PIC_USBH2      2
+# define PXA2XX_PIC_USBH1      3
+# define PXA2XX_PIC_PWRI2C     6
+# define PXA25X_PIC_HWUART     7
+# define PXA27X_PIC_OST_4_11   7
+# define PXA2XX_PIC_GPIO_0     8
+# define PXA2XX_PIC_GPIO_1     9
+# define PXA2XX_PIC_GPIO_X     10
+# define PXA2XX_PIC_I2S        13
+# define PXA26X_PIC_ASSP       15
+# define PXA25X_PIC_NSSP       16
+# define PXA27X_PIC_SSP2       16
+# define PXA2XX_PIC_LCD                17
+# define PXA2XX_PIC_I2C                18
+# define PXA2XX_PIC_ICP                19
+# define PXA2XX_PIC_STUART     20
+# define PXA2XX_PIC_BTUART     21
+# define PXA2XX_PIC_FFUART     22
+# define PXA2XX_PIC_MMC                23
+# define PXA2XX_PIC_SSP                24
+# define PXA2XX_PIC_DMA                25
+# define PXA2XX_PIC_OST_0      26
+# define PXA2XX_PIC_RTC1HZ     30
+# define PXA2XX_PIC_RTCALARM   31
+
+/* DMA requests */
+# define PXA2XX_RX_RQ_I2S      2
+# define PXA2XX_TX_RQ_I2S      3
+# define PXA2XX_RX_RQ_BTUART   4
+# define PXA2XX_TX_RQ_BTUART   5
+# define PXA2XX_RX_RQ_FFUART   6
+# define PXA2XX_TX_RQ_FFUART   7
+# define PXA2XX_RX_RQ_SSP1     13
+# define PXA2XX_TX_RQ_SSP1     14
+# define PXA2XX_RX_RQ_SSP2     15
+# define PXA2XX_TX_RQ_SSP2     16
+# define PXA2XX_RX_RQ_ICP      17
+# define PXA2XX_TX_RQ_ICP      18
+# define PXA2XX_RX_RQ_STUART   19
+# define PXA2XX_TX_RQ_STUART   20
+# define PXA2XX_RX_RQ_MMCI     21
+# define PXA2XX_TX_RQ_MMCI     22
+# define PXA2XX_USB_RQ(x)      ((x) + 24)
+# define PXA2XX_RX_RQ_SSP3     66
+# define PXA2XX_TX_RQ_SSP3     67
+
+# define PXA2XX_RAM_BASE       0xa0000000
+
+/* pxa2xx_pic.c */
+struct pxa2xx_pic_state_s;
+qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
+
+/* pxa2xx_gpio.c */
+struct pxa2xx_gpio_info_s;
+struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
+                CPUState *env, qemu_irq *pic, int lines);
+void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level);
+void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
+                gpio_handler_t handler, void *opaque);
+void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s,
+                void (*handler)(void *opaque), void *opaque);
+
+/* pxa2xx_dma.c */
+struct pxa2xx_dma_state_s;
+struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
+                qemu_irq irq);
+struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
+                qemu_irq irq);
+void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on);
+
+/* pxa2xx.c */
+struct pxa2xx_ssp_s;
+void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
+                uint32_t (*readfn)(void *opaque),
+                void (*writefn)(void *opaque, uint32_t value), void *opaque);
+
+struct pxa2xx_i2s_s;
+struct pxa2xx_fir_s;
+
+struct pxa2xx_state_s {
+    CPUState *env;
+    qemu_irq *pic;
+    struct pxa2xx_dma_state_s *dma;
+    struct pxa2xx_gpio_info_s *gpio;
+    struct pxa2xx_ssp_s **ssp;
+    struct pxa2xx_i2s_s *i2s;
+    struct pxa2xx_fir_s *fir;
+
+    /* Power management */
+    target_phys_addr_t pm_base;
+    uint32_t pm_regs[0x40];
+
+    /* Clock management */
+    target_phys_addr_t cm_base;
+    uint32_t cm_regs[4];
+    uint32_t clkcfg;
+
+    /* Memory management */
+    target_phys_addr_t mm_base;
+    uint32_t mm_regs[0x1a];
+
+    /* Performance monitoring */
+    uint32_t pmnc;
+
+    /* Real-Time clock */
+    target_phys_addr_t rtc_base;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t rdar1;
+    uint32_t rdar2;
+    uint32_t ryar1;
+    uint32_t ryar2;
+    uint32_t swar1;
+    uint32_t swar2;
+    uint32_t piar;
+    uint32_t last_rcnr;
+    uint32_t last_rdcr;
+    uint32_t last_rycr;
+    uint32_t last_swcr;
+    uint32_t last_rtcpicr;
+    int64_t last_hz;
+    int64_t last_sw;
+    int64_t last_pi;
+    QEMUTimer *rtc_hz;
+    QEMUTimer *rtc_rdal1;
+    QEMUTimer *rtc_rdal2;
+    QEMUTimer *rtc_swal1;
+    QEMUTimer *rtc_swal2;
+    QEMUTimer *rtc_pi;
+};
+
+struct pxa2xx_i2s_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    struct pxa2xx_dma_state_s *dma;
+    void (*data_req)(void *, int, int);
+
+    uint32_t control[2];
+    uint32_t status;
+    uint32_t mask;
+    uint32_t clk;
+
+    int enable;
+    int rx_len;
+    int tx_len;
+    void (*codec_out)(void *, uint32_t);
+    uint32_t (*codec_in)(void *);
+    void *opaque;
+
+    int fifo_len;
+    uint32_t fifo[16];
+};
+
+# define PA_FMT                        "0x%08lx"
+# define REG_FMT               "0x%lx"
+
+struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision);
+struct pxa2xx_state_s *pxa255_init(DisplayState *ds);
+
+void pxa2xx_reset(int line, int level, void *opaque);
+
+#endif /* PXA_H */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
new file mode 100644 (file)
index 0000000..f9d2925
--- /dev/null
@@ -0,0 +1,1673 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <[email protected]>
+ *
+ * This code is licenced under the GPL.
+ */
+
+# include "vl.h"
+
+static struct {
+    target_phys_addr_t io_base;
+    int irqn;
+} pxa255_serial[] = {
+    { 0x40100000, PXA2XX_PIC_FFUART },
+    { 0x40200000, PXA2XX_PIC_BTUART },
+    { 0x40700000, PXA2XX_PIC_STUART },
+    { 0x41600000, PXA25X_PIC_HWUART },
+    { 0, 0 }
+}, pxa270_serial[] = {
+    { 0x40100000, PXA2XX_PIC_FFUART },
+    { 0x40200000, PXA2XX_PIC_BTUART },
+    { 0x40700000, PXA2XX_PIC_STUART },
+    { 0, 0 }
+};
+
+static struct {
+    target_phys_addr_t io_base;
+    int irqn;
+} pxa250_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0, 0 }
+}, pxa255_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41400000, PXA25X_PIC_NSSP },
+    { 0, 0 }
+}, pxa26x_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41400000, PXA25X_PIC_NSSP },
+    { 0x41500000, PXA26X_PIC_ASSP },
+    { 0, 0 }
+}, pxa27x_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41700000, PXA27X_PIC_SSP2 },
+    { 0x41900000, PXA2XX_PIC_SSP3 },
+    { 0, 0 }
+};
+
+#define PMCR   0x00    /* Power Manager Control register */
+#define PSSR   0x04    /* Power Manager Sleep Status register */
+#define PSPR   0x08    /* Power Manager Scratch-Pad register */
+#define PWER   0x0c    /* Power Manager Wake-Up Enable register */
+#define PRER   0x10    /* Power Manager Rising-Edge Detect Enable register */
+#define PFER   0x14    /* Power Manager Falling-Edge Detect Enable register */
+#define PEDR   0x18    /* Power Manager Edge-Detect Status register */
+#define PCFR   0x1c    /* Power Manager General Configuration register */
+#define PGSR0  0x20    /* Power Manager GPIO Sleep-State register 0 */
+#define PGSR1  0x24    /* Power Manager GPIO Sleep-State register 1 */
+#define PGSR2  0x28    /* Power Manager GPIO Sleep-State register 2 */
+#define PGSR3  0x2c    /* Power Manager GPIO Sleep-State register 3 */
+#define RCSR   0x30    /* Reset Controller Status register */
+#define PSLR   0x34    /* Power Manager Sleep Configuration register */
+#define PTSR   0x38    /* Power Manager Standby Configuration register */
+#define PVCR   0x40    /* Power Manager Voltage Change Control register */
+#define PUCR   0x4c    /* Power Manager USIM Card Control/Status register */
+#define PKWR   0x50    /* Power Manager Keyboard Wake-Up Enable register */
+#define PKSR   0x54    /* Power Manager Keyboard Level-Detect Status */
+#define PCMD0  0x80    /* Power Manager I2C Command register File 0 */
+#define PCMD31 0xfc    /* Power Manager I2C Command register File 31 */
+
+static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->pm_base;
+
+    switch (addr) {
+    case PMCR ... PCMD31:
+        if (addr & 3)
+            goto fail;
+
+        return s->pm_regs[addr >> 2];
+    default:
+    fail:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->pm_base;
+
+    switch (addr) {
+    case PMCR:
+        s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
+        s->pm_regs[addr >> 2] |= value & 0x15;
+        break;
+
+    case PSSR: /* Read-clean registers */
+    case RCSR:
+    case PKSR:
+        s->pm_regs[addr >> 2] &= ~value;
+        break;
+
+    default:   /* Read-write registers */
+        if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) {
+            s->pm_regs[addr >> 2] = value;
+            break;
+        }
+
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_pm_readfn[] = {
+    pxa2xx_pm_read,
+    pxa2xx_pm_read,
+    pxa2xx_pm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = {
+    pxa2xx_pm_write,
+    pxa2xx_pm_write,
+    pxa2xx_pm_write,
+};
+
+#define CCCR   0x00    /* Core Clock Configuration register */
+#define CKEN   0x04    /* Clock Enable register */
+#define OSCC   0x08    /* Oscillator Configuration register */
+#define CCSR   0x0c    /* Core Clock Status register */
+
+static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->cm_base;
+
+    switch (addr) {
+    case CCCR:
+    case CKEN:
+    case OSCC:
+        return s->cm_regs[addr >> 2];
+
+    case CCSR:
+        return s->cm_regs[CCCR >> 2] | (3 << 28);
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->cm_base;
+
+    switch (addr) {
+    case CCCR:
+    case CKEN:
+        s->cm_regs[addr >> 2] = value;
+        break;
+
+    case OSCC:
+        s->cm_regs[addr >> 2] &= ~0x6e;
+        s->cm_regs[addr >> 2] |= value & 0x6e;
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_cm_readfn[] = {
+    pxa2xx_cm_read,
+    pxa2xx_cm_read,
+    pxa2xx_cm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = {
+    pxa2xx_cm_write,
+    pxa2xx_cm_write,
+    pxa2xx_cm_write,
+};
+
+static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    switch (reg) {
+    case 6:    /* Clock Configuration register */
+        return s->clkcfg;
+
+    case 7:    /* Power Mode register */
+        return 0;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    static const char *pwrmode[8] = {
+        "Normal", "Idle", "Deep-idle", "Standby",
+        "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
+    };
+
+    switch (reg) {
+    case 6:    /* Clock Configuration register */
+        s->clkcfg = value & 0xf;
+        if (value & 2)
+            printf("%s: CPU frequency change attempt\n", __FUNCTION__);
+        break;
+
+    case 7:    /* Power Mode register */
+        if (value & 8)
+            printf("%s: CPU voltage change attempt\n", __FUNCTION__);
+        switch (value & 7) {
+        case 0:
+            /* Do nothing */
+            break;
+
+        case 1:
+            /* Idle */
+            if (!(s->cm_regs[CCCR] & (1 << 31))) {     /* CPDIS */
+                cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+                break;
+            }
+            /* Fall through.  */
+
+        case 2:
+            /* Deep-Idle */
+            cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+            s->pm_regs[RCSR >> 2] |= 0x8;      /* Set GPR */
+            goto message;
+
+        case 3:
+            cpu_reset(s->env);
+            s->env->cp15.c1_sys = 0;
+            s->env->cp15.c1_coproc = 0;
+            s->env->cp15.c2 = 0;
+            s->env->cp15.c3 = 0;
+            s->pm_regs[PSSR >> 2] |= 0x8;      /* Set STS */
+            s->pm_regs[RCSR >> 2] |= 0x8;      /* Set GPR */
+
+            /*
+             * The scratch-pad register is almost universally used
+             * for storing the return address on suspend.  For the
+             * lack of a resuming bootloader, perform a jump
+             * directly to that address.
+             */
+            memset(s->env->regs, 0, 4 * 15);
+            s->env->regs[15] = s->pm_regs[PSPR >> 2];
+
+#if 0
+            buffer = 0xe59ff000;       /* ldr     pc, [pc, #0] */
+            cpu_physical_memory_write(0, &buffer, 4);
+            buffer = s->pm_regs[PSPR >> 2];
+            cpu_physical_memory_write(8, &buffer, 4);
+#endif
+
+            /* Suspend */
+            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+
+            goto message;
+
+        default:
+        message:
+            printf("%s: machine entered %s mode\n", __FUNCTION__,
+                            pwrmode[value & 7]);
+        }
+        break;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+/* Performace Monitoring Registers */
+#define CPPMNC         0       /* Performance Monitor Control register */
+#define CPCCNT         1       /* Clock Counter register */
+#define CPINTEN                4       /* Interrupt Enable register */
+#define CPFLAG         5       /* Overflow Flag register */
+#define CPEVTSEL       8       /* Event Selection register */
+
+#define CPPMN0         0       /* Performance Count register 0 */
+#define CPPMN1         1       /* Performance Count register 1 */
+#define CPPMN2         2       /* Performance Count register 2 */
+#define CPPMN3         3       /* Performance Count register 3 */
+
+static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    switch (reg) {
+    case CPPMNC:
+        return s->pmnc;
+    case CPCCNT:
+        if (s->pmnc & 1)
+            return qemu_get_clock(vm_clock);
+        else
+            return 0;
+    case CPINTEN:
+    case CPFLAG:
+    case CPEVTSEL:
+        return 0;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    switch (reg) {
+    case CPPMNC:
+        s->pmnc = value;
+        break;
+
+    case CPCCNT:
+    case CPINTEN:
+    case CPFLAG:
+    case CPEVTSEL:
+        break;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm)
+{
+    switch (crm) {
+    case 0:
+        return pxa2xx_clkpwr_read(opaque, op2, reg, crm);
+    case 1:
+        return pxa2xx_perf_read(opaque, op2, reg, crm);
+    case 2:
+        switch (reg) {
+        case CPPMN0:
+        case CPPMN1:
+        case CPPMN2:
+        case CPPMN3:
+            return 0;
+        }
+        /* Fall through */
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    switch (crm) {
+    case 0:
+        pxa2xx_clkpwr_write(opaque, op2, reg, crm, value);
+        break;
+    case 1:
+        pxa2xx_perf_write(opaque, op2, reg, crm, value);
+        break;
+    case 2:
+        switch (reg) {
+        case CPPMN0:
+        case CPPMN1:
+        case CPPMN2:
+        case CPPMN3:
+            return;
+        }
+        /* Fall through */
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+#define MDCNFG         0x00    /* SDRAM Configuration register */
+#define MDREFR         0x04    /* SDRAM Refresh Control register */
+#define MSC0           0x08    /* Static Memory Control register 0 */
+#define MSC1           0x0c    /* Static Memory Control register 1 */
+#define MSC2           0x10    /* Static Memory Control register 2 */
+#define MECR           0x14    /* Expansion Memory Bus Config register */
+#define SXCNFG         0x1c    /* Synchronous Static Memory Config register */
+#define MCMEM0         0x28    /* PC Card Memory Socket 0 Timing register */
+#define MCMEM1         0x2c    /* PC Card Memory Socket 1 Timing register */
+#define MCATT0         0x30    /* PC Card Attribute Socket 0 register */
+#define MCATT1         0x34    /* PC Card Attribute Socket 1 register */
+#define MCIO0          0x38    /* PC Card I/O Socket 0 Timing register */
+#define MCIO1          0x3c    /* PC Card I/O Socket 1 Timing register */
+#define MDMRS          0x40    /* SDRAM Mode Register Set Config register */
+#define BOOT_DEF       0x44    /* Boot-time Default Configuration register */
+#define ARB_CNTL       0x48    /* Arbiter Control register */
+#define BSCNTR0                0x4c    /* Memory Buffer Strength Control register 0 */
+#define BSCNTR1                0x50    /* Memory Buffer Strength Control register 1 */
+#define LCDBSCNTR      0x54    /* LCD Buffer Strength Control register */
+#define MDMRSLP                0x58    /* Low Power SDRAM Mode Set Config register */
+#define BSCNTR2                0x5c    /* Memory Buffer Strength Control register 2 */
+#define BSCNTR3                0x60    /* Memory Buffer Strength Control register 3 */
+#define SA1110         0x64    /* SA-1110 Memory Compatibility register */
+
+static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->mm_base;
+
+    switch (addr) {
+    case MDCNFG ... SA1110:
+        if ((addr & 3) == 0)
+            return s->mm_regs[addr >> 2];
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->mm_base;
+
+    switch (addr) {
+    case MDCNFG ... SA1110:
+        if ((addr & 3) == 0) {
+            s->mm_regs[addr >> 2] = value;
+            break;
+        }
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_mm_readfn[] = {
+    pxa2xx_mm_read,
+    pxa2xx_mm_read,
+    pxa2xx_mm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_mm_writefn[] = {
+    pxa2xx_mm_write,
+    pxa2xx_mm_write,
+    pxa2xx_mm_write,
+};
+
+/* Synchronous Serial Ports */
+struct pxa2xx_ssp_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    int enable;
+
+    uint32_t sscr[2];
+    uint32_t sspsp;
+    uint32_t ssto;
+    uint32_t ssitr;
+    uint32_t sssr;
+    uint8_t sstsa;
+    uint8_t ssrsa;
+    uint8_t ssacd;
+
+    uint32_t rx_fifo[16];
+    int rx_level;
+    int rx_start;
+
+    uint32_t (*readfn)(void *opaque);
+    void (*writefn)(void *opaque, uint32_t value);
+    void *opaque;
+};
+
+#define SSCR0  0x00    /* SSP Control register 0 */
+#define SSCR1  0x04    /* SSP Control register 1 */
+#define SSSR   0x08    /* SSP Status register */
+#define SSITR  0x0c    /* SSP Interrupt Test register */
+#define SSDR   0x10    /* SSP Data register */
+#define SSTO   0x28    /* SSP Time-Out register */
+#define SSPSP  0x2c    /* SSP Programmable Serial Protocol register */
+#define SSTSA  0x30    /* SSP TX Time Slot Active register */
+#define SSRSA  0x34    /* SSP RX Time Slot Active register */
+#define SSTSS  0x38    /* SSP Time Slot Status register */
+#define SSACD  0x3c    /* SSP Audio Clock Divider register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x)   (((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x)   (((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x)   (((x) & 0x30) == 0x30)
+#define SSCR0_SSE      (1 << 7)
+#define SSCR0_RIM      (1 << 22)
+#define SSCR0_TIM      (1 << 23)
+#define SSCR0_MOD      (1 << 31)
+#define SSCR0_DSS(x)   (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
+#define SSCR1_RIE      (1 << 0)
+#define SSCR1_TIE      (1 << 1)
+#define SSCR1_LBM      (1 << 2)
+#define SSCR1_MWDS     (1 << 5)
+#define SSCR1_TFT(x)   ((((x) >> 6) & 0xf) + 1)
+#define SSCR1_RFT(x)   ((((x) >> 10) & 0xf) + 1)
+#define SSCR1_EFWR     (1 << 14)
+#define SSCR1_PINTE    (1 << 18)
+#define SSCR1_TINTE    (1 << 19)
+#define SSCR1_RSRE     (1 << 20)
+#define SSCR1_TSRE     (1 << 21)
+#define SSCR1_EBCEI    (1 << 29)
+#define SSITR_INT      (7 << 5)
+#define SSSR_TNF       (1 << 2)
+#define SSSR_RNE       (1 << 3)
+#define SSSR_TFS       (1 << 5)
+#define SSSR_RFS       (1 << 6)
+#define SSSR_ROR       (1 << 7)
+#define SSSR_PINT      (1 << 18)
+#define SSSR_TINT      (1 << 19)
+#define SSSR_EOC       (1 << 20)
+#define SSSR_TUR       (1 << 21)
+#define SSSR_BCE       (1 << 23)
+#define SSSR_RW                0x00bc0080
+
+static void pxa2xx_ssp_int_update(struct pxa2xx_ssp_s *s)
+{
+    int level = 0;
+
+    level |= s->ssitr & SSITR_INT;
+    level |= (s->sssr & SSSR_BCE)  &&  (s->sscr[1] & SSCR1_EBCEI);
+    level |= (s->sssr & SSSR_TUR)  && !(s->sscr[0] & SSCR0_TIM);
+    level |= (s->sssr & SSSR_EOC)  &&  (s->sssr & (SSSR_TINT | SSSR_PINT));
+    level |= (s->sssr & SSSR_TINT) &&  (s->sscr[1] & SSCR1_TINTE);
+    level |= (s->sssr & SSSR_PINT) &&  (s->sscr[1] & SSCR1_PINTE);
+    level |= (s->sssr & SSSR_ROR)  && !(s->sscr[0] & SSCR0_RIM);
+    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
+    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
+    qemu_set_irq(s->irq, !!level);
+}
+
+static void pxa2xx_ssp_fifo_update(struct pxa2xx_ssp_s *s)
+{
+    s->sssr &= ~(0xf << 12);   /* Clear RFL */
+    s->sssr &= ~(0xf << 8);    /* Clear TFL */
+    s->sssr &= ~SSSR_TNF;
+    if (s->enable) {
+        s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
+        if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
+            s->sssr |= SSSR_RFS;
+        else
+            s->sssr &= ~SSSR_RFS;
+        if (0 <= SSCR1_TFT(s->sscr[1]))
+            s->sssr |= SSSR_TFS;
+        else
+            s->sssr &= ~SSSR_TFS;
+        if (s->rx_level)
+            s->sssr |= SSSR_RNE;
+        else
+            s->sssr &= ~SSSR_RNE;
+        s->sssr |= SSSR_TNF;
+    }
+
+    pxa2xx_ssp_int_update(s);
+}
+
+static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+    uint32_t retval;
+    addr -= s->base;
+
+    switch (addr) {
+    case SSCR0:
+        return s->sscr[0];
+    case SSCR1:
+        return s->sscr[1];
+    case SSPSP:
+        return s->sspsp;
+    case SSTO:
+        return s->ssto;
+    case SSITR:
+        return s->ssitr;
+    case SSSR:
+        return s->sssr | s->ssitr;
+    case SSDR:
+        if (!s->enable)
+            return 0xffffffff;
+        if (s->rx_level < 1) {
+            printf("%s: SSP Rx Underrun\n", __FUNCTION__);
+            return 0xffffffff;
+        }
+        s->rx_level --;
+        retval = s->rx_fifo[s->rx_start ++];
+        s->rx_start &= 0xf;
+        pxa2xx_ssp_fifo_update(s);
+        return retval;
+    case SSTSA:
+        return s->sstsa;
+    case SSRSA:
+        return s->ssrsa;
+    case SSTSS:
+        return 0;
+    case SSACD:
+        return s->ssacd;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+    addr -= s->base;
+
+    switch (addr) {
+    case SSCR0:
+        s->sscr[0] = value & 0xc7ffffff;
+        s->enable = value & SSCR0_SSE;
+        if (value & SSCR0_MOD)
+            printf("%s: Attempt to use network mode\n", __FUNCTION__);
+        if (s->enable && SSCR0_DSS(value) < 4)
+            printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
+                            SSCR0_DSS(value));
+        if (!(value & SSCR0_SSE)) {
+            s->sssr = 0;
+            s->ssitr = 0;
+            s->rx_level = 0;
+        }
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSCR1:
+        s->sscr[1] = value;
+        if (value & (SSCR1_LBM | SSCR1_EFWR))
+            printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSPSP:
+        s->sspsp = value;
+        break;
+
+    case SSTO:
+        s->ssto = value;
+        break;
+
+    case SSITR:
+        s->ssitr = value & SSITR_INT;
+        pxa2xx_ssp_int_update(s);
+        break;
+
+    case SSSR:
+        s->sssr &= ~(value & SSSR_RW);
+        pxa2xx_ssp_int_update(s);
+        break;
+
+    case SSDR:
+        if (SSCR0_UWIRE(s->sscr[0])) {
+            if (s->sscr[1] & SSCR1_MWDS)
+                value &= 0xffff;
+            else
+                value &= 0xff;
+        } else
+            /* Note how 32bits overflow does no harm here */
+            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+        /* Data goes from here to the Tx FIFO and is shifted out from
+         * there directly to the slave, no need to buffer it.
+         */
+        if (s->enable) {
+            if (s->writefn)
+                s->writefn(s->opaque, value);
+
+            if (s->rx_level < 0x10) {
+                if (s->readfn)
+                    s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] =
+                            s->readfn(s->opaque);
+                else
+                    s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = 0x0;
+            } else
+                s->sssr |= SSSR_ROR;
+        }
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSTSA:
+        s->sstsa = value;
+        break;
+
+    case SSRSA:
+        s->ssrsa = value;
+        break;
+
+    case SSACD:
+        s->ssacd = value;
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
+                uint32_t (*readfn)(void *opaque),
+                void (*writefn)(void *opaque, uint32_t value), void *opaque)
+{
+    if (!port) {
+        printf("%s: no such SSP\n", __FUNCTION__);
+        exit(-1);
+    }
+
+    port->opaque = opaque;
+    port->readfn = readfn;
+    port->writefn = writefn;
+}
+
+static CPUReadMemoryFunc *pxa2xx_ssp_readfn[] = {
+    pxa2xx_ssp_read,
+    pxa2xx_ssp_read,
+    pxa2xx_ssp_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_ssp_writefn[] = {
+    pxa2xx_ssp_write,
+    pxa2xx_ssp_write,
+    pxa2xx_ssp_write,
+};
+
+/* Real-Time Clock */
+#define RCNR           0x00    /* RTC Counter register */
+#define RTAR           0x04    /* RTC Alarm register */
+#define RTSR           0x08    /* RTC Status register */
+#define RTTR           0x0c    /* RTC Timer Trim register */
+#define RDCR           0x10    /* RTC Day Counter register */
+#define RYCR           0x14    /* RTC Year Counter register */
+#define RDAR1          0x18    /* RTC Wristwatch Day Alarm register 1 */
+#define RYAR1          0x1c    /* RTC Wristwatch Year Alarm register 1 */
+#define RDAR2          0x20    /* RTC Wristwatch Day Alarm register 2 */
+#define RYAR2          0x24    /* RTC Wristwatch Year Alarm register 2 */
+#define SWCR           0x28    /* RTC Stopwatch Counter register */
+#define SWAR1          0x2c    /* RTC Stopwatch Alarm register 1 */
+#define SWAR2          0x30    /* RTC Stopwatch Alarm register 2 */
+#define RTCPICR                0x34    /* RTC Periodic Interrupt Counter register */
+#define PIAR           0x38    /* RTC Periodic Interrupt Alarm register */
+
+static inline void pxa2xx_rtc_int_update(struct pxa2xx_state_s *s)
+{
+    qemu_set_irq(s->pic[PXA2XX_PIC_RTCALARM], !!(s->rtsr & 0x2553));
+}
+
+static void pxa2xx_rtc_hzupdate(struct pxa2xx_state_s *s)
+{
+    int64_t rt = qemu_get_clock(rt_clock);
+    s->last_rcnr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_rdcr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_hz = rt;
+}
+
+static void pxa2xx_rtc_swupdate(struct pxa2xx_state_s *s)
+{
+    int64_t rt = qemu_get_clock(rt_clock);
+    if (s->rtsr & (1 << 12))
+        s->last_swcr += (rt - s->last_sw) / 10;
+    s->last_sw = rt;
+}
+
+static void pxa2xx_rtc_piupdate(struct pxa2xx_state_s *s)
+{
+    int64_t rt = qemu_get_clock(rt_clock);
+    if (s->rtsr & (1 << 15))
+        s->last_swcr += rt - s->last_pi;
+    s->last_pi = rt;
+}
+
+static inline void pxa2xx_rtc_alarm_update(struct pxa2xx_state_s *s,
+                uint32_t rtsr)
+{
+    if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
+        qemu_mod_timer(s->rtc_hz, s->last_hz +
+                (((s->rtar - s->last_rcnr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15));
+    else
+        qemu_del_timer(s->rtc_hz);
+
+    if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
+        qemu_mod_timer(s->rtc_rdal1, s->last_hz +
+                (((s->rdar1 - s->last_rdcr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_rdal1);
+
+    if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
+        qemu_mod_timer(s->rtc_rdal2, s->last_hz +
+                (((s->rdar2 - s->last_rdcr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_rdal2);
+
+    if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
+        qemu_mod_timer(s->rtc_swal1, s->last_sw +
+                        (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_swal1);
+
+    if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
+        qemu_mod_timer(s->rtc_swal2, s->last_sw +
+                        (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_swal2);
+
+    if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
+        qemu_mod_timer(s->rtc_pi, s->last_pi +
+                        (s->piar & 0xffff) - s->last_rtcpicr);
+    else
+        qemu_del_timer(s->rtc_pi);
+}
+
+static inline void pxa2xx_rtc_hz_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 0);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 4);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 6);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal1_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 8);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal2_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 10);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_pi_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 13);
+    pxa2xx_rtc_piupdate(s);
+    s->last_rtcpicr = 0;
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->rtc_base;
+
+    switch (addr) {
+    case RTTR:
+        return s->rttr;
+    case RTSR:
+        return s->rtsr;
+    case RTAR:
+        return s->rtar;
+    case RDAR1:
+        return s->rdar1;
+    case RDAR2:
+        return s->rdar2;
+    case RYAR1:
+        return s->ryar1;
+    case RYAR2:
+        return s->ryar2;
+    case SWAR1:
+        return s->swar1;
+    case SWAR2:
+        return s->swar2;
+    case PIAR:
+        return s->piar;
+    case RCNR:
+        return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    case RDCR:
+        return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    case RYCR:
+        return s->last_rycr;
+    case SWCR:
+        if (s->rtsr & (1 << 12))
+            return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10;
+        else
+            return s->last_swcr;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->rtc_base;
+
+    switch (addr) {
+    case RTTR:
+        if (!(s->rttr & (1 << 31))) {
+            pxa2xx_rtc_hzupdate(s);
+            s->rttr = value;
+            pxa2xx_rtc_alarm_update(s, s->rtsr);
+        }
+        break;
+
+    case RTSR:
+        if ((s->rtsr ^ value) & (1 << 15))
+            pxa2xx_rtc_piupdate(s);
+
+        if ((s->rtsr ^ value) & (1 << 12))
+            pxa2xx_rtc_swupdate(s);
+
+        if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
+            pxa2xx_rtc_alarm_update(s, value);
+
+        s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
+        pxa2xx_rtc_int_update(s);
+        break;
+
+    case RTAR:
+        s->rtar = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDAR1:
+        s->rdar1 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDAR2:
+        s->rdar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYAR1:
+        s->ryar1 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYAR2:
+        s->ryar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case SWAR1:
+        pxa2xx_rtc_swupdate(s);
+        s->swar1 = value;
+        s->last_swcr = 0;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case SWAR2:
+        s->swar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case PIAR:
+        s->piar = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RCNR:
+        pxa2xx_rtc_hzupdate(s);
+        s->last_rcnr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDCR:
+        pxa2xx_rtc_hzupdate(s);
+        s->last_rdcr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYCR:
+        s->last_rycr = value;
+        break;
+
+    case SWCR:
+        pxa2xx_rtc_swupdate(s);
+        s->last_swcr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RTCPICR:
+        pxa2xx_rtc_piupdate(s);
+        s->last_rtcpicr = value & 0xffff;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static void pxa2xx_rtc_reset(struct pxa2xx_state_s *s)
+{
+    struct tm *tm;
+    time_t ti;
+    int wom;
+
+    s->rttr = 0x7fff;
+    s->rtsr = 0;
+
+    time(&ti);
+    if (rtc_utc)
+        tm = gmtime(&ti);
+    else
+        tm = localtime(&ti);
+    wom = ((tm->tm_mday - 1) / 7) + 1;
+
+    s->last_rcnr = (uint32_t) ti;
+    s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) |
+            (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec;
+    s->last_rycr = ((tm->tm_year + 1900) << 9) |
+            ((tm->tm_mon + 1) << 5) | tm->tm_mday;
+    s->last_swcr = (tm->tm_hour << 19) |
+            (tm->tm_min << 13) | (tm->tm_sec << 7);
+    s->last_rtcpicr = 0;
+    s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
+
+    s->rtc_hz    = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick,    s);
+    s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s);
+    s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s);
+    s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s);
+    s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s);
+    s->rtc_pi    = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick,    s);
+}
+
+static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = {
+    pxa2xx_rtc_read,
+    pxa2xx_rtc_read,
+    pxa2xx_rtc_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = {
+    pxa2xx_rtc_write,
+    pxa2xx_rtc_write,
+    pxa2xx_rtc_write,
+};
+
+/* PXA Inter-IC Sound Controller */
+static void pxa2xx_i2s_reset(struct pxa2xx_i2s_s *i2s)
+{
+    i2s->rx_len = 0;
+    i2s->tx_len = 0;
+    i2s->fifo_len = 0;
+    i2s->clk = 0x1a;
+    i2s->control[0] = 0x00;
+    i2s->control[1] = 0x00;
+    i2s->status = 0x00;
+    i2s->mask = 0x00;
+}
+
+#define SACR_TFTH(val) ((val >> 8) & 0xf)
+#define SACR_RFTH(val) ((val >> 12) & 0xf)
+#define SACR_DREC(val) (val & (1 << 3))
+#define SACR_DPRL(val) (val & (1 << 4))
+
+static inline void pxa2xx_i2s_update(struct pxa2xx_i2s_s *i2s)
+{
+    int rfs, tfs;
+    rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
+            !SACR_DREC(i2s->control[1]);
+    tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
+            i2s->enable && !SACR_DPRL(i2s->control[1]);
+
+    pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs);
+    pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs);
+
+    i2s->status &= 0xe0;
+    if (i2s->rx_len)
+        i2s->status |= 1 << 1;                 /* RNE */
+    if (i2s->enable)
+        i2s->status |= 1 << 2;                 /* BSY */
+    if (tfs)
+        i2s->status |= 1 << 3;                 /* TFS */
+    if (rfs)
+        i2s->status |= 1 << 4;                 /* RFS */
+    if (!(i2s->tx_len && i2s->enable))
+        i2s->status |= i2s->fifo_len << 8;     /* TFL */
+    i2s->status |= MAX(i2s->rx_len, 0xf) << 12;        /* RFL */
+
+    qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
+}
+
+#define SACR0  0x00    /* Serial Audio Global Control register */
+#define SACR1  0x04    /* Serial Audio I2S/MSB-Justified Control register */
+#define SASR0  0x0c    /* Serial Audio Interface and FIFO Status register */
+#define SAIMR  0x14    /* Serial Audio Interrupt Mask register */
+#define SAICR  0x18    /* Serial Audio Interrupt Clear register */
+#define SADIV  0x60    /* Serial Audio Clock Divider register */
+#define SADR   0x80    /* Serial Audio Data register */
+
+static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+    addr -= s->base;
+
+    switch (addr) {
+    case SACR0:
+        return s->control[0];
+    case SACR1:
+        return s->control[1];
+    case SASR0:
+        return s->status;
+    case SAIMR:
+        return s->mask;
+    case SAICR:
+        return 0;
+    case SADIV:
+        return s->clk;
+    case SADR:
+        if (s->rx_len > 0) {
+            s->rx_len --;
+            pxa2xx_i2s_update(s);
+            return s->codec_in(s->opaque);
+        }
+        return 0;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+    uint32_t *sample;
+    addr -= s->base;
+
+    switch (addr) {
+    case SACR0:
+        if (value & (1 << 3))                          /* RST */
+            pxa2xx_i2s_reset(s);
+        s->control[0] = value & 0xff3d;
+        if (!s->enable && (value & 1) && s->tx_len) {  /* ENB */
+            for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
+                s->codec_out(s->opaque, *sample);
+            s->status &= ~(1 << 7);                    /* I2SOFF */
+        }
+        if (value & (1 << 4))                          /* EFWR */
+            printf("%s: Attempt to use special function\n", __FUNCTION__);
+        s->enable = ((value ^ 4) & 5) == 5;            /* ENB && !RST*/
+        pxa2xx_i2s_update(s);
+        break;
+    case SACR1:
+        s->control[1] = value & 0x0039;
+        if (value & (1 << 5))                          /* ENLBF */
+            printf("%s: Attempt to use loopback function\n", __FUNCTION__);
+        if (value & (1 << 4))                          /* DPRL */
+            s->fifo_len = 0;
+        pxa2xx_i2s_update(s);
+        break;
+    case SAIMR:
+        s->mask = value & 0x0078;
+        pxa2xx_i2s_update(s);
+        break;
+    case SAICR:
+        s->status &= ~(value & (3 << 5));
+        pxa2xx_i2s_update(s);
+        break;
+    case SADIV:
+        s->clk = value & 0x007f;
+        break;
+    case SADR:
+        if (s->tx_len && s->enable) {
+            s->tx_len --;
+            pxa2xx_i2s_update(s);
+            s->codec_out(s->opaque, value);
+        } else if (s->fifo_len < 16) {
+            s->fifo[s->fifo_len ++] = value;
+            pxa2xx_i2s_update(s);
+        }
+        break;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_i2s_readfn[] = {
+    pxa2xx_i2s_read,
+    pxa2xx_i2s_read,
+    pxa2xx_i2s_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_i2s_writefn[] = {
+    pxa2xx_i2s_write,
+    pxa2xx_i2s_write,
+    pxa2xx_i2s_write,
+};
+
+static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+    uint32_t *sample;
+
+    /* Signal FIFO errors */
+    if (s->enable && s->tx_len)
+        s->status |= 1 << 5;           /* TUR */
+    if (s->enable && s->rx_len)
+        s->status |= 1 << 6;           /* ROR */
+
+    /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
+     * handle the cases where it makes a difference.  */
+    s->tx_len = tx - s->fifo_len;
+    s->rx_len = rx;
+    /* Note that is s->codec_out wasn't set, we wouldn't get called.  */
+    if (s->enable)
+        for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
+            s->codec_out(s->opaque, *sample);
+    pxa2xx_i2s_update(s);
+}
+
+static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base,
+                qemu_irq irq, struct pxa2xx_dma_state_s *dma)
+{
+    int iomemtype;
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_i2s_s));
+
+    s->base = base;
+    s->irq = irq;
+    s->dma = dma;
+    s->data_req = pxa2xx_i2s_data_req;
+
+    pxa2xx_i2s_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn,
+                    pxa2xx_i2s_writefn, s);
+    cpu_register_physical_memory(s->base & 0xfff00000, 0xfffff, iomemtype);
+
+    return s;
+}
+
+/* PXA Fast Infra-red Communications Port */
+struct pxa2xx_fir_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    struct pxa2xx_dma_state_s *dma;
+    int enable;
+    CharDriverState *chr;
+
+    uint8_t control[3];
+    uint8_t status[2];
+
+    int rx_len;
+    int rx_start;
+    uint8_t rx_fifo[64];
+};
+
+static void pxa2xx_fir_reset(struct pxa2xx_fir_s *s)
+{
+    s->control[0] = 0x00;
+    s->control[1] = 0x00;
+    s->control[2] = 0x00;
+    s->status[0] = 0x00;
+    s->status[1] = 0x00;
+    s->enable = 0;
+}
+
+static inline void pxa2xx_fir_update(struct pxa2xx_fir_s *s)
+{
+    static const int tresh[4] = { 8, 16, 32, 0 };
+    int intr = 0;
+    if ((s->control[0] & (1 << 4)) &&                  /* RXE */
+                    s->rx_len >= tresh[s->control[2] & 3])     /* TRIG */
+        s->status[0] |= 1 << 4;                                /* RFS */
+    else
+        s->status[0] &= ~(1 << 4);                     /* RFS */
+    if (s->control[0] & (1 << 3))                      /* TXE */
+        s->status[0] |= 1 << 3;                                /* TFS */
+    else
+        s->status[0] &= ~(1 << 3);                     /* TFS */
+    if (s->rx_len)
+        s->status[1] |= 1 << 2;                                /* RNE */
+    else
+        s->status[1] &= ~(1 << 2);                     /* RNE */
+    if (s->control[0] & (1 << 4))                      /* RXE */
+        s->status[1] |= 1 << 0;                                /* RSY */
+    else
+        s->status[1] &= ~(1 << 0);                     /* RSY */
+
+    intr |= (s->control[0] & (1 << 5)) &&              /* RIE */
+            (s->status[0] & (1 << 4));                 /* RFS */
+    intr |= (s->control[0] & (1 << 6)) &&              /* TIE */
+            (s->status[0] & (1 << 3));                 /* TFS */
+    intr |= (s->control[2] & (1 << 4)) &&              /* TRAIL */
+            (s->status[0] & (1 << 6));                 /* EOC */
+    intr |= (s->control[0] & (1 << 2)) &&              /* TUS */
+            (s->status[0] & (1 << 1));                 /* TUR */
+    intr |= s->status[0] & 0x25;                       /* FRE, RAB, EIF */
+
+    pxa2xx_dma_request(s->dma, PXA2XX_RX_RQ_ICP, (s->status[0] >> 4) & 1);
+    pxa2xx_dma_request(s->dma, PXA2XX_TX_RQ_ICP, (s->status[0] >> 3) & 1);
+
+    qemu_set_irq(s->irq, intr && s->enable);
+}
+
+#define ICCR0  0x00    /* FICP Control register 0 */
+#define ICCR1  0x04    /* FICP Control register 1 */
+#define ICCR2  0x08    /* FICP Control register 2 */
+#define ICDR   0x0c    /* FICP Data register */
+#define ICSR0  0x14    /* FICP Status register 0 */
+#define ICSR1  0x18    /* FICP Status register 1 */
+#define ICFOR  0x1c    /* FICP FIFO Occupancy Status register */
+
+static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    uint8_t ret;
+    addr -= s->base;
+
+    switch (addr) {
+    case ICCR0:
+        return s->control[0];
+    case ICCR1:
+        return s->control[1];
+    case ICCR2:
+        return s->control[2];
+    case ICDR:
+        s->status[0] &= ~0x01;
+        s->status[1] &= ~0x72;
+        if (s->rx_len) {
+            s->rx_len --;
+            ret = s->rx_fifo[s->rx_start ++];
+            s->rx_start &= 63;
+            pxa2xx_fir_update(s);
+            return ret;
+        }
+        printf("%s: Rx FIFO underrun.\n", __FUNCTION__);
+        break;
+    case ICSR0:
+        return s->status[0];
+    case ICSR1:
+        return s->status[1] | (1 << 3);                        /* TNF */
+    case ICFOR:
+        return s->rx_len;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    uint8_t ch;
+    addr -= s->base;
+
+    switch (addr) {
+    case ICCR0:
+        s->control[0] = value;
+        if (!(value & (1 << 4)))                       /* RXE */
+            s->rx_len = s->rx_start = 0;
+        if (!(value & (1 << 3)))                       /* TXE */
+            /* Nop */;
+        s->enable = value & 1;                         /* ITR */
+        if (!s->enable)
+            s->status[0] = 0;
+        pxa2xx_fir_update(s);
+        break;
+    case ICCR1:
+        s->control[1] = value;
+        break;
+    case ICCR2:
+        s->control[2] = value & 0x3f;
+        pxa2xx_fir_update(s);
+        break;
+    case ICDR:
+        if (s->control[2] & (1 << 2))                  /* TXP */
+            ch = value;
+        else
+            ch = ~value;
+        if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
+            qemu_chr_write(s->chr, &ch, 1);
+        break;
+    case ICSR0:
+        s->status[0] &= ~(value & 0x66);
+        pxa2xx_fir_update(s);
+        break;
+    case ICFOR:
+        break;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_fir_readfn[] = {
+    pxa2xx_fir_read,
+    pxa2xx_fir_read,
+    pxa2xx_fir_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_fir_writefn[] = {
+    pxa2xx_fir_write,
+    pxa2xx_fir_write,
+    pxa2xx_fir_write,
+};
+
+static int pxa2xx_fir_is_empty(void *opaque)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    return (s->rx_len < 64);
+}
+
+static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    if (!(s->control[0] & (1 << 4)))                   /* RXE */
+        return;
+
+    while (size --) {
+        s->status[1] |= 1 << 4;                                /* EOF */
+        if (s->rx_len >= 64) {
+            s->status[1] |= 1 << 6;                    /* ROR */
+            break;
+        }
+
+        if (s->control[2] & (1 << 3))                  /* RXP */
+            s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
+        else
+            s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
+    }
+
+    pxa2xx_fir_update(s);
+}
+
+static void pxa2xx_fir_event(void *opaque, int event)
+{
+}
+
+static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base,
+                qemu_irq irq, struct pxa2xx_dma_state_s *dma,
+                CharDriverState *chr)
+{
+    int iomemtype;
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_fir_s));
+
+    s->base = base;
+    s->irq = irq;
+    s->dma = dma;
+    s->chr = chr;
+
+    pxa2xx_fir_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_fir_readfn,
+                    pxa2xx_fir_writefn, s);
+    cpu_register_physical_memory(s->base, 0xfff, iomemtype);
+
+    if (chr)
+        qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
+                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
+
+    return s;
+}
+
+void pxa2xx_reset(int line, int level, void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    if (level && (s->pm_regs[PCFR >> 2] & 0x10)) {     /* GPR_EN */
+        cpu_reset(s->env);
+        /* TODO: reset peripherals */
+    }
+}
+
+/* Initialise a PXA270 integrated chip (ARM based core).  */
+struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision)
+{
+    struct pxa2xx_state_s *s;
+    struct pxa2xx_ssp_s *ssp;
+    char *cpu_model;
+    int iomemtype, i;
+    s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
+
+    s->env = cpu_init();
+    asprintf(&cpu_model, "pxa270-%s", revision);
+    cpu_arm_set_model(s->env, cpu_model);
+    free(cpu_model);
+
+    s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+    s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+
+    s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+
+    for (i = 0; pxa270_serial[i].io_base; i ++)
+        if (serial_hds[i])
+            serial_mm_init(pxa270_serial[i].io_base, 2,
+                            s->pic[pxa270_serial[i].irqn], serial_hds[i], 1);
+        else
+            break;
+    if (serial_hds[i])
+        s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
+                        s->dma, serial_hds[i]);
+
+    s->cm_base = 0x41300000;
+    s->cm_regs[CCCR >> 4] = 0x02000210;        /* 416.0 MHz */
+    s->clkcfg = 0x00000009;            /* Turbo mode active */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
+                    pxa2xx_cm_writefn, s);
+    cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype);
+
+    cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+    s->mm_base = 0x48000000;
+    s->mm_regs[MDMRS >> 2] = 0x00020002;
+    s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+    s->mm_regs[MECR >> 2] = 0x00000001;        /* Two PC Card sockets */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
+                    pxa2xx_mm_writefn, s);
+    cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype);
+
+    for (i = 0; pxa27x_ssp[i].io_base; i ++);
+    s->ssp = (struct pxa2xx_ssp_s **)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
+    ssp = (struct pxa2xx_ssp_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
+    for (i = 0; pxa27x_ssp[i].io_base; i ++) {
+        s->ssp[i] = &ssp[i];
+        ssp[i].base = pxa27x_ssp[i].io_base;
+        ssp[i].irq = s->pic[pxa27x_ssp[i].irqn];
+
+        iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
+                        pxa2xx_ssp_writefn, &ssp[i]);
+        cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
+    }
+
+    s->rtc_base = 0x40900000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
+                    pxa2xx_rtc_writefn, s);
+    cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype);
+    pxa2xx_rtc_reset(s);
+
+    s->pm_base = 0x40f00000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
+                    pxa2xx_pm_writefn, s);
+    cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype);
+
+    s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+
+    /* GPIO1 resets the processor */
+    /* The handler can be overriden by board-specific code */
+    pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
+    return s;
+}
+
+/* Initialise a PXA255 integrated chip (ARM based core).  */
+struct pxa2xx_state_s *pxa255_init(DisplayState *ds)
+{
+    struct pxa2xx_state_s *s;
+    struct pxa2xx_ssp_s *ssp;
+    int iomemtype, i;
+    s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
+
+    s->env = cpu_init();
+    cpu_arm_set_model(s->env, "pxa255");
+
+    s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+    s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+
+    s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+
+    for (i = 0; pxa255_serial[i].io_base; i ++)
+        if (serial_hds[i])
+            serial_mm_init(pxa255_serial[i].io_base, 2,
+                            s->pic[pxa255_serial[i].irqn], serial_hds[i], 1);
+        else
+            break;
+    if (serial_hds[i])
+        s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
+                        s->dma, serial_hds[i]);
+
+    s->cm_base = 0x41300000;
+    s->cm_regs[CCCR >> 4] = 0x02000210;        /* 416.0 MHz */
+    s->clkcfg = 0x00000009;            /* Turbo mode active */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
+                    pxa2xx_cm_writefn, s);
+    cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype);
+
+    cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+    s->mm_base = 0x48000000;
+    s->mm_regs[MDMRS >> 2] = 0x00020002;
+    s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+    s->mm_regs[MECR >> 2] = 0x00000001;        /* Two PC Card sockets */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
+                    pxa2xx_mm_writefn, s);
+    cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype);
+
+    for (i = 0; pxa255_ssp[i].io_base; i ++);
+    s->ssp = (struct pxa2xx_ssp_s **)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
+    ssp = (struct pxa2xx_ssp_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
+    for (i = 0; pxa255_ssp[i].io_base; i ++) {
+        s->ssp[i] = &ssp[i];
+        ssp[i].base = pxa255_ssp[i].io_base;
+        ssp[i].irq = s->pic[pxa255_ssp[i].irqn];
+
+        iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
+                        pxa2xx_ssp_writefn, &ssp[i]);
+        cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
+    }
+
+    s->rtc_base = 0x40900000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
+                    pxa2xx_rtc_writefn, s);
+    cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype);
+    pxa2xx_rtc_reset(s);
+
+    s->pm_base = 0x40f00000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
+                    pxa2xx_pm_writefn, s);
+    cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype);
+
+    s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+
+    /* GPIO1 resets the processor */
+    /* The handler can be overriden by board-specific code */
+    pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
+    return s;
+}
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
new file mode 100644 (file)
index 0000000..63d2fb7
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * Intel XScale PXA255/270 DMA controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <[email protected]>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+
+struct pxa2xx_dma_channel_s {
+    target_phys_addr_t descr;
+    target_phys_addr_t src;
+    target_phys_addr_t dest;
+    uint32_t cmd;
+    uint32_t state;
+    int request;
+};
+
+/* Allow the DMA to be used as a PIC.  */
+typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level);
+
+struct pxa2xx_dma_state_s {
+    pxa2xx_dma_handler_t handler;
+    target_phys_addr_t base;
+    qemu_irq irq;
+
+    uint32_t stopintr;
+    uint32_t eorintr;
+    uint32_t rasintr;
+    uint32_t startintr;
+    uint32_t endintr;
+
+    uint32_t align;
+    uint32_t pio;
+
+    int channels;
+    struct pxa2xx_dma_channel_s *chan;
+
+    uint8_t *req;
+
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+};
+
+#define PXA255_DMA_NUM_CHANNELS        16
+#define PXA27X_DMA_NUM_CHANNELS        32
+
+#define PXA2XX_DMA_NUM_REQUESTS        75
+
+#define DCSR0  0x0000  /* DMA Control / Status register for Channel 0 */
+#define DCSR31 0x007c  /* DMA Control / Status register for Channel 31 */
+#define DALGN  0x00a0  /* DMA Alignment register */
+#define DPCSR  0x00a4  /* DMA Programmed I/O Control Status register */
+#define DRQSR0 0x00e0  /* DMA DREQ<0> Status register */
+#define DRQSR1 0x00e4  /* DMA DREQ<1> Status register */
+#define DRQSR2 0x00e8  /* DMA DREQ<2> Status register */
+#define DINT   0x00f0  /* DMA Interrupt register */
+#define DRCMR0 0x0100  /* Request to Channel Map register 0 */
+#define DRCMR63        0x01fc  /* Request to Channel Map register 63 */
+#define D_CH0  0x0200  /* Channel 0 Descriptor start */
+#define DRCMR64        0x1100  /* Request to Channel Map register 64 */
+#define DRCMR74        0x1128  /* Request to Channel Map register 74 */
+
+/* Per-channel register */
+#define DDADR  0x00
+#define DSADR  0x01
+#define DTADR  0x02
+#define DCMD   0x03
+
+/* Bit-field masks */
+#define DRCMR_CHLNUM           0x1f
+#define DRCMR_MAPVLD           (1 << 7)
+#define DDADR_STOP             (1 << 0)
+#define DDADR_BREN             (1 << 1)
+#define DCMD_LEN               0x1fff
+#define DCMD_WIDTH(x)          (1 << ((((x) >> 14) & 3) - 1))
+#define DCMD_SIZE(x)           (4 << (((x) >> 16) & 3))
+#define DCMD_FLYBYT            (1 << 19)
+#define DCMD_FLYBYS            (1 << 20)
+#define DCMD_ENDIRQEN          (1 << 21)
+#define DCMD_STARTIRQEN                (1 << 22)
+#define DCMD_CMPEN             (1 << 25)
+#define DCMD_FLOWTRG           (1 << 28)
+#define DCMD_FLOWSRC           (1 << 29)
+#define DCMD_INCTRGADDR                (1 << 30)
+#define DCMD_INCSRCADDR                (1 << 31)
+#define DCSR_BUSERRINTR                (1 << 0)
+#define DCSR_STARTINTR         (1 << 1)
+#define DCSR_ENDINTR           (1 << 2)
+#define DCSR_STOPINTR          (1 << 3)
+#define DCSR_RASINTR           (1 << 4)
+#define DCSR_REQPEND           (1 << 8)
+#define DCSR_EORINT            (1 << 9)
+#define DCSR_CMPST             (1 << 10)
+#define DCSR_MASKRUN           (1 << 22)
+#define DCSR_RASIRQEN          (1 << 23)
+#define DCSR_CLRCMPST          (1 << 24)
+#define DCSR_SETCMPST          (1 << 25)
+#define DCSR_EORSTOPEN         (1 << 26)
+#define DCSR_EORJMPEN          (1 << 27)
+#define DCSR_EORIRQEN          (1 << 28)
+#define DCSR_STOPIRQEN         (1 << 29)
+#define DCSR_NODESCFETCH       (1 << 30)
+#define DCSR_RUN               (1 << 31)
+
+static inline void pxa2xx_dma_update(struct pxa2xx_dma_state_s *s, int ch)
+{
+    if (ch >= 0) {
+        if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
+                (s->chan[ch].state & DCSR_STOPINTR))
+            s->stopintr |= 1 << ch;
+        else
+            s->stopintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_EORIRQEN) &&
+                (s->chan[ch].state & DCSR_EORINT))
+            s->eorintr |= 1 << ch;
+        else
+            s->eorintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_RASIRQEN) &&
+                (s->chan[ch].state & DCSR_RASINTR))
+            s->rasintr |= 1 << ch;
+        else
+            s->rasintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_STARTINTR)
+            s->startintr |= 1 << ch;
+        else
+            s->startintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_ENDINTR)
+            s->endintr |= 1 << ch;
+        else
+            s->endintr &= ~(1 << ch);
+    }
+
+    if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static inline void pxa2xx_dma_descriptor_fetch(
+                struct pxa2xx_dma_state_s *s, int ch)
+{
+    uint32_t desc[4];
+    target_phys_addr_t daddr = s->chan[ch].descr & ~0xf;
+    if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
+        daddr += 32;
+
+    cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
+    s->chan[ch].descr = desc[DDADR];
+    s->chan[ch].src = desc[DSADR];
+    s->chan[ch].dest = desc[DTADR];
+    s->chan[ch].cmd = desc[DCMD];
+
+    if (s->chan[ch].cmd & DCMD_FLOWSRC)
+        s->chan[ch].src &= ~3;
+    if (s->chan[ch].cmd & DCMD_FLOWTRG)
+        s->chan[ch].dest &= ~3;
+
+    if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
+        printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
+
+    if (s->chan[ch].cmd & DCMD_STARTIRQEN)
+        s->chan[ch].state |= DCSR_STARTINTR;
+}
+
+static void pxa2xx_dma_run(struct pxa2xx_dma_state_s *s)
+{
+    int c, srcinc, destinc;
+    uint32_t n, size;
+    uint32_t width;
+    uint32_t length;
+    char buffer[32];
+    struct pxa2xx_dma_channel_s *ch;
+
+    if (s->running ++)
+        return;
+
+    while (s->running) {
+        s->running = 1;
+        for (c = 0; c < s->channels; c ++) {
+            ch = &s->chan[c];
+
+            while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
+                /* Test for pending requests */
+                if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
+                    break;
+
+                length = ch->cmd & DCMD_LEN;
+                size = DCMD_SIZE(ch->cmd);
+                width = DCMD_WIDTH(ch->cmd);
+
+                srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
+                destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
+
+                while (length) {
+                    size = MIN(length, size);
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_read(ch->src, buffer + n, width);
+                        ch->src += srcinc;
+                    }
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_write(ch->dest, buffer + n, width);
+                        ch->dest += destinc;
+                    }
+
+                    length -= size;
+
+                    if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
+                            !ch->request) {
+                        ch->state |= DCSR_EORINT;
+                        if (ch->state & DCSR_EORSTOPEN)
+                            ch->state |= DCSR_STOPINTR;
+                        if ((ch->state & DCSR_EORJMPEN) &&
+                                        !(ch->state & DCSR_NODESCFETCH))
+                            pxa2xx_dma_descriptor_fetch(s, c);
+                        break;
+                   }
+                }
+
+                ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
+
+                /* Is the transfer complete now? */
+                if (!length) {
+                    if (ch->cmd & DCMD_ENDIRQEN)
+                        ch->state |= DCSR_ENDINTR;
+
+                    if ((ch->state & DCSR_NODESCFETCH) ||
+                                (ch->descr & DDADR_STOP) ||
+                                (ch->state & DCSR_EORSTOPEN)) {
+                        ch->state |= DCSR_STOPINTR;
+                        ch->state &= ~DCSR_RUN;
+
+                        break;
+                    }
+
+                    ch->state |= DCSR_STOPINTR;
+                    break;
+                }
+            }
+        }
+
+        s->running --;
+    }
+}
+
+static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
+    unsigned int channel;
+    offset -= s->base;
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+        return s->req[channel];
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        return 0;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+       if (s->chan[channel].request)
+            return s->chan[channel].state | DCSR_REQPEND;
+        return s->chan[channel].state;
+
+    case DINT:
+        return s->stopintr | s->eorintr | s->rasintr |
+                s->startintr | s->endintr;
+
+    case DALGN:
+        return s->align;
+
+    case DPCSR:
+        return s->pio;
+    }
+
+    if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+        channel = (offset - D_CH0) >> 4;
+        switch ((offset & 0x0f) >> 2) {
+        case DDADR:
+            return s->chan[channel].descr;
+        case DSADR:
+            return s->chan[channel].src;
+        case DTADR:
+            return s->chan[channel].dest;
+        case DCMD:
+            return s->chan[channel].cmd;
+        }
+    }
+
+    cpu_abort(cpu_single_env,
+                    "%s: Bad offset 0x%04lx\n", __FUNCTION__, offset);
+    return 7;
+}
+
+static void pxa2xx_dma_write(void *opaque,
+                 target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
+    unsigned int channel;
+    offset -= s->base;
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+
+        if (value & DRCMR_MAPVLD)
+            if ((value & DRCMR_CHLNUM) > s->channels)
+                cpu_abort(cpu_single_env, "%s: Bad DMA channel %i\n",
+                        __FUNCTION__, value & DRCMR_CHLNUM);
+
+        s->req[channel] = value;
+        break;
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        /* Nothing to do */
+        break;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+        s->chan[channel].state &= 0x0000071f & ~(value &
+                        (DCSR_EORINT | DCSR_ENDINTR |
+                         DCSR_STARTINTR | DCSR_BUSERRINTR));
+        s->chan[channel].state |= value & 0xfc800000;
+
+        if (s->chan[channel].state & DCSR_STOPIRQEN)
+            s->chan[channel].state &= ~DCSR_STOPINTR;
+
+        if (value & DCSR_NODESCFETCH) {
+            /* No-descriptor-fetch mode */
+            if (value & DCSR_RUN)
+                pxa2xx_dma_run(s);
+        } else {
+            /* Descriptor-fetch mode */
+            if (value & DCSR_RUN) {
+                s->chan[channel].state &= ~DCSR_STOPINTR;
+                pxa2xx_dma_descriptor_fetch(s, channel);
+                pxa2xx_dma_run(s);
+            }
+        }
+
+        /* Shouldn't matter as our DMA is synchronous.  */
+        if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
+            s->chan[channel].state |= DCSR_STOPINTR;
+
+        if (value & DCSR_CLRCMPST)
+            s->chan[channel].state &= ~DCSR_CMPST;
+        if (value & DCSR_SETCMPST)
+            s->chan[channel].state |= DCSR_CMPST;
+
+        pxa2xx_dma_update(s, channel);
+        break;
+
+    case DALGN:
+        s->align = value;
+        break;
+
+    case DPCSR:
+        s->pio = value & 0x80000001;
+        break;
+
+    default:
+        if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+            channel = (offset - D_CH0) >> 4;
+            switch ((offset & 0x0f) >> 2) {
+            case DDADR:
+                s->chan[channel].descr = value;
+                break;
+            case DSADR:
+                s->chan[channel].src = value;
+                break;
+            case DTADR:
+                s->chan[channel].dest = value;
+                break;
+            case DCMD:
+                s->chan[channel].cmd = value;
+                break;
+            default:
+                goto fail;
+            }
+
+            break;
+        }
+    fail:
+        cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n",
+                __FUNCTION__, offset);
+    }
+}
+
+static uint32_t pxa2xx_dma_readbad(void *opaque, target_phys_addr_t offset)
+{
+    cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
+    return 5;
+}
+
+static void pxa2xx_dma_writebad(void *opaque,
+                 target_phys_addr_t offset, uint32_t value)
+{
+    cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
+}
+
+static CPUReadMemoryFunc *pxa2xx_dma_readfn[] = {
+    pxa2xx_dma_readbad,
+    pxa2xx_dma_readbad,
+    pxa2xx_dma_read
+};
+
+static CPUWriteMemoryFunc *pxa2xx_dma_writefn[] = {
+    pxa2xx_dma_writebad,
+    pxa2xx_dma_writebad,
+    pxa2xx_dma_write
+};
+
+static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base,
+                qemu_irq irq, int channels)
+{
+    int i, iomemtype;
+    struct pxa2xx_dma_state_s *s;
+    s = (struct pxa2xx_dma_state_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_dma_state_s));
+
+    s->channels = channels;
+    s->chan = qemu_mallocz(sizeof(struct pxa2xx_dma_channel_s) * s->channels);
+    s->base = base;
+    s->irq = irq;
+    s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request;
+    s->req = qemu_mallocz(sizeof(int) * PXA2XX_DMA_NUM_REQUESTS);
+
+    memset(s->chan, 0, sizeof(struct pxa2xx_dma_channel_s) * s->channels);
+    for (i = 0; i < s->channels; i ++)
+        s->chan[i].state = DCSR_STOPINTR;
+
+    memset(s->req, 0, sizeof(int) * PXA2XX_DMA_NUM_REQUESTS);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn,
+                   pxa2xx_dma_writefn, s);
+    cpu_register_physical_memory(base, 0x0000ffff, iomemtype);
+
+    return s;
+}
+
+struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
+                qemu_irq irq)
+{
+    return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS);
+}
+
+struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
+                qemu_irq irq)
+{
+    return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS);
+}
+
+void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on)
+{
+    int ch;
+    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
+        cpu_abort(cpu_single_env,
+              "%s: Bad DMA request %i\n", __FUNCTION__, req_num);
+
+    if (!(s->req[req_num] & DRCMR_MAPVLD))
+        return;
+    ch = s->req[req_num] & DRCMR_CHLNUM;
+
+    if (!s->chan[ch].request && on)
+        s->chan[ch].state |= DCSR_RASINTR;
+    else
+        s->chan[ch].state &= ~DCSR_RASINTR;
+    if (s->chan[ch].request && !on)
+        s->chan[ch].state |= DCSR_EORINT;
+
+    s->chan[ch].request = on;
+    if (on) {
+        pxa2xx_dma_run(s);
+        pxa2xx_dma_update(s, ch);
+    }
+}
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
new file mode 100644 (file)
index 0000000..eab2e72
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Intel XScale PXA255/270 GPIO controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <[email protected]>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "vl.h"
+
+#define PXA2XX_GPIO_BANKS      4
+
+struct pxa2xx_gpio_info_s {
+    target_phys_addr_t base;
+    qemu_irq *pic;
+    int lines;
+    CPUState *cpu_env;
+
+    /* XXX: GNU C vectors are more suitable */
+    uint32_t ilevel[PXA2XX_GPIO_BANKS];
+    uint32_t olevel[PXA2XX_GPIO_BANKS];
+    uint32_t dir[PXA2XX_GPIO_BANKS];
+    uint32_t rising[PXA2XX_GPIO_BANKS];
+    uint32_t falling[PXA2XX_GPIO_BANKS];
+    uint32_t status[PXA2XX_GPIO_BANKS];
+    uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
+
+    uint32_t prev_level[PXA2XX_GPIO_BANKS];
+    struct {
+        gpio_handler_t fn;
+        void *opaque;
+    } handler[PXA2XX_GPIO_BANKS * 32];
+
+    void (*read_notify)(void *opaque);
+    void *opaque;
+};
+
+static struct {
+    enum {
+        GPIO_NONE,
+        GPLR,
+        GPSR,
+        GPCR,
+        GPDR,
+        GRER,
+        GFER,
+        GEDR,
+        GAFR_L,
+        GAFR_U,
+    } reg;
+    int bank;
+} pxa2xx_gpio_regs[0x200] = {
+    [0 ... 0x1ff] = { GPIO_NONE, 0 },
+#define PXA2XX_REG(reg, a0, a1, a2, a3)        \
+    [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, 
+
+    PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
+    PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
+    PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
+    PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
+    PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
+    PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
+    PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
+    PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
+    PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
+};
+
+static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s)
+{
+    if (s->status[0] & (1 << 0))
+        qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]);
+    else
+        qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]);
+
+    if (s->status[0] & (1 << 1))
+        qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]);
+    else
+        qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]);
+
+    if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
+        qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]);
+    else
+        qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]);
+}
+
+/* Bitmap of pins used as standby and sleep wake-up sources.  */
+const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
+    0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
+};
+
+void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level)
+{
+    int bank;
+    uint32_t mask;
+
+    if (line >= s->lines) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    bank = line >> 5;
+    mask = 1 << (line & 31);
+
+    if (level) {
+        s->status[bank] |= s->rising[bank] & mask &
+                ~s->ilevel[bank] & ~s->dir[bank];
+        s->ilevel[bank] |= mask;
+    } else {
+        s->status[bank] |= s->falling[bank] & mask &
+                s->ilevel[bank] & ~s->dir[bank];
+        s->ilevel[bank] &= ~mask;
+    }
+
+    if (s->status[bank] & mask)
+        pxa2xx_gpio_irq_update(s);
+
+    /* Wake-up GPIOs */
+    if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
+}
+
+static void pxa2xx_gpio_handler_update(struct pxa2xx_gpio_info_s *s) {
+    uint32_t level, diff;
+    int i, bit, line;
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        level = s->olevel[i] & s->dir[i];
+
+        for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
+            bit = ffs(diff) - 1;
+            line = bit + 32 * i;
+            if (s->handler[line].fn)
+                s->handler[line].fn(line, (level >> bit) & 1,
+                                s->handler[line].opaque);
+        }
+
+        s->prev_level[i] = level;
+    }
+}
+
+static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    uint32_t ret;
+    int bank;
+    offset -= s->base;
+    if (offset >= 0x200)
+        return 0;
+
+    bank = pxa2xx_gpio_regs[offset].bank;
+    switch (pxa2xx_gpio_regs[offset].reg) {
+    case GPDR:         /* GPIO Pin-Direction registers */
+        return s->dir[bank];
+
+    case GRER:         /* GPIO Rising-Edge Detect Enable registers */
+        return s->rising[bank];
+
+    case GFER:         /* GPIO Falling-Edge Detect Enable registers */
+        return s->falling[bank];
+
+    case GAFR_L:       /* GPIO Alternate Function registers */
+        return s->gafr[bank * 2];
+
+    case GAFR_U:       /* GPIO Alternate Function registers */
+        return s->gafr[bank * 2 + 1];
+
+    case GPLR:         /* GPIO Pin-Level registers */
+        ret = (s->olevel[bank] & s->dir[bank]) |
+                (s->ilevel[bank] & ~s->dir[bank]);
+        if (s->read_notify)
+            s->read_notify(s->opaque);
+        return ret;
+
+    case GEDR:         /* GPIO Edge Detect Status registers */
+        return s->status[bank];
+
+    default:
+        cpu_abort(cpu_single_env,
+                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_gpio_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    int bank;
+    offset -= s->base;
+    if (offset >= 0x200)
+        return;
+
+    bank = pxa2xx_gpio_regs[offset].bank;
+    switch (pxa2xx_gpio_regs[offset].reg) {
+    case GPDR:         /* GPIO Pin-Direction registers */
+        s->dir[bank] = value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GPSR:         /* GPIO Pin-Output Set registers */
+        s->olevel[bank] |= value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GPCR:         /* GPIO Pin-Output Clear registers */
+        s->olevel[bank] &= ~value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GRER:         /* GPIO Rising-Edge Detect Enable registers */
+        s->rising[bank] = value;
+        break;
+
+    case GFER:         /* GPIO Falling-Edge Detect Enable registers */
+        s->falling[bank] = value;
+        break;
+
+    case GAFR_L:       /* GPIO Alternate Function registers */
+        s->gafr[bank * 2] = value;
+        break;
+
+    case GAFR_U:       /* GPIO Alternate Function registers */
+        s->gafr[bank * 2 + 1] = value;
+        break;
+
+    case GEDR:         /* GPIO Edge Detect Status registers */
+        s->status[bank] &= ~value;
+        pxa2xx_gpio_irq_update(s);
+        break;
+
+    default:
+        cpu_abort(cpu_single_env,
+                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_gpio_readfn[] = {
+    pxa2xx_gpio_read,
+    pxa2xx_gpio_read,
+    pxa2xx_gpio_read
+};
+
+static CPUWriteMemoryFunc *pxa2xx_gpio_writefn[] = {
+    pxa2xx_gpio_write,
+    pxa2xx_gpio_write,
+    pxa2xx_gpio_write
+};
+
+struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
+                CPUState *env, qemu_irq *pic, int lines)
+{
+    int iomemtype;
+    struct pxa2xx_gpio_info_s *s;
+
+    s = (struct pxa2xx_gpio_info_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_gpio_info_s));
+    memset(s, 0, sizeof(struct pxa2xx_gpio_info_s));
+    s->base = base;
+    s->pic = pic;
+    s->lines = lines;
+    s->cpu_env = env;
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn,
+                    pxa2xx_gpio_writefn, s);
+    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+
+    return s;
+}
+
+void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
+                gpio_handler_t handler, void *opaque) {
+    if (line >= s->lines) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    s->handler[line].fn = handler;
+    s->handler[line].opaque = opaque;
+}
+
+/*
+ * Registers a callback to notify on GPLR reads.  This normally
+ * shouldn't be needed but it is used for the hack on Spitz machines.
+ */
+void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s,
+                void (*handler)(void *opaque), void *opaque) {
+    s->read_notify = handler;
+    s->opaque = opaque;
+}
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
new file mode 100644 (file)
index 0000000..e3cf241
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Intel XScale PXA Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <[email protected]>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.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 */
+#define ICHP   0x18    /* Interrupt Controller Highest Priority register */
+#define IPR0   0x1c    /* Interrupt Controller Priority register 0 */
+#define IPR31  0x98    /* Interrupt Controller Priority register 31 */
+#define ICIP2  0x9c    /* Interrupt Controller IRQ Pending register 2 */
+#define ICMR2  0xa0    /* Interrupt Controller Mask register 2 */
+#define ICLR2  0xa4    /* Interrupt Controller Level register 2 */
+#define ICFP2  0xa8    /* Interrupt Controller FIQ Pending register 2 */
+#define ICPR2  0xac    /* Interrupt Controller Pending register 2 */
+#define IPR32  0xb0    /* Interrupt Controller Priority register 32 */
+#define IPR39  0xcc    /* Interrupt Controller Priority register 39 */
+
+#define PXA2XX_PIC_SRCS        40
+
+struct pxa2xx_pic_state_s {
+    target_phys_addr_t base;
+    CPUState *cpu_env;
+    uint32_t int_enabled[2];
+    uint32_t int_pending[2];
+    uint32_t is_fiq[2];
+    uint32_t int_idle;
+    uint32_t priority[PXA2XX_PIC_SRCS];
+};
+
+static void pxa2xx_pic_update(void *opaque)
+{
+    uint32_t mask[2];
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+
+    if (s->cpu_env->halted) {
+        mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
+        mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
+        if (mask[0] || mask[1])
+            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
+    }
+
+    mask[0] = s->int_pending[0] & s->int_enabled[0];
+    mask[1] = s->int_pending[1] & s->int_enabled[1];
+
+    if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+    else
+        cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+
+    if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+    else
+        cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+}
+
+/* Note: Here level means state of the signal on a pin, not
+ * IRQ/FIQ distinction as in PXA Developer Manual.  */
+static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    int int_set = (irq >= 32);
+    irq &= 31;
+
+    if (level)
+        s->int_pending[int_set] |= 1 << irq;
+    else
+        s->int_pending[int_set] &= ~(1 << irq);
+
+    pxa2xx_pic_update(opaque);
+}
+
+static inline uint32_t pxa2xx_pic_highest(struct pxa2xx_pic_state_s *s) {
+    int i, int_set, irq;
+    uint32_t bit, mask[2];
+    uint32_t ichp = 0x003f003f;        /* Both IDs invalid */
+
+    mask[0] = s->int_pending[0] & s->int_enabled[0];
+    mask[1] = s->int_pending[1] & s->int_enabled[1];
+
+    for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
+        irq = s->priority[i] & 0x3f;
+        if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
+            /* Source peripheral ID is valid.  */
+            bit = 1 << (irq & 31);
+            int_set = (irq >= 32);
+
+            if (mask[int_set] & bit & s->is_fiq[int_set]) {
+                /* FIQ asserted */
+                ichp &= 0xffff0000;
+                ichp |= (1 << 15) | irq;
+            }
+
+            if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
+                /* IRQ asserted */
+                ichp &= 0x0000ffff;
+                ichp |= (1 << 31) | (irq << 16);
+            }
+        }
+    }
+
+    return ichp;
+}
+
+static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case ICIP: /* IRQ Pending register */
+        return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
+    case ICIP2:        /* IRQ Pending register 2 */
+        return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
+    case ICMR: /* Mask register */
+        return s->int_enabled[0];
+    case ICMR2:        /* Mask register 2 */
+        return s->int_enabled[1];
+    case ICLR: /* Level register */
+        return s->is_fiq[0];
+    case ICLR2:        /* Level register 2 */
+        return s->is_fiq[1];
+    case ICCR: /* Idle mask */
+        return (s->int_idle == 0);
+    case ICFP: /* FIQ Pending register */
+        return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
+    case ICFP2:        /* FIQ Pending register 2 */
+        return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
+    case ICPR: /* Pending register */
+        return s->int_pending[0];
+    case ICPR2:        /* Pending register 2 */
+        return s->int_pending[1];
+    case IPR0  ... IPR31:
+        return s->priority[0  + ((offset - IPR0 ) >> 2)];
+    case IPR32 ... IPR39:
+        return s->priority[32 + ((offset - IPR32) >> 2)];
+    case ICHP: /* Highest Priority register */
+        return pxa2xx_pic_highest(s);
+    default:
+        printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
+        return 0;
+    }
+}
+
+static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case ICMR: /* Mask register */
+        s->int_enabled[0] = value;
+        break;
+    case ICMR2:        /* Mask register 2 */
+        s->int_enabled[1] = value;
+        break;
+    case ICLR: /* Level register */
+        s->is_fiq[0] = value;
+        break;
+    case ICLR2:        /* Level register 2 */
+        s->is_fiq[1] = value;
+        break;
+    case ICCR: /* Idle mask */
+        s->int_idle = (value & 1) ? 0 : ~0;
+        break;
+    case IPR0  ... IPR31:
+        s->priority[0  + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
+        break;
+    case IPR32 ... IPR39:
+        s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
+        break;
+    default:
+        printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
+        return;
+    }
+    pxa2xx_pic_update(opaque);
+}
+
+/* Interrupt Controller Coprocessor Space Register Mapping */
+static const int pxa2xx_cp_reg_map[0x10] = {
+    [0x0 ... 0xf] = -1,
+    [0x0] = ICIP,
+    [0x1] = ICMR,
+    [0x2] = ICLR,
+    [0x3] = ICFP,
+    [0x4] = ICPR,
+    [0x5] = ICHP,
+    [0x6] = ICIP2,
+    [0x7] = ICMR2,
+    [0x8] = ICLR2,
+    [0x9] = ICFP2,
+    [0xa] = ICPR2,
+};
+
+static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    target_phys_addr_t offset;
+
+    if (pxa2xx_cp_reg_map[reg] == -1) {
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        return 0;
+    }
+
+    offset = s->base + pxa2xx_cp_reg_map[reg];
+    return pxa2xx_pic_mem_read(opaque, offset);
+}
+
+static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    target_phys_addr_t offset;
+
+    if (pxa2xx_cp_reg_map[reg] == -1) {
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        return;
+    }
+
+    offset = s->base + pxa2xx_cp_reg_map[reg];
+    pxa2xx_pic_mem_write(opaque, offset, value);
+}
+
+static CPUReadMemoryFunc *pxa2xx_pic_readfn[] = {
+    pxa2xx_pic_mem_read,
+    pxa2xx_pic_mem_read,
+    pxa2xx_pic_mem_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = {
+    pxa2xx_pic_mem_write,
+    pxa2xx_pic_mem_write,
+    pxa2xx_pic_mem_write,
+};
+
+qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
+{
+    struct pxa2xx_pic_state_s *s;
+    int iomemtype;
+    qemu_irq *qi;
+
+    s = (struct pxa2xx_pic_state_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_pic_state_s));
+    if (!s)
+        return NULL;
+
+    s->cpu_env = env;
+    s->base = base;
+
+    s->int_pending[0] = 0;
+    s->int_pending[1] = 0;
+    s->int_enabled[0] = 0;
+    s->int_enabled[1] = 0;
+    s->is_fiq[0] = 0;
+    s->is_fiq[1] = 0;
+
+    qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS);
+
+    /* Enable IC memory-mapped registers access.  */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn,
+                    pxa2xx_pic_writefn, s);
+    cpu_register_physical_memory(base, 0x000fffff, iomemtype);
+
+    /* Enable IC coprocessor access.  */
+    cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
+
+    return qi;
+}
index 68bf3fd0f4bf5abaded1f34c3d1b879b4ce47cd7..6e2ae905feaf07c38dd65c8336accf9a0ee37039 100644 (file)
 #define EXCP_FIQ             6
 #define EXCP_BKPT            7
 
+typedef void ARMWriteCPFunc(void *opaque, int cp_info,
+                            int srcreg, int operand, uint32_t value);
+typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
+                               int dstreg, int operand);
+
 /* We currently assume float and double are IEEE single and double
    precision respectively.
    Doing runtime conversions is tricky because VFP registers may contain
@@ -75,6 +80,7 @@ typedef struct CPUARMState {
     /* System control coprocessor (cp15) */
     struct {
         uint32_t c0_cpuid;
+        uint32_t c0_cachetype;
         uint32_t c1_sys; /* System control register.  */
         uint32_t c1_coproc; /* Coprocessor access register.  */
         uint32_t c2; /* MMU translation table base.  */
@@ -87,8 +93,16 @@ typedef struct CPUARMState {
         uint32_t c9_data;
         uint32_t c13_fcse; /* FCSE PID.  */
         uint32_t c13_context; /* Context ID.  */
+        uint32_t c15_cpar; /* XScale Coprocessor Access Register */
     } cp15;
 
+    /* Coprocessor IO used by peripherals */
+    struct {
+        ARMReadCPFunc *cp_read;
+        ARMWriteCPFunc *cp_write;
+        void *opaque;
+    } cp[15];
+
     /* Internal CPU feature flags.  */
     uint32_t features;
 
@@ -204,10 +218,10 @@ enum arm_cpu_mode {
 #define ARM_VFP_FPINST  9
 #define ARM_VFP_FPINST2 10
 
-
 enum arm_features {
     ARM_FEATURE_VFP,
-    ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register.  */
+    ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
+    ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -218,8 +232,24 @@ static inline int arm_feature(CPUARMState *env, int feature)
 void arm_cpu_list(void);
 void cpu_arm_set_model(CPUARMState *env, const char *name);
 
-#define ARM_CPUID_ARM1026 0x4106a262
-#define ARM_CPUID_ARM926  0x41069265
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+                       ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+                       void *opaque);
+
+#define ARM_CPUID_ARM1026   0x4106a262
+#define ARM_CPUID_ARM926    0x41069265
+#define ARM_CPUID_PXA250    0x69052100
+#define ARM_CPUID_PXA255    0x69052d00
+#define ARM_CPUID_PXA260    0x69052903
+#define ARM_CPUID_PXA261    0x69052d05
+#define ARM_CPUID_PXA262    0x69052d06
+#define ARM_CPUID_PXA270    0x69054110
+#define ARM_CPUID_PXA270_A0 0x69054110
+#define ARM_CPUID_PXA270_A1 0x69054111
+#define ARM_CPUID_PXA270_B0 0x69054112
+#define ARM_CPUID_PXA270_B1 0x69054113
+#define ARM_CPUID_PXA270_C0 0x69054114
+#define ARM_CPUID_PXA270_C5 0x69054117
 
 #if defined(CONFIG_USER_ONLY)
 #define TARGET_PAGE_BITS 12
index e73e12dc5c7a1e1518ebba01085207e019ae6226..87c41b218e89d73499b595d77e32a811d03cf261 100644 (file)
@@ -54,6 +54,8 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 
 void cpu_lock(void);
 void cpu_unlock(void);
+void helper_set_cp(CPUState *, uint32_t, uint32_t);
+uint32_t helper_get_cp(CPUState *, uint32_t);
 void helper_set_cp15(CPUState *, uint32_t, uint32_t);
 uint32_t helper_get_cp15(CPUState *, uint32_t);
 
index bae4c9fdb783902d51a3f80d6839adc6addf77ec..798df304e17cdb0b79ed849f1b68811bc901f462 100644 (file)
@@ -17,11 +17,32 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_ARM926:
         set_feature(env, ARM_FEATURE_VFP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
+        env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_ARM1026:
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        break;
+    case ARM_CPUID_PXA250:
+    case ARM_CPUID_PXA255:
+    case ARM_CPUID_PXA260:
+    case ARM_CPUID_PXA261:
+    case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_XSCALE);
+        /* JTAG_ID is ((id << 28) | 0x09265013) */
+        env->cp15.c0_cachetype = 0xd172172;
+        break;
+    case ARM_CPUID_PXA270_A0:
+    case ARM_CPUID_PXA270_A1:
+    case ARM_CPUID_PXA270_B0:
+    case ARM_CPUID_PXA270_B1:
+    case ARM_CPUID_PXA270_C0:
+    case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_XSCALE);
+        /* JTAG_ID is ((id << 28) | 0x09265013) */
+        env->cp15.c0_cachetype = 0xd172172;
         break;
     default:
         cpu_abort(env, "Bad CPU ID: %x\n", id);
@@ -68,6 +89,18 @@ struct arm_cpu_t {
 static const struct arm_cpu_t arm_cpu_names[] = {
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM1026, "arm1026"},
+    { ARM_CPUID_PXA250, "pxa250" },
+    { ARM_CPUID_PXA255, "pxa255" },
+    { ARM_CPUID_PXA260, "pxa260" },
+    { ARM_CPUID_PXA261, "pxa261" },
+    { ARM_CPUID_PXA262, "pxa262" },
+    { ARM_CPUID_PXA270, "pxa270" },
+    { ARM_CPUID_PXA270_A0, "pxa270-a0" },
+    { ARM_CPUID_PXA270_A1, "pxa270-a1" },
+    { ARM_CPUID_PXA270_B0, "pxa270-b0" },
+    { ARM_CPUID_PXA270_B1, "pxa270-b1" },
+    { ARM_CPUID_PXA270_C0, "pxa270-c0" },
+    { ARM_CPUID_PXA270_C5, "pxa270-c5" },
     { 0, NULL}
 };
 
@@ -132,6 +165,20 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 }
 
 /* These should probably raise undefined insn exceptions.  */
+void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return;
+}
+
+uint32_t helper_get_cp(CPUState *env, uint32_t insn)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return 0;
+}
+
 void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
 {
     cpu_abort(env, "cp15 insn %08x\n", insn);
@@ -393,12 +440,16 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
                 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
                 break;
             case 3: /* 1k page.  */
-                if (type == 1) {
-                    /* Page translation fault.  */
-                    code = 7;
-                    goto do_fault;
+                if (arm_feature(env, ARM_FEATURE_XSCALE))
+                    phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+                else {
+                    if (type == 1) {
+                        /* Page translation fault.  */
+                        code = 7;
+                        goto do_fault;
+                    }
+                    phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
                 }
-                phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
                 ap = (desc >> 4) & 3;
                 break;
             default:
@@ -461,6 +512,31 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     return phys_addr;
 }
 
+void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int cp_num = (insn >> 8) & 0xf;
+    int cp_info = (insn >> 5) & 7;
+    int src = (insn >> 16) & 0xf;
+    int operand = insn & 0xf;
+
+    if (env->cp[cp_num].cp_write)
+        env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
+                                 cp_info, src, operand, val);
+}
+
+uint32_t helper_get_cp(CPUState *env, uint32_t insn)
+{
+    int cp_num = (insn >> 8) & 0xf;
+    int cp_info = (insn >> 5) & 7;
+    int dest = (insn >> 16) & 0xf;
+    int operand = insn & 0xf;
+
+    if (env->cp[cp_num].cp_read)
+        return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
+                                       cp_info, dest, operand);
+    return 0;
+}
+
 void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
 {
     uint32_t op2;
@@ -472,15 +548,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
     case 1: /* System configuration.  */
         switch (op2) {
         case 0:
-            env->cp15.c1_sys = val;
+            if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0)
+                env->cp15.c1_sys = val;
             /* ??? Lots of these bits are not implemented.  */
             /* This may enable/disable the MMU, so do a TLB flush.  */
             tlb_flush(env, 1);
             break;
+        case 1:
+            /* XScale doesn't implement AUX CR (P-Bit) but allows
+             * writing with zero and reading.  */
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                break;
+            goto bad_reg;
         case 2:
             env->cp15.c1_coproc = val;
             /* ??? Is this safe when called from within a TB?  */
             tb_flush(env);
+            break;
         default:
             goto bad_reg;
         }
@@ -584,13 +668,21 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
     case 14: /* Reserved.  */
         goto bad_reg;
     case 15: /* Implementation specific.  */
-        /* ??? Internal registers not implemented.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+            if (op2 == 0 && (insn & 0xf) == 1) {
+                /* Changes cp0 to cp13 behavior, so needs a TB flush.  */
+                tb_flush(env);
+                env->cp15.c15_cpar = (val & 0x3fff) | 2;
+                break;
+            }
+            goto bad_reg;
+        }
         break;
     }
     return;
 bad_reg:
     /* ??? For debugging only.  Should raise illegal instruction exception.  */
-    cpu_abort(env, "Unimplemented cp15 register read\n");
+    cpu_abort(env, "Unimplemented cp15 register write\n");
 }
 
 uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
@@ -604,7 +696,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
         default: /* Device ID.  */
             return env->cp15.c0_cpuid;
         case 1: /* Cache Type.  */
-            return 0x1dd20d2;
+            return env->cp15.c0_cachetype;
         case 2: /* TCM status.  */
             return 0;
         }
@@ -615,6 +707,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
         case 1: /* Auxiliary control register.  */
             if (arm_feature(env, ARM_FEATURE_AUXCR))
                 return 1;
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                return 0;
             goto bad_reg;
         case 2: /* Coprocessor access register.  */
             return env->cp15.c1_coproc;
@@ -649,7 +743,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
         }
     case 7: /* Cache control.  */
         /* ??? This is for test, clean and invaidate operations that set the
-           Z flag.  We can't represent N = Z = 1, so it also clears clears
+           Z flag.  We can't represent N = Z = 1, so it also clears
            the N flag.  Oh well.  */
         env->NZF = 0;
         return 0;
@@ -682,7 +776,12 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
     case 14: /* Reserved.  */
         goto bad_reg;
     case 15: /* Implementation specific.  */
-        /* ??? Internal registers not implemented.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+            if (op2 == 0 && (insn & 0xf) == 1)
+                return env->cp15.c15_cpar;
+
+            goto bad_reg;
+        }
         return 0;
     }
 bad_reg:
@@ -691,4 +790,18 @@ bad_reg:
     return 0;
 }
 
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+                ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+                void *opaque)
+{
+    if (cpnum < 0 || cpnum > 14) {
+        cpu_abort(env, "Bad coprocessor number: %i\n", cpnum);
+        return;
+    }
+
+    env->cp[cpnum].cp_read = cp_read;
+    env->cp[cpnum].cp_write = cp_write;
+    env->cp[cpnum].opaque = opaque;
+}
+
 #endif
index f17b812737cb681bc6912af5b829e501be35b74e..9cfb46237b8fcb083f1d7aa643984a37e659fd29 100644 (file)
@@ -1142,12 +1142,24 @@ void OPPROTO op_vfp_mdrr(void)
     FT0d = u.d;
 }
 
-/* Copy the most significant bit to T0 to all bits of T1.  */
+/* Copy the most significant bit of T0 to all bits of T1.  */
 void OPPROTO op_signbit_T1_T0(void)
 {
     T1 = (int32_t)T0 >> 31;
 }
 
+void OPPROTO op_movl_cp_T0(void)
+{
+    helper_set_cp(env, PARAM1, T0);
+    FORCE_RET();
+}
+
+void OPPROTO op_movl_T0_cp(void)
+{
+    T0 = helper_get_cp(env, PARAM1);
+    FORCE_RET();
+}
+
 void OPPROTO op_movl_cp15_T0(void)
 {
     helper_set_cp15(env, PARAM1, T0);
index 1631fcd3126e4387fb2ef33b3ee1c4424dcd21b3..65d234ae00a3c70a351711f642a3cea26542dc80 100644 (file)
@@ -492,6 +492,34 @@ static inline void gen_mov_vreg_F0(int dp, int reg)
         gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
 }
 
+/* Disassemble system coprocessor instruction.  Return nonzero if
+   instruction is not defined.  */
+static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    uint32_t rd = (insn >> 12) & 0xf;
+    uint32_t cp = (insn >> 8) & 0xf;
+    if (IS_USER(s)) {
+        return 1;
+    }
+
+    if (insn & (1 << 20)) {
+        if (!env->cp[cp].cp_read)
+            return 1;
+        gen_op_movl_T0_im((uint32_t) s->pc);
+        gen_op_movl_reg_TN[0][15]();
+        gen_op_movl_T0_cp(insn);
+        gen_movl_reg_T0(s, rd);
+    } else {
+        if (!env->cp[cp].cp_write)
+            return 1;
+        gen_op_movl_T0_im((uint32_t) s->pc);
+        gen_op_movl_reg_TN[0][15]();
+        gen_movl_T0_reg(s, rd);
+        gen_op_movl_cp_T0(insn);
+    }
+    return 0;
+}
+
 /* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
    instruction is not defined.  */
 static int disas_cp15_insn(DisasContext *s, uint32_t insn)
@@ -1812,7 +1840,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0xe:
             /* Coprocessor.  */
             op1 = (insn >> 8) & 0xf;
+            if (arm_feature(env, ARM_FEATURE_XSCALE) &&
+                    ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1)))
+                goto illegal_op;
             switch (op1) {
+            case 0 ... 1:
+            case 2 ... 9:
+            case 12 ... 14:
+                if (disas_cp_insn (env, s, insn))
+                    goto illegal_op;
+                break;
             case 10:
             case 11:
                 if (disas_vfp_insn (env, s, insn))
diff --git a/vl.h b/vl.h
index 09db43ef3b9bd49fdd8698442df22ca5c2ddf0b7..3b12d372c20c784e4ecf4c06204df09bc4af6703 100644 (file)
--- a/vl.h
+++ b/vl.h
@@ -1525,6 +1525,8 @@ struct pcmcia_card_s {
 /* dscm1xxxx.c */
 struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv);
 
+#include "hw/pxa.h"
+
 #include "gdbstub.h"
 
 #endif /* defined(QEMU_TOOL) */
This page took 0.111066 seconds and 4 git commands to generate.