]> git.proxmox.com Git - mirror_qemu.git/commitdiff
hw: move timer devices to hw/timer/, configure with default-configs/
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 13:38:25 +0000 (14:38 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 8 Apr 2013 16:13:14 +0000 (18:13 +0200)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
46 files changed:
default-configs/arm-softmmu.mak
default-configs/sparc-softmmu.mak
hw/arm/Makefile.objs
hw/arm_mptimer.c [deleted file]
hw/cris/Makefile.objs
hw/etraxfs_timer.c [deleted file]
hw/exynos4210_mct.c [deleted file]
hw/exynos4210_pwm.c [deleted file]
hw/exynos4210_rtc.c [deleted file]
hw/grlib_gptimer.c [deleted file]
hw/imx_timer.c [deleted file]
hw/input/Makefile.objs
hw/input/milkymist-softusb.c [new file with mode: 0644]
hw/input/pxa2xx_keypad.c [new file with mode: 0644]
hw/input/tsc210x.c [new file with mode: 0644]
hw/lm32/Makefile.objs
hw/lm32_timer.c [deleted file]
hw/milkymist-softusb.c [deleted file]
hw/milkymist-sysctl.c [deleted file]
hw/omap_gptimer.c [deleted file]
hw/omap_synctimer.c [deleted file]
hw/pxa2xx_keypad.c [deleted file]
hw/pxa2xx_timer.c [deleted file]
hw/sh4/Makefile.objs
hw/sh_timer.c [deleted file]
hw/slavio_timer.c [deleted file]
hw/sparc/Makefile.objs
hw/timer/Makefile.objs
hw/timer/arm_mptimer.c [new file with mode: 0644]
hw/timer/etraxfs_timer.c [new file with mode: 0644]
hw/timer/exynos4210_mct.c [new file with mode: 0644]
hw/timer/exynos4210_pwm.c [new file with mode: 0644]
hw/timer/exynos4210_rtc.c [new file with mode: 0644]
hw/timer/grlib_gptimer.c [new file with mode: 0644]
hw/timer/imx_timer.c [new file with mode: 0644]
hw/timer/lm32_timer.c [new file with mode: 0644]
hw/timer/milkymist-sysctl.c [new file with mode: 0644]
hw/timer/omap_gptimer.c [new file with mode: 0644]
hw/timer/omap_synctimer.c [new file with mode: 0644]
hw/timer/pxa2xx_timer.c [new file with mode: 0644]
hw/timer/sh_timer.c [new file with mode: 0644]
hw/timer/slavio_timer.c [new file with mode: 0644]
hw/timer/tusb6010.c [new file with mode: 0644]
hw/tsc210x.c [deleted file]
hw/tusb6010.c [deleted file]
include/hw/sparc/sun4m.h

index 8da5ec857edb3a80b71a791db51bc9ee7c2e0b81..94b52da3c82cbcf4ed30c7e7ea7267f1a8b569be 100644 (file)
@@ -34,6 +34,7 @@ CONFIG_MICRODRIVE=y
 CONFIG_USB_MUSB=y
 
 CONFIG_ARM_TIMER=y
+CONFIG_ARM_MPTIMER=y
 CONFIG_PL011=y
 CONFIG_PL022=y
 CONFIG_PL031=y
@@ -53,10 +54,13 @@ CONFIG_PXA2XX=y
 CONFIG_BITBANG_I2C=y
 CONFIG_FRAMEBUFFER=y
 CONFIG_XILINX_SPIPS=y
+
 CONFIG_MARVELL_88W8618=y
 CONFIG_OMAP=y
+CONFIG_TSC210X=y
 CONFIG_BLIZZARD=y
 CONFIG_ONENAND=y
+CONFIG_TUSB6010=y
 CONFIG_IMX=y
 CONFIG_ZAURUS=y
 
index da5b02d40517412b1041702640f8c2fbf51dfc73..6a2bad39629e19058c3441f17304487975ee57ef 100644 (file)
@@ -10,5 +10,6 @@ CONFIG_EMPTY_SLOT=y
 CONFIG_PCNET_COMMON=y
 CONFIG_LANCE=y
 CONFIG_TCX=y
+CONFIG_SLAVIO=y
 CONFIG_CS4231=y
 CONFIG_GRLIB=y
index 26e107f93c411ba15482ba45a677b23feb0f5bf6..76915402976c3045b61b6b77085f02cdfe11cff6 100644 (file)
@@ -3,23 +3,20 @@ obj-y += arm_gic.o arm_gic_common.o
 obj-y += a9scu.o
 obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-y += exynos4210_gic.o exynos4210_combiner.o
-obj-y += exynos4210_pwm.o
-obj-y += exynos4210_pmu.o exynos4210_mct.o
-obj-y += exynos4210_rtc.o
-obj-y += arm_mptimer.o a15mpcore.o
+obj-y += exynos4210_pmu.o
+obj-y += a15mpcore.o
 obj-y += armv7m_nvic.o
-obj-y += pxa2xx_timer.o pxa2xx_dma.o
-obj-y += pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
+obj-y += pxa2xx_dma.o
+obj-y += pxa2xx_mmci.o pxa2xx_pcmcia.o
 obj-y += zaurus.o
 obj-y += omap_dma.o omap_clk.o omap_mmc.o \
                 omap_gpio.o omap_intc.o
-obj-y += soc_dma.o omap_gptimer.o omap_synctimer.o \
+obj-y += soc_dma.o \
                 omap_gpmc.o omap_sdrc.o omap_tap.o omap_l4.o
-obj-y += tsc210x.o
-obj-y += cbus.o tusb6010.o
+obj-y += cbus.o
 obj-y += mst_fpga.o
 obj-y += strongarm.o
-obj-y += imx_ccm.o imx_timer.o imx_avic.o
+obj-y += imx_ccm.o imx_avic.o
 obj-$(CONFIG_KVM) += kvm/arm_gic.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
deleted file mode 100644 (file)
index 317f5e4..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited
- * Written by Paul Brook, Peter Maydell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-
-/* This device implements the per-cpu private timer and watchdog block
- * which is used in both the ARM11MPCore and Cortex-A9MP.
- */
-
-#define MAX_CPUS 4
-
-/* State of a single timer or watchdog block */
-typedef struct {
-    uint32_t count;
-    uint32_t load;
-    uint32_t control;
-    uint32_t status;
-    int64_t tick;
-    QEMUTimer *timer;
-    qemu_irq irq;
-    MemoryRegion iomem;
-} TimerBlock;
-
-typedef struct {
-    SysBusDevice busdev;
-    uint32_t num_cpu;
-    TimerBlock timerblock[MAX_CPUS];
-    MemoryRegion iomem;
-} ARMMPTimerState;
-
-static inline int get_current_cpu(ARMMPTimerState *s)
-{
-    CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
-
-    if (cpu_single_cpu->cpu_index >= s->num_cpu) {
-        hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
-                 s->num_cpu, cpu_single_cpu->cpu_index);
-    }
-    return cpu_single_cpu->cpu_index;
-}
-
-static inline void timerblock_update_irq(TimerBlock *tb)
-{
-    qemu_set_irq(tb->irq, tb->status);
-}
-
-/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
-static inline uint32_t timerblock_scale(TimerBlock *tb)
-{
-    return (((tb->control >> 8) & 0xff) + 1) * 10;
-}
-
-static void timerblock_reload(TimerBlock *tb, int restart)
-{
-    if (tb->count == 0) {
-        return;
-    }
-    if (restart) {
-        tb->tick = qemu_get_clock_ns(vm_clock);
-    }
-    tb->tick += (int64_t)tb->count * timerblock_scale(tb);
-    qemu_mod_timer(tb->timer, tb->tick);
-}
-
-static void timerblock_tick(void *opaque)
-{
-    TimerBlock *tb = (TimerBlock *)opaque;
-    tb->status = 1;
-    if (tb->control & 2) {
-        tb->count = tb->load;
-        timerblock_reload(tb, 0);
-    } else {
-        tb->count = 0;
-    }
-    timerblock_update_irq(tb);
-}
-
-static uint64_t timerblock_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    TimerBlock *tb = (TimerBlock *)opaque;
-    int64_t val;
-    switch (addr) {
-    case 0: /* Load */
-        return tb->load;
-    case 4: /* Counter.  */
-        if (((tb->control & 1) == 0) || (tb->count == 0)) {
-            return 0;
-        }
-        /* Slow and ugly, but hopefully won't happen too often.  */
-        val = tb->tick - qemu_get_clock_ns(vm_clock);
-        val /= timerblock_scale(tb);
-        if (val < 0) {
-            val = 0;
-        }
-        return val;
-    case 8: /* Control.  */
-        return tb->control;
-    case 12: /* Interrupt status.  */
-        return tb->status;
-    default:
-        return 0;
-    }
-}
-
-static void timerblock_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    TimerBlock *tb = (TimerBlock *)opaque;
-    int64_t old;
-    switch (addr) {
-    case 0: /* Load */
-        tb->load = value;
-        /* Fall through.  */
-    case 4: /* Counter.  */
-        if ((tb->control & 1) && tb->count) {
-            /* Cancel the previous timer.  */
-            qemu_del_timer(tb->timer);
-        }
-        tb->count = value;
-        if (tb->control & 1) {
-            timerblock_reload(tb, 1);
-        }
-        break;
-    case 8: /* Control.  */
-        old = tb->control;
-        tb->control = value;
-        if (((old & 1) == 0) && (value & 1)) {
-            if (tb->count == 0 && (tb->control & 2)) {
-                tb->count = tb->load;
-            }
-            timerblock_reload(tb, 1);
-        }
-        break;
-    case 12: /* Interrupt status.  */
-        tb->status &= ~value;
-        timerblock_update_irq(tb);
-        break;
-    }
-}
-
-/* Wrapper functions to implement the "read timer/watchdog for
- * the current CPU" memory regions.
- */
-static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
-    int id = get_current_cpu(s);
-    return timerblock_read(&s->timerblock[id], addr, size);
-}
-
-static void arm_thistimer_write(void *opaque, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
-    int id = get_current_cpu(s);
-    timerblock_write(&s->timerblock[id], addr, value, size);
-}
-
-static const MemoryRegionOps arm_thistimer_ops = {
-    .read = arm_thistimer_read,
-    .write = arm_thistimer_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps timerblock_ops = {
-    .read = timerblock_read,
-    .write = timerblock_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timerblock_reset(TimerBlock *tb)
-{
-    tb->count = 0;
-    tb->load = 0;
-    tb->control = 0;
-    tb->status = 0;
-    tb->tick = 0;
-    if (tb->timer) {
-        qemu_del_timer(tb->timer);
-    }
-}
-
-static void arm_mptimer_reset(DeviceState *dev)
-{
-    ARMMPTimerState *s =
-        FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev));
-    int i;
-    for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
-        timerblock_reset(&s->timerblock[i]);
-    }
-}
-
-static int arm_mptimer_init(SysBusDevice *dev)
-{
-    ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, dev);
-    int i;
-    if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
-        hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
-    }
-    /* We implement one timer block per CPU, and expose multiple MMIO regions:
-     *  * region 0 is "timer for this core"
-     *  * region 1 is "timer for core 0"
-     *  * region 2 is "timer for core 1"
-     * and so on.
-     * The outgoing interrupt lines are
-     *  * timer for core 0
-     *  * timer for core 1
-     * and so on.
-     */
-    memory_region_init_io(&s->iomem, &arm_thistimer_ops, s,
-                          "arm_mptimer_timer", 0x20);
-    sysbus_init_mmio(dev, &s->iomem);
-    for (i = 0; i < s->num_cpu; i++) {
-        TimerBlock *tb = &s->timerblock[i];
-        tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
-        sysbus_init_irq(dev, &tb->irq);
-        memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
-                              "arm_mptimer_timerblock", 0x20);
-        sysbus_init_mmio(dev, &tb->iomem);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_timerblock = {
-    .name = "arm_mptimer_timerblock",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(count, TimerBlock),
-        VMSTATE_UINT32(load, TimerBlock),
-        VMSTATE_UINT32(control, TimerBlock),
-        VMSTATE_UINT32(status, TimerBlock),
-        VMSTATE_INT64(tick, TimerBlock),
-        VMSTATE_TIMER(timer, TimerBlock),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_arm_mptimer = {
-    .name = "arm_mptimer",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
-                                     2, vmstate_timerblock, TimerBlock),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property arm_mptimer_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void arm_mptimer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sbc->init = arm_mptimer_init;
-    dc->vmsd = &vmstate_arm_mptimer;
-    dc->reset = arm_mptimer_reset;
-    dc->no_user = 1;
-    dc->props = arm_mptimer_properties;
-}
-
-static const TypeInfo arm_mptimer_info = {
-    .name          = "arm_mptimer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(ARMMPTimerState),
-    .class_init    = arm_mptimer_class_init,
-};
-
-static void arm_mptimer_register_types(void)
-{
-    type_register_static(&arm_mptimer_info);
-}
-
-type_init(arm_mptimer_register_types)
index c4d5189fc05d2a9e9dae55134c4f1fae9ec285c8..a8a4a9efcfd5bbdba4a39958585a8e512f56f068 100644 (file)
@@ -1,7 +1,6 @@
 # IO blocks
 obj-y += etraxfs_dma.o
 obj-y += etraxfs_pic.o
-obj-y += etraxfs_timer.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
deleted file mode 100644 (file)
index 3cd9476..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * QEMU ETRAX Timers
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-
-#define D(x)
-
-#define RW_TMR0_DIV   0x00
-#define R_TMR0_DATA   0x04
-#define RW_TMR0_CTRL  0x08
-#define RW_TMR1_DIV   0x10
-#define R_TMR1_DATA   0x14
-#define RW_TMR1_CTRL  0x18
-#define R_TIME        0x38
-#define RW_WD_CTRL    0x40
-#define R_WD_STAT     0x44
-#define RW_INTR_MASK  0x48
-#define RW_ACK_INTR   0x4c
-#define R_INTR        0x50
-#define R_MASKED_INTR 0x54
-
-struct etrax_timer {
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    qemu_irq irq;
-    qemu_irq nmi;
-
-    QEMUBH *bh_t0;
-    QEMUBH *bh_t1;
-    QEMUBH *bh_wd;
-    ptimer_state *ptimer_t0;
-    ptimer_state *ptimer_t1;
-    ptimer_state *ptimer_wd;
-
-    int wd_hits;
-
-    /* Control registers.  */
-    uint32_t rw_tmr0_div;
-    uint32_t r_tmr0_data;
-    uint32_t rw_tmr0_ctrl;
-
-    uint32_t rw_tmr1_div;
-    uint32_t r_tmr1_data;
-    uint32_t rw_tmr1_ctrl;
-
-    uint32_t rw_wd_ctrl;
-
-    uint32_t rw_intr_mask;
-    uint32_t rw_ack_intr;
-    uint32_t r_intr;
-    uint32_t r_masked_intr;
-};
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct etrax_timer *t = opaque;
-    uint32_t r = 0;
-
-    switch (addr) {
-    case R_TMR0_DATA:
-        r = ptimer_get_count(t->ptimer_t0);
-        break;
-    case R_TMR1_DATA:
-        r = ptimer_get_count(t->ptimer_t1);
-        break;
-    case R_TIME:
-        r = qemu_get_clock_ns(vm_clock) / 10;
-        break;
-    case RW_INTR_MASK:
-        r = t->rw_intr_mask;
-        break;
-    case R_MASKED_INTR:
-        r = t->r_intr & t->rw_intr_mask;
-        break;
-    default:
-        D(printf ("%s %x\n", __func__, addr));
-        break;
-    }
-    return r;
-}
-
-static void update_ctrl(struct etrax_timer *t, int tnum)
-{
-    unsigned int op;
-    unsigned int freq;
-    unsigned int freq_hz;
-    unsigned int div;
-    uint32_t ctrl;
-
-    ptimer_state *timer;
-
-    if (tnum == 0) {
-        ctrl = t->rw_tmr0_ctrl;
-        div = t->rw_tmr0_div;
-        timer = t->ptimer_t0;
-    } else {
-        ctrl = t->rw_tmr1_ctrl;
-        div = t->rw_tmr1_div;
-        timer = t->ptimer_t1;
-    }
-
-
-    op = ctrl & 3;
-    freq = ctrl >> 2;
-    freq_hz = 32000000;
-
-    switch (freq)
-    {
-    case 0:
-    case 1:
-        D(printf ("extern or disabled timer clock?\n"));
-        break;
-    case 4: freq_hz =  29493000; break;
-    case 5: freq_hz =  32000000; break;
-    case 6: freq_hz =  32768000; break;
-    case 7: freq_hz = 100000000; break;
-    default:
-        abort();
-        break;
-    }
-
-    D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
-    ptimer_set_freq(timer, freq_hz);
-    ptimer_set_limit(timer, div, 0);
-
-    switch (op)
-    {
-        case 0:
-            /* Load.  */
-            ptimer_set_limit(timer, div, 1);
-            break;
-        case 1:
-            /* Hold.  */
-            ptimer_stop(timer);
-            break;
-        case 2:
-            /* Run.  */
-            ptimer_run(timer, 0);
-            break;
-        default:
-            abort();
-            break;
-    }
-}
-
-static void timer_update_irq(struct etrax_timer *t)
-{
-    t->r_intr &= ~(t->rw_ack_intr);
-    t->r_masked_intr = t->r_intr & t->rw_intr_mask;
-
-    D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
-    qemu_set_irq(t->irq, !!t->r_masked_intr);
-}
-
-static void timer0_hit(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-    t->r_intr |= 1;
-    timer_update_irq(t);
-}
-
-static void timer1_hit(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-    t->r_intr |= 2;
-    timer_update_irq(t);
-}
-
-static void watchdog_hit(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-    if (t->wd_hits == 0) {
-        /* real hw gives a single tick before reseting but we are
-           a bit friendlier to compensate for our slower execution.  */
-        ptimer_set_count(t->ptimer_wd, 10);
-        ptimer_run(t->ptimer_wd, 1);
-        qemu_irq_raise(t->nmi);
-    }
-    else
-        qemu_system_reset_request();
-
-    t->wd_hits++;
-}
-
-static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
-{
-    unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
-    unsigned int wd_key = t->rw_wd_ctrl >> 9;
-    unsigned int wd_cnt = t->rw_wd_ctrl & 511;
-    unsigned int new_key = value >> 9 & ((1 << 7) - 1);
-    unsigned int new_cmd = (value >> 8) & 1;
-
-    /* If the watchdog is enabled, they written key must match the
-       complement of the previous.  */
-    wd_key = ~wd_key & ((1 << 7) - 1);
-
-    if (wd_en && wd_key != new_key)
-        return;
-
-    D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
-         wd_en, new_key, wd_key, new_cmd, wd_cnt));
-
-    if (t->wd_hits)
-        qemu_irq_lower(t->nmi);
-
-    t->wd_hits = 0;
-
-    ptimer_set_freq(t->ptimer_wd, 760);
-    if (wd_cnt == 0)
-        wd_cnt = 256;
-    ptimer_set_count(t->ptimer_wd, wd_cnt);
-    if (new_cmd)
-        ptimer_run(t->ptimer_wd, 1);
-    else
-        ptimer_stop(t->ptimer_wd);
-
-    t->rw_wd_ctrl = value;
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
-            uint64_t val64, unsigned int size)
-{
-    struct etrax_timer *t = opaque;
-    uint32_t value = val64;
-
-    switch (addr)
-    {
-        case RW_TMR0_DIV:
-            t->rw_tmr0_div = value;
-            break;
-        case RW_TMR0_CTRL:
-            D(printf ("RW_TMR0_CTRL=%x\n", value));
-            t->rw_tmr0_ctrl = value;
-            update_ctrl(t, 0);
-            break;
-        case RW_TMR1_DIV:
-            t->rw_tmr1_div = value;
-            break;
-        case RW_TMR1_CTRL:
-            D(printf ("RW_TMR1_CTRL=%x\n", value));
-            t->rw_tmr1_ctrl = value;
-            update_ctrl(t, 1);
-            break;
-        case RW_INTR_MASK:
-            D(printf ("RW_INTR_MASK=%x\n", value));
-            t->rw_intr_mask = value;
-            timer_update_irq(t);
-            break;
-        case RW_WD_CTRL:
-            timer_watchdog_update(t, value);
-            break;
-        case RW_ACK_INTR:
-            t->rw_ack_intr = value;
-            timer_update_irq(t);
-            t->rw_ack_intr = 0;
-            break;
-        default:
-            printf ("%s " TARGET_FMT_plx " %x\n",
-                __func__, addr, value);
-            break;
-    }
-}
-
-static const MemoryRegionOps timer_ops = {
-    .read = timer_read,
-    .write = timer_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void etraxfs_timer_reset(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-
-    ptimer_stop(t->ptimer_t0);
-    ptimer_stop(t->ptimer_t1);
-    ptimer_stop(t->ptimer_wd);
-    t->rw_wd_ctrl = 0;
-    t->r_intr = 0;
-    t->rw_intr_mask = 0;
-    qemu_irq_lower(t->irq);
-}
-
-static int etraxfs_timer_init(SysBusDevice *dev)
-{
-    struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
-
-    t->bh_t0 = qemu_bh_new(timer0_hit, t);
-    t->bh_t1 = qemu_bh_new(timer1_hit, t);
-    t->bh_wd = qemu_bh_new(watchdog_hit, t);
-    t->ptimer_t0 = ptimer_init(t->bh_t0);
-    t->ptimer_t1 = ptimer_init(t->bh_t1);
-    t->ptimer_wd = ptimer_init(t->bh_wd);
-
-    sysbus_init_irq(dev, &t->irq);
-    sysbus_init_irq(dev, &t->nmi);
-
-    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
-    sysbus_init_mmio(dev, &t->mmio);
-    qemu_register_reset(etraxfs_timer_reset, t);
-    return 0;
-}
-
-static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = etraxfs_timer_init;
-}
-
-static const TypeInfo etraxfs_timer_info = {
-    .name          = "etraxfs,timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof (struct etrax_timer),
-    .class_init    = etraxfs_timer_class_init,
-};
-
-static void etraxfs_timer_register_types(void)
-{
-    type_register_static(&etraxfs_timer_info);
-}
-
-type_init(etraxfs_timer_register_types)
diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c
deleted file mode 100644 (file)
index 87ce75b..0000000
+++ /dev/null
@@ -1,1482 +0,0 @@
-/*
- * Samsung exynos4210 Multi Core timer
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Global Timer:
- *
- * Consists of two timers. First represents Free Running Counter and second
- * is used to measure interval from FRC to nearest comparator.
- *
- *        0                                                           UINT64_MAX
- *        |                              timer0                             |
- *        | <-------------------------------------------------------------- |
- *        | --------------------------------------------frc---------------> |
- *        |______________________________________________|__________________|
- *                CMP0          CMP1             CMP2    |           CMP3
- *                                                     __|            |_
- *                                                     |     timer1     |
- *                                                     | -------------> |
- *                                                    frc              CMPx
- *
- * Problem: when implementing global timer as is, overflow arises.
- * next_time = cur_time + period * count;
- * period and count are 64 bits width.
- * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT
- * register during each event.
- *
- * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because
- * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--.
- * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0
- * generates IRQs suffers from too frequently events. Better to have one
- * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT,
- * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values,
- * there is no way to avoid frequently events).
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/arm/exynos4210.h"
-
-//#define DEBUG_MCT
-
-#ifdef DEBUG_MCT
-#define DPRINTF(fmt, ...) \
-        do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \
-                     ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define    MCT_CFG          0x000
-#define    G_CNT_L          0x100
-#define    G_CNT_U          0x104
-#define    G_CNT_WSTAT      0x110
-#define    G_COMP0_L        0x200
-#define    G_COMP0_U        0x204
-#define    G_COMP0_ADD_INCR 0x208
-#define    G_COMP1_L        0x210
-#define    G_COMP1_U        0x214
-#define    G_COMP1_ADD_INCR 0x218
-#define    G_COMP2_L        0x220
-#define    G_COMP2_U        0x224
-#define    G_COMP2_ADD_INCR 0x228
-#define    G_COMP3_L        0x230
-#define    G_COMP3_U        0x234
-#define    G_COMP3_ADD_INCR 0x238
-#define    G_TCON           0x240
-#define    G_INT_CSTAT      0x244
-#define    G_INT_ENB        0x248
-#define    G_WSTAT          0x24C
-#define    L0_TCNTB         0x300
-#define    L0_TCNTO         0x304
-#define    L0_ICNTB         0x308
-#define    L0_ICNTO         0x30C
-#define    L0_FRCNTB        0x310
-#define    L0_FRCNTO        0x314
-#define    L0_TCON          0x320
-#define    L0_INT_CSTAT     0x330
-#define    L0_INT_ENB       0x334
-#define    L0_WSTAT         0x340
-#define    L1_TCNTB         0x400
-#define    L1_TCNTO         0x404
-#define    L1_ICNTB         0x408
-#define    L1_ICNTO         0x40C
-#define    L1_FRCNTB        0x410
-#define    L1_FRCNTO        0x414
-#define    L1_TCON          0x420
-#define    L1_INT_CSTAT     0x430
-#define    L1_INT_ENB       0x434
-#define    L1_WSTAT         0x440
-
-#define MCT_CFG_GET_PRESCALER(x)    ((x) & 0xFF)
-#define MCT_CFG_GET_DIVIDER(x)      (1 << ((x) >> 8 & 7))
-
-#define GET_G_COMP_IDX(offset)          (((offset) - G_COMP0_L) / 0x10)
-#define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10)
-
-#define G_COMP_L(x) (G_COMP0_L + (x) * 0x10)
-#define G_COMP_U(x) (G_COMP0_U + (x) * 0x10)
-
-#define G_COMP_ADD_INCR(x)  (G_COMP0_ADD_INCR + (x) * 0x10)
-
-/* MCT bits */
-#define G_TCON_COMP_ENABLE(x)   (1 << 2 * (x))
-#define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1))
-#define G_TCON_TIMER_ENABLE     (1 << 8)
-
-#define G_INT_ENABLE(x)         (1 << (x))
-#define G_INT_CSTAT_COMP(x)     (1 << (x))
-
-#define G_CNT_WSTAT_L           1
-#define G_CNT_WSTAT_U           2
-
-#define G_WSTAT_COMP_L(x)       (1 << 4 * (x))
-#define G_WSTAT_COMP_U(x)       (1 << ((4 * (x)) + 1))
-#define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2))
-#define G_WSTAT_TCON_WRITE      (1 << 16)
-
-#define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100)
-#define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \
-        (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2)
-
-#define L_ICNTB_MANUAL_UPDATE   (1 << 31)
-
-#define L_TCON_TICK_START       (1)
-#define L_TCON_INT_START        (1 << 1)
-#define L_TCON_INTERVAL_MODE    (1 << 2)
-#define L_TCON_FRC_START        (1 << 3)
-
-#define L_INT_CSTAT_INTCNT      (1 << 0)
-#define L_INT_CSTAT_FRCCNT      (1 << 1)
-
-#define L_INT_INTENB_ICNTEIE    (1 << 0)
-#define L_INT_INTENB_FRCEIE     (1 << 1)
-
-#define L_WSTAT_TCNTB_WRITE     (1 << 0)
-#define L_WSTAT_ICNTB_WRITE     (1 << 1)
-#define L_WSTAT_FRCCNTB_WRITE   (1 << 2)
-#define L_WSTAT_TCON_WRITE      (1 << 3)
-
-enum LocalTimerRegCntIndexes {
-    L_REG_CNT_TCNTB,
-    L_REG_CNT_TCNTO,
-    L_REG_CNT_ICNTB,
-    L_REG_CNT_ICNTO,
-    L_REG_CNT_FRCCNTB,
-    L_REG_CNT_FRCCNTO,
-
-    L_REG_CNT_AMOUNT
-};
-
-#define MCT_NIRQ                6
-#define MCT_SFR_SIZE            0x444
-
-#define MCT_GT_CMP_NUM          4
-
-#define MCT_GT_MAX_VAL          UINT64_MAX
-
-#define MCT_GT_COUNTER_STEP     0x100000000ULL
-#define MCT_LT_COUNTER_STEP     0x100000000ULL
-#define MCT_LT_CNT_LOW_LIMIT    0x100
-
-/* global timer */
-typedef struct {
-    qemu_irq  irq[MCT_GT_CMP_NUM];
-
-    struct gregs {
-        uint64_t cnt;
-        uint32_t cnt_wstat;
-        uint32_t tcon;
-        uint32_t int_cstat;
-        uint32_t int_enb;
-        uint32_t wstat;
-        uint64_t comp[MCT_GT_CMP_NUM];
-        uint32_t comp_add_incr[MCT_GT_CMP_NUM];
-    } reg;
-
-    uint64_t count;            /* Value FRC was armed with */
-    int32_t curr_comp;             /* Current comparator FRC is running to */
-
-    ptimer_state *ptimer_frc;                   /* FRC timer */
-
-} Exynos4210MCTGT;
-
-/* local timer */
-typedef struct {
-    int         id;             /* timer id */
-    qemu_irq    irq;            /* local timer irq */
-
-    struct tick_timer {
-        uint32_t cnt_run;           /* cnt timer is running */
-        uint32_t int_run;           /* int timer is running */
-
-        uint32_t last_icnto;
-        uint32_t last_tcnto;
-        uint32_t tcntb;             /* initial value for TCNTB */
-        uint32_t icntb;             /* initial value for ICNTB */
-
-        /* for step mode */
-        uint64_t    distance;       /* distance to count to the next event */
-        uint64_t    progress;       /* progress when counting by steps */
-        uint64_t    count;          /* count to arm timer with */
-
-        ptimer_state *ptimer_tick;  /* timer for tick counter */
-    } tick_timer;
-
-    /* use ptimer.c to represent count down timer */
-
-    ptimer_state *ptimer_frc;   /* timer for free running counter */
-
-    /* registers */
-    struct lregs {
-        uint32_t    cnt[L_REG_CNT_AMOUNT];
-        uint32_t    tcon;
-        uint32_t    int_cstat;
-        uint32_t    int_enb;
-        uint32_t    wstat;
-    } reg;
-
-} Exynos4210MCTLT;
-
-typedef struct Exynos4210MCTState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    /* Registers */
-    uint32_t    reg_mct_cfg;
-
-    Exynos4210MCTLT l_timer[2];
-    Exynos4210MCTGT g_timer;
-
-    uint32_t    freq;                   /* all timers tick frequency, TCLK */
-} Exynos4210MCTState;
-
-/*** VMState ***/
-static const VMStateDescription vmstate_tick_timer = {
-    .name = "exynos4210.mct.tick_timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(cnt_run, struct tick_timer),
-        VMSTATE_UINT32(int_run, struct tick_timer),
-        VMSTATE_UINT32(last_icnto, struct tick_timer),
-        VMSTATE_UINT32(last_tcnto, struct tick_timer),
-        VMSTATE_UINT32(tcntb, struct tick_timer),
-        VMSTATE_UINT32(icntb, struct tick_timer),
-        VMSTATE_UINT64(distance, struct tick_timer),
-        VMSTATE_UINT64(progress, struct tick_timer),
-        VMSTATE_UINT64(count, struct tick_timer),
-        VMSTATE_PTIMER(ptimer_tick, struct tick_timer),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_lregs = {
-    .name = "exynos4210.mct.lregs",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT),
-        VMSTATE_UINT32(tcon, struct lregs),
-        VMSTATE_UINT32(int_cstat, struct lregs),
-        VMSTATE_UINT32(int_enb, struct lregs),
-        VMSTATE_UINT32(wstat, struct lregs),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_exynos4210_mct_lt = {
-    .name = "exynos4210.mct.lt",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(id, Exynos4210MCTLT),
-        VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0,
-                vmstate_tick_timer,
-                struct tick_timer),
-        VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT),
-        VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0,
-                vmstate_lregs,
-                struct lregs),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_gregs = {
-    .name = "exynos4210.mct.lregs",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(cnt, struct gregs),
-        VMSTATE_UINT32(cnt_wstat, struct gregs),
-        VMSTATE_UINT32(tcon, struct gregs),
-        VMSTATE_UINT32(int_cstat, struct gregs),
-        VMSTATE_UINT32(int_enb, struct gregs),
-        VMSTATE_UINT32(wstat, struct gregs),
-        VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM),
-        VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs,
-                MCT_GT_CMP_NUM),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_exynos4210_mct_gt = {
-    .name = "exynos4210.mct.lt",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs,
-                struct gregs),
-        VMSTATE_UINT64(count, Exynos4210MCTGT),
-        VMSTATE_INT32(curr_comp, Exynos4210MCTGT),
-        VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_exynos4210_mct_state = {
-    .name = "exynos4210.mct",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState),
-        VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0,
-            vmstate_exynos4210_mct_lt, Exynos4210MCTLT),
-        VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0,
-            vmstate_exynos4210_mct_gt, Exynos4210MCTGT),
-        VMSTATE_UINT32(freq, Exynos4210MCTState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void exynos4210_mct_update_freq(Exynos4210MCTState *s);
-
-/*
- * Set counter of FRC global timer.
- */
-static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
-{
-    s->count = count;
-    DPRINTF("global timer frc set count 0x%llx\n", count);
-    ptimer_set_count(s->ptimer_frc, count);
-}
-
-/*
- * Get counter of FRC global timer.
- */
-static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
-{
-    uint64_t count = 0;
-    count = ptimer_get_count(s->ptimer_frc);
-    count = s->count - count;
-    return s->reg.cnt + count;
-}
-
-/*
- * Stop global FRC timer
- */
-static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
-{
-    DPRINTF("global timer frc stop\n");
-
-    ptimer_stop(s->ptimer_frc);
-}
-
-/*
- * Start global FRC timer
- */
-static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
-{
-    DPRINTF("global timer frc start\n");
-
-    ptimer_run(s->ptimer_frc, 1);
-}
-
-/*
- * Find next nearest Comparator. If current Comparator value equals to other
- * Comparator value, skip them both
- */
-static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
-{
-    int res;
-    int i;
-    int enabled;
-    uint64_t min;
-    int min_comp_i;
-    uint64_t gfrc;
-    uint64_t distance;
-    uint64_t distance_min;
-    int comp_i;
-
-    /* get gfrc count */
-    gfrc = exynos4210_gfrc_get_count(&s->g_timer);
-
-    min = UINT64_MAX;
-    distance_min = UINT64_MAX;
-    comp_i = MCT_GT_CMP_NUM;
-    min_comp_i = MCT_GT_CMP_NUM;
-    enabled = 0;
-
-    /* lookup for nearest comparator */
-    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-
-        if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
-
-            enabled = 1;
-
-            if (s->g_timer.reg.comp[i] > gfrc) {
-                /* Comparator is upper then FRC */
-                distance = s->g_timer.reg.comp[i] - gfrc;
-
-                if (distance <= distance_min) {
-                    distance_min = distance;
-                    comp_i = i;
-                }
-            } else {
-                /* Comparator is below FRC, find the smallest */
-
-                if (s->g_timer.reg.comp[i] <= min) {
-                    min = s->g_timer.reg.comp[i];
-                    min_comp_i = i;
-                }
-            }
-        }
-    }
-
-    if (!enabled) {
-        /* All Comparators disabled */
-        res = -1;
-    } else if (comp_i < MCT_GT_CMP_NUM) {
-        /* Found upper Comparator */
-        res = comp_i;
-    } else {
-        /* All Comparators are below or equal to FRC  */
-        res = min_comp_i;
-    }
-
-    DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
-            res,
-            s->g_timer.reg.comp[res],
-            distance_min,
-            gfrc);
-
-    return res;
-}
-
-/*
- * Get distance to nearest Comparator
- */
-static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
-{
-    if (id == -1) {
-        /* no enabled Comparators, choose max distance */
-        return MCT_GT_COUNTER_STEP;
-    }
-    if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
-        return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
-    } else {
-        return MCT_GT_COUNTER_STEP;
-    }
-}
-
-/*
- * Restart global FRC timer
- */
-static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
-{
-    uint64_t distance;
-
-    exynos4210_gfrc_stop(&s->g_timer);
-
-    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
-
-    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
-
-    if (distance > MCT_GT_COUNTER_STEP || !distance) {
-        distance = MCT_GT_COUNTER_STEP;
-    }
-
-    exynos4210_gfrc_set_count(&s->g_timer, distance);
-    exynos4210_gfrc_start(&s->g_timer);
-}
-
-/*
- * Raise global timer CMP IRQ
- */
-static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
-{
-    Exynos4210MCTGT *s = opaque;
-
-    /* If CSTAT is pending and IRQ is enabled */
-    if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
-            (s->reg.int_enb & G_INT_ENABLE(id))) {
-        DPRINTF("gcmp timer[%d] IRQ\n", id);
-        qemu_irq_raise(s->irq[id]);
-    }
-}
-
-/*
- * Lower global timer CMP IRQ
- */
-static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
-{
-    Exynos4210MCTGT *s = opaque;
-    qemu_irq_lower(s->irq[id]);
-}
-
-/*
- * Global timer FRC event handler.
- * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
- * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
- */
-static void exynos4210_gfrc_event(void *opaque)
-{
-    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
-    int i;
-    uint64_t distance;
-
-    DPRINTF("\n");
-
-    s->g_timer.reg.cnt += s->g_timer.count;
-
-    /* Process all comparators */
-    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-
-        if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
-            /* reached nearest comparator */
-
-            s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
-
-            /* Auto increment */
-            if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
-                s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
-            }
-
-            /* IRQ */
-            exynos4210_gcomp_raise_irq(&s->g_timer, i);
-        }
-    }
-
-    /* Reload FRC to reach nearest comparator */
-    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
-    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
-    if (distance > MCT_GT_COUNTER_STEP || !distance) {
-        distance = MCT_GT_COUNTER_STEP;
-    }
-    exynos4210_gfrc_set_count(&s->g_timer, distance);
-
-    exynos4210_gfrc_start(&s->g_timer);
-}
-
-/*
- * Get counter of FRC local timer.
- */
-static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
-{
-    return ptimer_get_count(s->ptimer_frc);
-}
-
-/*
- * Set counter of FRC local timer.
- */
-static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
-{
-    if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) {
-        ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP);
-    } else {
-        ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]);
-    }
-}
-
-/*
- * Start local FRC timer
- */
-static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
-{
-    ptimer_run(s->ptimer_frc, 1);
-}
-
-/*
- * Stop local FRC timer
- */
-static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
-{
-    ptimer_stop(s->ptimer_frc);
-}
-
-/*
- * Local timer free running counter tick handler
- */
-static void exynos4210_lfrc_event(void *opaque)
-{
-    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
-
-    /* local frc expired */
-
-    DPRINTF("\n");
-
-    s->reg.int_cstat |= L_INT_CSTAT_FRCCNT;
-
-    /* update frc counter */
-    exynos4210_lfrc_update_count(s);
-
-    /* raise irq */
-    if (s->reg.int_enb & L_INT_INTENB_FRCEIE) {
-        qemu_irq_raise(s->irq);
-    }
-
-    /*  we reached here, this means that timer is enabled */
-    exynos4210_lfrc_start(s);
-}
-
-static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s);
-static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s);
-static void exynos4210_ltick_recalc_count(struct tick_timer *s);
-
-/*
- * Action on enabling local tick int timer
- */
-static void exynos4210_ltick_int_start(struct tick_timer *s)
-{
-    if (!s->int_run) {
-        s->int_run = 1;
-    }
-}
-
-/*
- * Action on disabling local tick int timer
- */
-static void exynos4210_ltick_int_stop(struct tick_timer *s)
-{
-    if (s->int_run) {
-        s->last_icnto = exynos4210_ltick_int_get_cnto(s);
-        s->int_run = 0;
-    }
-}
-
-/*
- * Get count for INT timer
- */
-static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
-{
-    uint32_t icnto;
-    uint64_t remain;
-    uint64_t count;
-    uint64_t counted;
-    uint64_t cur_progress;
-
-    count = ptimer_get_count(s->ptimer_tick);
-    if (count) {
-        /* timer is still counting, called not from event */
-        counted = s->count - ptimer_get_count(s->ptimer_tick);
-        cur_progress = s->progress + counted;
-    } else {
-        /* timer expired earlier */
-        cur_progress = s->progress;
-    }
-
-    remain = s->distance - cur_progress;
-
-    if (!s->int_run) {
-        /* INT is stopped. */
-        icnto = s->last_icnto;
-    } else {
-        /* Both are counting */
-        icnto = remain / s->tcntb;
-    }
-
-    return icnto;
-}
-
-/*
- * Start local tick cnt timer.
- */
-static void exynos4210_ltick_cnt_start(struct tick_timer *s)
-{
-    if (!s->cnt_run) {
-
-        exynos4210_ltick_recalc_count(s);
-        ptimer_set_count(s->ptimer_tick, s->count);
-        ptimer_run(s->ptimer_tick, 1);
-
-        s->cnt_run = 1;
-    }
-}
-
-/*
- * Stop local tick cnt timer.
- */
-static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
-{
-    if (s->cnt_run) {
-
-        s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s);
-
-        if (s->int_run) {
-            exynos4210_ltick_int_stop(s);
-        }
-
-        ptimer_stop(s->ptimer_tick);
-
-        s->cnt_run = 0;
-    }
-}
-
-/*
- * Get counter for CNT timer
- */
-static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
-{
-    uint32_t tcnto;
-    uint32_t icnto;
-    uint64_t remain;
-    uint64_t counted;
-    uint64_t count;
-    uint64_t cur_progress;
-
-    count = ptimer_get_count(s->ptimer_tick);
-    if (count) {
-        /* timer is still counting, called not from event */
-        counted = s->count - ptimer_get_count(s->ptimer_tick);
-        cur_progress = s->progress + counted;
-    } else {
-        /* timer expired earlier */
-        cur_progress = s->progress;
-    }
-
-    remain = s->distance - cur_progress;
-
-    if (!s->cnt_run) {
-        /* Both are stopped. */
-        tcnto = s->last_tcnto;
-    } else if (!s->int_run) {
-        /* INT counter is stopped, progress is by CNT timer */
-        tcnto = remain % s->tcntb;
-    } else {
-        /* Both are counting */
-        icnto = remain / s->tcntb;
-        if (icnto) {
-            tcnto = remain % (icnto * s->tcntb);
-        } else {
-            tcnto = remain % s->tcntb;
-        }
-    }
-
-    return tcnto;
-}
-
-/*
- * Set new values of counters for CNT and INT timers
- */
-static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
-        uint32_t new_int)
-{
-    uint32_t cnt_stopped = 0;
-    uint32_t int_stopped = 0;
-
-    if (s->cnt_run) {
-        exynos4210_ltick_cnt_stop(s);
-        cnt_stopped = 1;
-    }
-
-    if (s->int_run) {
-        exynos4210_ltick_int_stop(s);
-        int_stopped = 1;
-    }
-
-    s->tcntb = new_cnt + 1;
-    s->icntb = new_int + 1;
-
-    if (cnt_stopped) {
-        exynos4210_ltick_cnt_start(s);
-    }
-    if (int_stopped) {
-        exynos4210_ltick_int_start(s);
-    }
-
-}
-
-/*
- * Calculate new counter value for tick timer
- */
-static void exynos4210_ltick_recalc_count(struct tick_timer *s)
-{
-    uint64_t to_count;
-
-    if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) {
-        /*
-         * one or both timers run and not counted to the end;
-         * distance is not passed, recalculate with last_tcnto * last_icnto
-         */
-
-        if (s->last_tcnto) {
-            to_count = s->last_tcnto * s->last_icnto;
-        } else {
-            to_count = s->last_icnto;
-        }
-    } else {
-        /* distance is passed, recalculate with tcnto * icnto */
-        if (s->icntb) {
-            s->distance = s->tcntb * s->icntb;
-        } else {
-            s->distance = s->tcntb;
-        }
-
-        to_count = s->distance;
-        s->progress = 0;
-    }
-
-    if (to_count > MCT_LT_COUNTER_STEP) {
-        /* count by step */
-        s->count = MCT_LT_COUNTER_STEP;
-    } else {
-        s->count = to_count;
-    }
-}
-
-/*
- * Initialize tick_timer
- */
-static void exynos4210_ltick_timer_init(struct tick_timer *s)
-{
-    exynos4210_ltick_int_stop(s);
-    exynos4210_ltick_cnt_stop(s);
-
-    s->count = 0;
-    s->distance = 0;
-    s->progress = 0;
-    s->icntb = 0;
-    s->tcntb = 0;
-}
-
-/*
- * tick_timer event.
- * Raises when abstract tick_timer expires.
- */
-static void exynos4210_ltick_timer_event(struct tick_timer *s)
-{
-    s->progress += s->count;
-}
-
-/*
- * Local timer tick counter handler.
- * Don't use reloaded timers. If timer counter = zero
- * then handler called but after handler finished no
- * timer reload occurs.
- */
-static void exynos4210_ltick_event(void *opaque)
-{
-    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
-    uint32_t tcnto;
-    uint32_t icnto;
-#ifdef DEBUG_MCT
-    static uint64_t time1[2] = {0};
-    static uint64_t time2[2] = {0};
-#endif
-
-    /* Call tick_timer event handler, it will update its tcntb and icntb. */
-    exynos4210_ltick_timer_event(&s->tick_timer);
-
-    /* get tick_timer cnt */
-    tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer);
-
-    /* get tick_timer int */
-    icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer);
-
-    /* raise IRQ if needed */
-    if (!icnto && s->reg.tcon & L_TCON_INT_START) {
-        /* INT counter enabled and expired */
-
-        s->reg.int_cstat |= L_INT_CSTAT_INTCNT;
-
-        /* raise interrupt if enabled */
-        if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) {
-#ifdef DEBUG_MCT
-            time2[s->id] = qemu_get_clock_ns(vm_clock);
-            DPRINTF("local timer[%d] IRQ: %llx\n", s->id,
-                    time2[s->id] - time1[s->id]);
-            time1[s->id] = time2[s->id];
-#endif
-            qemu_irq_raise(s->irq);
-        }
-
-        /* reload ICNTB */
-        if (s->reg.tcon & L_TCON_INTERVAL_MODE) {
-            exynos4210_ltick_set_cntb(&s->tick_timer,
-                    s->reg.cnt[L_REG_CNT_TCNTB],
-                    s->reg.cnt[L_REG_CNT_ICNTB]);
-        }
-    } else {
-        /* reload TCNTB */
-        if (!tcnto) {
-            exynos4210_ltick_set_cntb(&s->tick_timer,
-                    s->reg.cnt[L_REG_CNT_TCNTB],
-                    icnto);
-        }
-    }
-
-    /* start tick_timer cnt */
-    exynos4210_ltick_cnt_start(&s->tick_timer);
-
-    /* start tick_timer int */
-    exynos4210_ltick_int_start(&s->tick_timer);
-}
-
-/* update timer frequency */
-static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
-{
-    uint32_t freq = s->freq;
-    s->freq = 24000000 /
-            ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) *
-                    MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
-
-    if (freq != s->freq) {
-        DPRINTF("freq=%dHz\n", s->freq);
-
-        /* global timer */
-        ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
-
-        /* local timer */
-        ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
-        ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
-        ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
-        ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
-    }
-}
-
-/* set defaul_timer values for all fields */
-static void exynos4210_mct_reset(DeviceState *d)
-{
-    Exynos4210MCTState *s = (Exynos4210MCTState *)d;
-    uint32_t i;
-
-    s->reg_mct_cfg = 0;
-
-    /* global timer */
-    memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
-    exynos4210_gfrc_stop(&s->g_timer);
-
-    /* local timer */
-    memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
-    memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt));
-    for (i = 0; i < 2; i++) {
-        s->l_timer[i].reg.int_cstat = 0;
-        s->l_timer[i].reg.int_enb = 0;
-        s->l_timer[i].reg.tcon = 0;
-        s->l_timer[i].reg.wstat = 0;
-        s->l_timer[i].tick_timer.count = 0;
-        s->l_timer[i].tick_timer.distance = 0;
-        s->l_timer[i].tick_timer.progress = 0;
-        ptimer_stop(s->l_timer[i].ptimer_frc);
-
-        exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
-    }
-
-    exynos4210_mct_update_freq(s);
-
-}
-
-/* Multi Core Timer read */
-static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
-    int index;
-    int shift;
-    uint64_t count;
-    uint32_t value;
-    int lt_i;
-
-    switch (offset) {
-
-    case MCT_CFG:
-        value = s->reg_mct_cfg;
-        break;
-
-    case G_CNT_L: case G_CNT_U:
-        shift = 8 * (offset & 0x4);
-        count = exynos4210_gfrc_get_count(&s->g_timer);
-        value = UINT32_MAX & (count >> shift);
-        DPRINTF("read FRC=0x%llx\n", count);
-        break;
-
-    case G_CNT_WSTAT:
-        value = s->g_timer.reg.cnt_wstat;
-        break;
-
-    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
-    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
-    index = GET_G_COMP_IDX(offset);
-    shift = 8 * (offset & 0x4);
-    value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
-    break;
-
-    case G_TCON:
-        value = s->g_timer.reg.tcon;
-        break;
-
-    case G_INT_CSTAT:
-        value = s->g_timer.reg.int_cstat;
-        break;
-
-    case G_INT_ENB:
-        value = s->g_timer.reg.int_enb;
-        break;
-        break;
-    case G_WSTAT:
-        value = s->g_timer.reg.wstat;
-        break;
-
-    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
-    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
-        value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
-        break;
-
-        /* Local timers */
-    case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
-    case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
-        lt_i = GET_L_TIMER_IDX(offset);
-        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-        value = s->l_timer[lt_i].reg.cnt[index];
-        break;
-
-    case L0_TCNTO: case L1_TCNTO:
-        lt_i = GET_L_TIMER_IDX(offset);
-
-        value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
-        DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
-        break;
-
-    case L0_ICNTO: case L1_ICNTO:
-        lt_i = GET_L_TIMER_IDX(offset);
-
-        value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
-        DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
-        break;
-
-    case L0_FRCNTO: case L1_FRCNTO:
-        lt_i = GET_L_TIMER_IDX(offset);
-
-        value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
-
-        break;
-
-    case L0_TCON: case L1_TCON:
-        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
-        value = s->l_timer[lt_i].reg.tcon;
-        break;
-
-    case L0_INT_CSTAT: case L1_INT_CSTAT:
-        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
-        value = s->l_timer[lt_i].reg.int_cstat;
-        break;
-
-    case L0_INT_ENB: case L1_INT_ENB:
-        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
-        value = s->l_timer[lt_i].reg.int_enb;
-        break;
-
-    case L0_WSTAT: case L1_WSTAT:
-        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
-        value = s->l_timer[lt_i].reg.wstat;
-        break;
-
-    default:
-        hw_error("exynos4210.mct: bad read offset "
-                TARGET_FMT_plx "\n", offset);
-        break;
-    }
-    return value;
-}
-
-/* MCT write */
-static void exynos4210_mct_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
-    int index;  /* index in buffer which represents register set */
-    int shift;
-    int lt_i;
-    uint64_t new_frc;
-    uint32_t i;
-    uint32_t old_val;
-#ifdef DEBUG_MCT
-    static uint32_t icntb_max[2] = {0};
-    static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
-    static uint32_t tcntb_max[2] = {0};
-    static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
-#endif
-
-    new_frc = s->g_timer.reg.cnt;
-
-    switch (offset) {
-
-    case MCT_CFG:
-        s->reg_mct_cfg = value;
-        exynos4210_mct_update_freq(s);
-        break;
-
-    case G_CNT_L:
-    case G_CNT_U:
-        if (offset == G_CNT_L) {
-
-            DPRINTF("global timer write to reg.cntl %llx\n", value);
-
-            new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
-            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
-        }
-        if (offset == G_CNT_U) {
-
-            DPRINTF("global timer write to reg.cntu %llx\n", value);
-
-            new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
-                    ((uint64_t)value << 32);
-            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
-        }
-
-        s->g_timer.reg.cnt = new_frc;
-        exynos4210_gfrc_restart(s);
-        break;
-
-    case G_CNT_WSTAT:
-        s->g_timer.reg.cnt_wstat &= ~(value);
-        break;
-
-    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
-    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
-    index = GET_G_COMP_IDX(offset);
-    shift = 8 * (offset & 0x4);
-    s->g_timer.reg.comp[index] =
-            (s->g_timer.reg.comp[index] &
-            (((uint64_t)UINT32_MAX << 32) >> shift)) +
-            (value << shift);
-
-    DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
-
-    if (offset&0x4) {
-        s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
-    } else {
-        s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
-    }
-
-    exynos4210_gfrc_restart(s);
-    break;
-
-    case G_TCON:
-        old_val = s->g_timer.reg.tcon;
-        s->g_timer.reg.tcon = value;
-        s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
-
-        DPRINTF("global timer write to reg.g_tcon %llx\n", value);
-
-        /* Start FRC if transition from disabled to enabled */
-        if ((value & G_TCON_TIMER_ENABLE) > (old_val &
-                G_TCON_TIMER_ENABLE)) {
-            exynos4210_gfrc_start(&s->g_timer);
-        }
-        if ((value & G_TCON_TIMER_ENABLE) < (old_val &
-                G_TCON_TIMER_ENABLE)) {
-            exynos4210_gfrc_stop(&s->g_timer);
-        }
-
-        /* Start CMP if transition from disabled to enabled */
-        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-            if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
-                    G_TCON_COMP_ENABLE(i))) {
-                exynos4210_gfrc_restart(s);
-            }
-        }
-        break;
-
-    case G_INT_CSTAT:
-        s->g_timer.reg.int_cstat &= ~(value);
-        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-            if (value & G_INT_CSTAT_COMP(i)) {
-                exynos4210_gcomp_lower_irq(&s->g_timer, i);
-            }
-        }
-        break;
-
-    case G_INT_ENB:
-
-        /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
-        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-            if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
-                    G_INT_ENABLE(i))) {
-                if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
-                    exynos4210_gcomp_raise_irq(&s->g_timer, i);
-                }
-            }
-
-            if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
-                    G_INT_ENABLE(i))) {
-                exynos4210_gcomp_lower_irq(&s->g_timer, i);
-            }
-        }
-
-        DPRINTF("global timer INT enable %llx\n", value);
-        s->g_timer.reg.int_enb = value;
-        break;
-
-    case G_WSTAT:
-        s->g_timer.reg.wstat &= ~(value);
-        break;
-
-    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
-    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
-        index = GET_G_COMP_ADD_INCR_IDX(offset);
-        s->g_timer.reg.comp_add_incr[index] = value;
-        s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
-        break;
-
-        /* Local timers */
-    case L0_TCON: case L1_TCON:
-        lt_i = GET_L_TIMER_IDX(offset);
-        old_val = s->l_timer[lt_i].reg.tcon;
-
-        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
-        s->l_timer[lt_i].reg.tcon = value;
-
-        /* Stop local CNT */
-        if ((value & L_TCON_TICK_START) <
-                (old_val & L_TCON_TICK_START)) {
-            DPRINTF("local timer[%d] stop cnt\n", lt_i);
-            exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
-        }
-
-        /* Stop local INT */
-        if ((value & L_TCON_INT_START) <
-                (old_val & L_TCON_INT_START)) {
-            DPRINTF("local timer[%d] stop int\n", lt_i);
-            exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
-        }
-
-        /* Start local CNT */
-        if ((value & L_TCON_TICK_START) >
-        (old_val & L_TCON_TICK_START)) {
-            DPRINTF("local timer[%d] start cnt\n", lt_i);
-            exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
-        }
-
-        /* Start local INT */
-        if ((value & L_TCON_INT_START) >
-        (old_val & L_TCON_INT_START)) {
-            DPRINTF("local timer[%d] start int\n", lt_i);
-            exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
-        }
-
-        /* Start or Stop local FRC if TCON changed */
-        if ((value & L_TCON_FRC_START) >
-        (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
-            DPRINTF("local timer[%d] start frc\n", lt_i);
-            exynos4210_lfrc_start(&s->l_timer[lt_i]);
-        }
-        if ((value & L_TCON_FRC_START) <
-                (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
-            DPRINTF("local timer[%d] stop frc\n", lt_i);
-            exynos4210_lfrc_stop(&s->l_timer[lt_i]);
-        }
-        break;
-
-    case L0_TCNTB: case L1_TCNTB:
-
-        lt_i = GET_L_TIMER_IDX(offset);
-        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-
-        /*
-         * TCNTB is updated to internal register only after CNT expired.
-         * Due to this we should reload timer to nearest moment when CNT is
-         * expired and then in event handler update tcntb to new TCNTB value.
-         */
-        exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
-                s->l_timer[lt_i].tick_timer.icntb);
-
-        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
-        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
-
-#ifdef DEBUG_MCT
-        if (tcntb_min[lt_i] > value) {
-            tcntb_min[lt_i] = value;
-        }
-        if (tcntb_max[lt_i] < value) {
-            tcntb_max[lt_i] = value;
-        }
-        DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
-                lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
-#endif
-        break;
-
-    case L0_ICNTB: case L1_ICNTB:
-
-        lt_i = GET_L_TIMER_IDX(offset);
-        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-
-        s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
-        s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
-                ~L_ICNTB_MANUAL_UPDATE;
-
-        /*
-         * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
-         * could raise too fast disallowing QEMU to execute target code.
-         */
-        if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
-            s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
-            if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
-                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
-                        MCT_LT_CNT_LOW_LIMIT;
-            } else {
-                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
-                        MCT_LT_CNT_LOW_LIMIT /
-                        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
-            }
-        }
-
-        if (value & L_ICNTB_MANUAL_UPDATE) {
-            exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
-                    s->l_timer[lt_i].tick_timer.tcntb,
-                    s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
-        }
-
-#ifdef DEBUG_MCT
-        if (icntb_min[lt_i] > value) {
-            icntb_min[lt_i] = value;
-        }
-        if (icntb_max[lt_i] < value) {
-            icntb_max[lt_i] = value;
-        }
-DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
-        lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
-#endif
-break;
-
-    case L0_FRCNTB: case L1_FRCNTB:
-
-        lt_i = GET_L_TIMER_IDX(offset);
-        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-
-        DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
-
-        s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
-        s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
-
-        break;
-
-    case L0_TCNTO: case L1_TCNTO:
-    case L0_ICNTO: case L1_ICNTO:
-    case L0_FRCNTO: case L1_FRCNTO:
-        fprintf(stderr, "\n[exynos4210.mct: write to RO register "
-                TARGET_FMT_plx "]\n\n", offset);
-        break;
-
-    case L0_INT_CSTAT: case L1_INT_CSTAT:
-        lt_i = GET_L_TIMER_IDX(offset);
-
-        DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
-
-        s->l_timer[lt_i].reg.int_cstat &= ~value;
-        if (!s->l_timer[lt_i].reg.int_cstat) {
-            qemu_irq_lower(s->l_timer[lt_i].irq);
-        }
-        break;
-
-    case L0_INT_ENB: case L1_INT_ENB:
-        lt_i = GET_L_TIMER_IDX(offset);
-        old_val = s->l_timer[lt_i].reg.int_enb;
-
-        /* Raise Local timer IRQ if cstat is pending */
-        if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
-            if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
-                qemu_irq_raise(s->l_timer[lt_i].irq);
-            }
-        }
-
-        s->l_timer[lt_i].reg.int_enb = value;
-
-        break;
-
-    case L0_WSTAT: case L1_WSTAT:
-        lt_i = GET_L_TIMER_IDX(offset);
-
-        s->l_timer[lt_i].reg.wstat &= ~value;
-        break;
-
-    default:
-        hw_error("exynos4210.mct: bad write offset "
-                TARGET_FMT_plx "\n", offset);
-        break;
-    }
-}
-
-static const MemoryRegionOps exynos4210_mct_ops = {
-    .read = exynos4210_mct_read,
-    .write = exynos4210_mct_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* MCT init */
-static int exynos4210_mct_init(SysBusDevice *dev)
-{
-    int i;
-    Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev);
-    QEMUBH *bh[2];
-
-    /* Global timer */
-    bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
-    s->g_timer.ptimer_frc = ptimer_init(bh[0]);
-    memset(&s->g_timer.reg, 0, sizeof(struct gregs));
-
-    /* Local timers */
-    for (i = 0; i < 2; i++) {
-        bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
-        bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
-        s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]);
-        s->l_timer[i].ptimer_frc = ptimer_init(bh[1]);
-        s->l_timer[i].id = i;
-    }
-
-    /* IRQs */
-    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-        sysbus_init_irq(dev, &s->g_timer.irq[i]);
-    }
-    for (i = 0; i < 2; i++) {
-        sysbus_init_irq(dev, &s->l_timer[i].irq);
-    }
-
-    memory_region_init_io(&s->iomem, &exynos4210_mct_ops, s, "exynos4210-mct",
-            MCT_SFR_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_mct_init;
-    dc->reset = exynos4210_mct_reset;
-    dc->vmsd = &vmstate_exynos4210_mct_state;
-}
-
-static const TypeInfo exynos4210_mct_info = {
-    .name          = "exynos4210.mct",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210MCTState),
-    .class_init    = exynos4210_mct_class_init,
-};
-
-static void exynos4210_mct_register_types(void)
-{
-    type_register_static(&exynos4210_mct_info);
-}
-
-type_init(exynos4210_mct_register_types)
diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c
deleted file mode 100644 (file)
index 185ccb9..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Samsung exynos4210 Pulse Width Modulation Timer
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/arm/exynos4210.h"
-
-//#define DEBUG_PWM
-
-#ifdef DEBUG_PWM
-#define DPRINTF(fmt, ...) \
-        do { fprintf(stdout, "PWM: [%24s:%5d] " fmt, __func__, __LINE__, \
-                ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define     EXYNOS4210_PWM_TIMERS_NUM      5
-#define     EXYNOS4210_PWM_REG_MEM_SIZE    0x50
-
-#define     TCFG0        0x0000
-#define     TCFG1        0x0004
-#define     TCON         0x0008
-#define     TCNTB0       0x000C
-#define     TCMPB0       0x0010
-#define     TCNTO0       0x0014
-#define     TCNTB1       0x0018
-#define     TCMPB1       0x001C
-#define     TCNTO1       0x0020
-#define     TCNTB2       0x0024
-#define     TCMPB2       0x0028
-#define     TCNTO2       0x002C
-#define     TCNTB3       0x0030
-#define     TCMPB3       0x0034
-#define     TCNTO3       0x0038
-#define     TCNTB4       0x003C
-#define     TCNTO4       0x0040
-#define     TINT_CSTAT   0x0044
-
-#define     TCNTB(x)    (0xC * (x))
-#define     TCMPB(x)    (0xC * (x) + 1)
-#define     TCNTO(x)    (0xC * (x) + 2)
-
-#define GET_PRESCALER(reg, x) (((reg) & (0xFF << (8 * (x)))) >> 8 * (x))
-#define GET_DIVIDER(reg, x) (1 << (((reg) & (0xF << (4 * (x)))) >> (4 * (x))))
-
-/*
- * Attention! Timer4 doesn't have OUTPUT_INVERTER,
- * so Auto Reload bit is not accessible by macros!
- */
-#define     TCON_TIMER_BASE(x)          (((x) ? 1 : 0) * 4 + 4 * (x))
-#define     TCON_TIMER_START(x)         (1 << (TCON_TIMER_BASE(x) + 0))
-#define     TCON_TIMER_MANUAL_UPD(x)    (1 << (TCON_TIMER_BASE(x) + 1))
-#define     TCON_TIMER_OUTPUT_INV(x)    (1 << (TCON_TIMER_BASE(x) + 2))
-#define     TCON_TIMER_AUTO_RELOAD(x)   (1 << (TCON_TIMER_BASE(x) + 3))
-#define     TCON_TIMER4_AUTO_RELOAD     (1 << 22)
-
-#define     TINT_CSTAT_STATUS(x)        (1 << (5 + (x)))
-#define     TINT_CSTAT_ENABLE(x)        (1 << (x))
-
-/* timer struct */
-typedef struct {
-    uint32_t    id;             /* timer id */
-    qemu_irq    irq;            /* local timer irq */
-    uint32_t    freq;           /* timer frequency */
-
-    /* use ptimer.c to represent count down timer */
-    ptimer_state *ptimer;       /* timer  */
-
-    /* registers */
-    uint32_t    reg_tcntb;      /* counter register buffer */
-    uint32_t    reg_tcmpb;      /* compare register buffer */
-
-    struct Exynos4210PWMState *parent;
-
-} Exynos4210PWM;
-
-
-typedef struct Exynos4210PWMState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    uint32_t    reg_tcfg[2];
-    uint32_t    reg_tcon;
-    uint32_t    reg_tint_cstat;
-
-    Exynos4210PWM timer[EXYNOS4210_PWM_TIMERS_NUM];
-
-} Exynos4210PWMState;
-
-/*** VMState ***/
-static const VMStateDescription vmstate_exynos4210_pwm = {
-    .name = "exynos4210.pwm.pwm",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(id, Exynos4210PWM),
-        VMSTATE_UINT32(freq, Exynos4210PWM),
-        VMSTATE_PTIMER(ptimer, Exynos4210PWM),
-        VMSTATE_UINT32(reg_tcntb, Exynos4210PWM),
-        VMSTATE_UINT32(reg_tcmpb, Exynos4210PWM),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_exynos4210_pwm_state = {
-    .name = "exynos4210.pwm",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2),
-        VMSTATE_UINT32(reg_tcon, Exynos4210PWMState),
-        VMSTATE_UINT32(reg_tint_cstat, Exynos4210PWMState),
-        VMSTATE_STRUCT_ARRAY(timer, Exynos4210PWMState,
-            EXYNOS4210_PWM_TIMERS_NUM, 0,
-        vmstate_exynos4210_pwm, Exynos4210PWM),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/*
- * PWM update frequency
- */
-static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id)
-{
-    uint32_t freq;
-    freq = s->timer[id].freq;
-    if (id > 1) {
-        s->timer[id].freq = 24000000 /
-        ((GET_PRESCALER(s->reg_tcfg[0], 1) + 1) *
-                (GET_DIVIDER(s->reg_tcfg[1], id)));
-    } else {
-        s->timer[id].freq = 24000000 /
-        ((GET_PRESCALER(s->reg_tcfg[0], 0) + 1) *
-                (GET_DIVIDER(s->reg_tcfg[1], id)));
-    }
-
-    if (freq != s->timer[id].freq) {
-        ptimer_set_freq(s->timer[id].ptimer, s->timer[id].freq);
-        DPRINTF("freq=%dHz\n", s->timer[id].freq);
-    }
-}
-
-/*
- * Counter tick handler
- */
-static void exynos4210_pwm_tick(void *opaque)
-{
-    Exynos4210PWM *s = (Exynos4210PWM *)opaque;
-    Exynos4210PWMState *p = (Exynos4210PWMState *)s->parent;
-    uint32_t id = s->id;
-    bool cmp;
-
-    DPRINTF("timer %d tick\n", id);
-
-    /* set irq status */
-    p->reg_tint_cstat |= TINT_CSTAT_STATUS(id);
-
-    /* raise IRQ */
-    if (p->reg_tint_cstat & TINT_CSTAT_ENABLE(id)) {
-        DPRINTF("timer %d IRQ\n", id);
-        qemu_irq_raise(p->timer[id].irq);
-    }
-
-    /* reload timer */
-    if (id != 4) {
-        cmp = p->reg_tcon & TCON_TIMER_AUTO_RELOAD(id);
-    } else {
-        cmp = p->reg_tcon & TCON_TIMER4_AUTO_RELOAD;
-    }
-
-    if (cmp) {
-        DPRINTF("auto reload timer %d count to %x\n", id,
-                p->timer[id].reg_tcntb);
-        ptimer_set_count(p->timer[id].ptimer, p->timer[id].reg_tcntb);
-        ptimer_run(p->timer[id].ptimer, 1);
-    } else {
-        /* stop timer, set status to STOP, see Basic Timer Operation */
-        p->reg_tcon &= ~TCON_TIMER_START(id);
-        ptimer_stop(p->timer[id].ptimer);
-    }
-}
-
-/*
- * PWM Read
- */
-static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
-    uint32_t value = 0;
-    int index;
-
-    switch (offset) {
-    case TCFG0: case TCFG1:
-        index = (offset - TCFG0) >> 2;
-        value = s->reg_tcfg[index];
-        break;
-
-    case TCON:
-        value = s->reg_tcon;
-        break;
-
-    case TCNTB0: case TCNTB1:
-    case TCNTB2: case TCNTB3: case TCNTB4:
-        index = (offset - TCNTB0) / 0xC;
-        value = s->timer[index].reg_tcntb;
-        break;
-
-    case TCMPB0: case TCMPB1:
-    case TCMPB2: case TCMPB3:
-        index = (offset - TCMPB0) / 0xC;
-        value = s->timer[index].reg_tcmpb;
-        break;
-
-    case TCNTO0: case TCNTO1:
-    case TCNTO2: case TCNTO3: case TCNTO4:
-        index = (offset == TCNTO4) ? 4 : (offset - TCNTO0) / 0xC;
-        value = ptimer_get_count(s->timer[index].ptimer);
-        break;
-
-    case TINT_CSTAT:
-        value = s->reg_tint_cstat;
-        break;
-
-    default:
-        fprintf(stderr,
-                "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n",
-                offset);
-        break;
-    }
-    return value;
-}
-
-/*
- * PWM Write
- */
-static void exynos4210_pwm_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
-    int index;
-    uint32_t new_val;
-    int i;
-
-    switch (offset) {
-    case TCFG0: case TCFG1:
-        index = (offset - TCFG0) >> 2;
-        s->reg_tcfg[index] = value;
-
-        /* update timers frequencies */
-        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
-            exynos4210_pwm_update_freq(s, s->timer[i].id);
-        }
-        break;
-
-    case TCON:
-        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
-            if ((value & TCON_TIMER_MANUAL_UPD(i)) >
-            (s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) {
-                /*
-                 * TCNTB and TCMPB are loaded into TCNT and TCMP.
-                 * Update timers.
-                 */
-
-                /* this will start timer to run, this ok, because
-                 * during processing start bit timer will be stopped
-                 * if needed */
-                ptimer_set_count(s->timer[i].ptimer, s->timer[i].reg_tcntb);
-                DPRINTF("set timer %d count to %x\n", i,
-                        s->timer[i].reg_tcntb);
-            }
-
-            if ((value & TCON_TIMER_START(i)) >
-            (s->reg_tcon & TCON_TIMER_START(i))) {
-                /* changed to start */
-                ptimer_run(s->timer[i].ptimer, 1);
-                DPRINTF("run timer %d\n", i);
-            }
-
-            if ((value & TCON_TIMER_START(i)) <
-                    (s->reg_tcon & TCON_TIMER_START(i))) {
-                /* changed to stop */
-                ptimer_stop(s->timer[i].ptimer);
-                DPRINTF("stop timer %d\n", i);
-            }
-        }
-        s->reg_tcon = value;
-        break;
-
-    case TCNTB0: case TCNTB1:
-    case TCNTB2: case TCNTB3: case TCNTB4:
-        index = (offset - TCNTB0) / 0xC;
-        s->timer[index].reg_tcntb = value;
-        break;
-
-    case TCMPB0: case TCMPB1:
-    case TCMPB2: case TCMPB3:
-        index = (offset - TCMPB0) / 0xC;
-        s->timer[index].reg_tcmpb = value;
-        break;
-
-    case TINT_CSTAT:
-        new_val = (s->reg_tint_cstat & 0x3E0) + (0x1F & value);
-        new_val &= ~(0x3E0 & value);
-
-        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
-            if ((new_val & TINT_CSTAT_STATUS(i)) <
-                    (s->reg_tint_cstat & TINT_CSTAT_STATUS(i))) {
-                qemu_irq_lower(s->timer[i].irq);
-            }
-        }
-
-        s->reg_tint_cstat = new_val;
-        break;
-
-    default:
-        fprintf(stderr,
-                "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n",
-                offset);
-        break;
-
-    }
-}
-
-/*
- * Set default values to timer fields and registers
- */
-static void exynos4210_pwm_reset(DeviceState *d)
-{
-    Exynos4210PWMState *s = (Exynos4210PWMState *)d;
-    int i;
-    s->reg_tcfg[0] = 0x0101;
-    s->reg_tcfg[1] = 0x0;
-    s->reg_tcon = 0;
-    s->reg_tint_cstat = 0;
-    for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
-        s->timer[i].reg_tcmpb = 0;
-        s->timer[i].reg_tcntb = 0;
-
-        exynos4210_pwm_update_freq(s, s->timer[i].id);
-        ptimer_stop(s->timer[i].ptimer);
-    }
-}
-
-static const MemoryRegionOps exynos4210_pwm_ops = {
-    .read = exynos4210_pwm_read,
-    .write = exynos4210_pwm_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * PWM timer initialization
- */
-static int exynos4210_pwm_init(SysBusDevice *dev)
-{
-    Exynos4210PWMState *s = FROM_SYSBUS(Exynos4210PWMState, dev);
-    int i;
-    QEMUBH *bh;
-
-    for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
-        bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]);
-        sysbus_init_irq(dev, &s->timer[i].irq);
-        s->timer[i].ptimer = ptimer_init(bh);
-        s->timer[i].id = i;
-        s->timer[i].parent = s;
-    }
-
-    memory_region_init_io(&s->iomem, &exynos4210_pwm_ops, s, "exynos4210-pwm",
-            EXYNOS4210_PWM_REG_MEM_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_pwm_init;
-    dc->reset = exynos4210_pwm_reset;
-    dc->vmsd = &vmstate_exynos4210_pwm_state;
-}
-
-static const TypeInfo exynos4210_pwm_info = {
-    .name          = "exynos4210.pwm",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210PWMState),
-    .class_init    = exynos4210_pwm_class_init,
-};
-
-static void exynos4210_pwm_register_types(void)
-{
-    type_register_static(&exynos4210_pwm_info);
-}
-
-type_init(exynos4210_pwm_register_types)
diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c
deleted file mode 100644 (file)
index bceee44..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Samsung exynos4210 Real Time Clock
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *  Ogurtsov Oleg <o.ogurtsov@samsung.com>
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* Description:
- * Register RTCCON:
- *  CLKSEL Bit[1] not used
- *  CLKOUTEN Bit[9] not used
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/arm/exynos4210.h"
-
-#define DEBUG_RTC 0
-
-#if DEBUG_RTC
-#define DPRINTF(fmt, ...) \
-        do { fprintf(stdout, "RTC: [%24s:%5d] " fmt, __func__, __LINE__, \
-                ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define     EXYNOS4210_RTC_REG_MEM_SIZE     0x0100
-
-#define     INTP            0x0030
-#define     RTCCON          0x0040
-#define     TICCNT          0x0044
-#define     RTCALM          0x0050
-#define     ALMSEC          0x0054
-#define     ALMMIN          0x0058
-#define     ALMHOUR         0x005C
-#define     ALMDAY          0x0060
-#define     ALMMON          0x0064
-#define     ALMYEAR         0x0068
-#define     BCDSEC          0x0070
-#define     BCDMIN          0x0074
-#define     BCDHOUR         0x0078
-#define     BCDDAY          0x007C
-#define     BCDDAYWEEK      0x0080
-#define     BCDMON          0x0084
-#define     BCDYEAR         0x0088
-#define     CURTICNT        0x0090
-
-#define     TICK_TIMER_ENABLE   0x0100
-#define     TICNT_THRESHHOLD    2
-
-
-#define     RTC_ENABLE          0x0001
-
-#define     INTP_TICK_ENABLE    0x0001
-#define     INTP_ALM_ENABLE     0x0002
-
-#define     ALARM_INT_ENABLE    0x0040
-
-#define     RTC_BASE_FREQ       32768
-
-typedef struct Exynos4210RTCState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    /* registers */
-    uint32_t    reg_intp;
-    uint32_t    reg_rtccon;
-    uint32_t    reg_ticcnt;
-    uint32_t    reg_rtcalm;
-    uint32_t    reg_almsec;
-    uint32_t    reg_almmin;
-    uint32_t    reg_almhour;
-    uint32_t    reg_almday;
-    uint32_t    reg_almmon;
-    uint32_t    reg_almyear;
-    uint32_t    reg_curticcnt;
-
-    ptimer_state    *ptimer;        /* tick timer */
-    ptimer_state    *ptimer_1Hz;    /* clock timer */
-    uint32_t        freq;
-
-    qemu_irq        tick_irq;   /* Time Tick Generator irq */
-    qemu_irq        alm_irq;    /* alarm irq */
-
-    struct tm   current_tm;     /* current time */
-} Exynos4210RTCState;
-
-#define TICCKSEL(value) ((value & (0x0F << 4)) >> 4)
-
-/*** VMState ***/
-static const VMStateDescription vmstate_exynos4210_rtc_state = {
-    .name = "exynos4210.rtc",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(reg_intp, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_ticcnt, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_rtcalm, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almsec, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almmin, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almhour, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almday, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almmon, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almyear, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_curticcnt, Exynos4210RTCState),
-        VMSTATE_PTIMER(ptimer, Exynos4210RTCState),
-        VMSTATE_PTIMER(ptimer_1Hz, Exynos4210RTCState),
-        VMSTATE_UINT32(freq, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_sec, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_min, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_hour, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_wday, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_mday, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_mon, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_year, Exynos4210RTCState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#define BCD3DIGITS(x) \
-    ((uint32_t)to_bcd((uint8_t)(x % 100)) + \
-    ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8))
-
-static void check_alarm_raise(Exynos4210RTCState *s)
-{
-    unsigned int alarm_raise = 0;
-    struct tm stm = s->current_tm;
-
-    if ((s->reg_rtcalm & 0x01) &&
-        (to_bcd((uint8_t)stm.tm_sec) == (uint8_t)s->reg_almsec)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x02) &&
-        (to_bcd((uint8_t)stm.tm_min) == (uint8_t)s->reg_almmin)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x04) &&
-        (to_bcd((uint8_t)stm.tm_hour) == (uint8_t)s->reg_almhour)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x08) &&
-        (to_bcd((uint8_t)stm.tm_mday) == (uint8_t)s->reg_almday)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x10) &&
-         (to_bcd((uint8_t)stm.tm_mon) == (uint8_t)s->reg_almmon)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x20) &&
-        (BCD3DIGITS(stm.tm_year) == s->reg_almyear)) {
-        alarm_raise = 1;
-    }
-
-    if (alarm_raise) {
-        DPRINTF("ALARM IRQ\n");
-        /* set irq status */
-        s->reg_intp |= INTP_ALM_ENABLE;
-        qemu_irq_raise(s->alm_irq);
-    }
-}
-
-/*
- * RTC update frequency
- * Parameters:
- *     reg_value - current RTCCON register or his new value
- */
-static void exynos4210_rtc_update_freq(Exynos4210RTCState *s,
-                                       uint32_t reg_value)
-{
-    uint32_t freq;
-
-    freq = s->freq;
-    /* set frequncy for time generator */
-    s->freq = RTC_BASE_FREQ / (1 << TICCKSEL(reg_value));
-
-    if (freq != s->freq) {
-        ptimer_set_freq(s->ptimer, s->freq);
-        DPRINTF("freq=%dHz\n", s->freq);
-    }
-}
-
-/* month is between 0 and 11. */
-static int get_days_in_month(int month, int year)
-{
-    static const int days_tab[12] = {
-        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-    };
-    int d;
-    if ((unsigned)month >= 12) {
-        return 31;
-    }
-    d = days_tab[month];
-    if (month == 1) {
-        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
-            d++;
-        }
-    }
-    return d;
-}
-
-/* update 'tm' to the next second */
-static void rtc_next_second(struct tm *tm)
-{
-    int days_in_month;
-
-    tm->tm_sec++;
-    if ((unsigned)tm->tm_sec >= 60) {
-        tm->tm_sec = 0;
-        tm->tm_min++;
-        if ((unsigned)tm->tm_min >= 60) {
-            tm->tm_min = 0;
-            tm->tm_hour++;
-            if ((unsigned)tm->tm_hour >= 24) {
-                tm->tm_hour = 0;
-                /* next day */
-                tm->tm_wday++;
-                if ((unsigned)tm->tm_wday >= 7) {
-                    tm->tm_wday = 0;
-                }
-                days_in_month = get_days_in_month(tm->tm_mon,
-                                                  tm->tm_year + 1900);
-                tm->tm_mday++;
-                if (tm->tm_mday < 1) {
-                    tm->tm_mday = 1;
-                } else if (tm->tm_mday > days_in_month) {
-                    tm->tm_mday = 1;
-                    tm->tm_mon++;
-                    if (tm->tm_mon >= 12) {
-                        tm->tm_mon = 0;
-                        tm->tm_year++;
-                    }
-                }
-            }
-        }
-    }
-}
-
-/*
- * tick handler
- */
-static void exynos4210_rtc_tick(void *opaque)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    DPRINTF("TICK IRQ\n");
-    /* set irq status */
-    s->reg_intp |= INTP_TICK_ENABLE;
-    /* raise IRQ */
-    qemu_irq_raise(s->tick_irq);
-
-    /* restart timer */
-    ptimer_set_count(s->ptimer, s->reg_ticcnt);
-    ptimer_run(s->ptimer, 1);
-}
-
-/*
- * 1Hz clock handler
- */
-static void exynos4210_rtc_1Hz_tick(void *opaque)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    rtc_next_second(&s->current_tm);
-    /* DPRINTF("1Hz tick\n"); */
-
-    /* raise IRQ */
-    if (s->reg_rtcalm & ALARM_INT_ENABLE) {
-        check_alarm_raise(s);
-    }
-
-    ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
-    ptimer_run(s->ptimer_1Hz, 1);
-}
-
-/*
- * RTC Read
- */
-static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    uint32_t value = 0;
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    switch (offset) {
-    case INTP:
-        value = s->reg_intp;
-        break;
-    case RTCCON:
-        value = s->reg_rtccon;
-        break;
-    case TICCNT:
-        value = s->reg_ticcnt;
-        break;
-    case RTCALM:
-        value = s->reg_rtcalm;
-        break;
-    case ALMSEC:
-        value = s->reg_almsec;
-        break;
-    case ALMMIN:
-        value = s->reg_almmin;
-        break;
-    case ALMHOUR:
-        value = s->reg_almhour;
-        break;
-    case ALMDAY:
-        value = s->reg_almday;
-        break;
-    case ALMMON:
-        value = s->reg_almmon;
-        break;
-    case ALMYEAR:
-        value = s->reg_almyear;
-        break;
-
-    case BCDSEC:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_sec);
-        break;
-    case BCDMIN:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_min);
-        break;
-    case BCDHOUR:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_hour);
-        break;
-    case BCDDAYWEEK:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_wday);
-        break;
-    case BCDDAY:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mday);
-        break;
-    case BCDMON:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mon + 1);
-        break;
-    case BCDYEAR:
-        value = BCD3DIGITS(s->current_tm.tm_year);
-        break;
-
-    case CURTICNT:
-        s->reg_curticcnt = ptimer_get_count(s->ptimer);
-        value = s->reg_curticcnt;
-        break;
-
-    default:
-        fprintf(stderr,
-                "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n",
-                offset);
-        break;
-    }
-    return value;
-}
-
-/*
- * RTC Write
- */
-static void exynos4210_rtc_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    switch (offset) {
-    case INTP:
-        if (value & INTP_ALM_ENABLE) {
-            qemu_irq_lower(s->alm_irq);
-            s->reg_intp &= (~INTP_ALM_ENABLE);
-        }
-        if (value & INTP_TICK_ENABLE) {
-            qemu_irq_lower(s->tick_irq);
-            s->reg_intp &= (~INTP_TICK_ENABLE);
-        }
-        break;
-    case RTCCON:
-        if (value & RTC_ENABLE) {
-            exynos4210_rtc_update_freq(s, value);
-        }
-        if ((value & RTC_ENABLE) > (s->reg_rtccon & RTC_ENABLE)) {
-            /* clock timer */
-            ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
-            ptimer_run(s->ptimer_1Hz, 1);
-            DPRINTF("run clock timer\n");
-        }
-        if ((value & RTC_ENABLE) < (s->reg_rtccon & RTC_ENABLE)) {
-            /* tick timer */
-            ptimer_stop(s->ptimer);
-            /* clock timer */
-            ptimer_stop(s->ptimer_1Hz);
-            DPRINTF("stop all timers\n");
-        }
-        if (value & RTC_ENABLE) {
-            if ((value & TICK_TIMER_ENABLE) >
-                (s->reg_rtccon & TICK_TIMER_ENABLE) &&
-                (s->reg_ticcnt)) {
-                ptimer_set_count(s->ptimer, s->reg_ticcnt);
-                ptimer_run(s->ptimer, 1);
-                DPRINTF("run tick timer\n");
-            }
-            if ((value & TICK_TIMER_ENABLE) <
-                (s->reg_rtccon & TICK_TIMER_ENABLE)) {
-                ptimer_stop(s->ptimer);
-            }
-        }
-        s->reg_rtccon = value;
-        break;
-    case TICCNT:
-        if (value > TICNT_THRESHHOLD) {
-            s->reg_ticcnt = value;
-        } else {
-            fprintf(stderr,
-                    "[exynos4210.rtc: bad TICNT value %u ]\n",
-                    (uint32_t)value);
-        }
-        break;
-
-    case RTCALM:
-        s->reg_rtcalm = value;
-        break;
-    case ALMSEC:
-        s->reg_almsec = (value & 0x7f);
-        break;
-    case ALMMIN:
-        s->reg_almmin = (value & 0x7f);
-        break;
-    case ALMHOUR:
-        s->reg_almhour = (value & 0x3f);
-        break;
-    case ALMDAY:
-        s->reg_almday = (value & 0x3f);
-        break;
-    case ALMMON:
-        s->reg_almmon = (value & 0x1f);
-        break;
-    case ALMYEAR:
-        s->reg_almyear = (value & 0x0fff);
-        break;
-
-    case BCDSEC:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_sec = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDMIN:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_min = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDHOUR:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_hour = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDDAYWEEK:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_wday = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDDAY:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_mday = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDMON:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_mon = (int)from_bcd((uint8_t)value) - 1;
-        }
-        break;
-    case BCDYEAR:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            /* 3 digits */
-            s->current_tm.tm_year = (int)from_bcd((uint8_t)value) +
-                    (int)from_bcd((uint8_t)((value >> 8) & 0x0f)) * 100;
-        }
-        break;
-
-    default:
-        fprintf(stderr,
-                "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n",
-                offset);
-        break;
-
-    }
-}
-
-/*
- * Set default values to timer fields and registers
- */
-static void exynos4210_rtc_reset(DeviceState *d)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)d;
-
-    qemu_get_timedate(&s->current_tm, 0);
-
-    DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n",
-            s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday,
-            s->current_tm.tm_hour, s->current_tm.tm_min, s->current_tm.tm_sec);
-
-    s->reg_intp = 0;
-    s->reg_rtccon = 0;
-    s->reg_ticcnt = 0;
-    s->reg_rtcalm = 0;
-    s->reg_almsec = 0;
-    s->reg_almmin = 0;
-    s->reg_almhour = 0;
-    s->reg_almday = 0;
-    s->reg_almmon = 0;
-    s->reg_almyear = 0;
-
-    s->reg_curticcnt = 0;
-
-    exynos4210_rtc_update_freq(s, s->reg_rtccon);
-    ptimer_stop(s->ptimer);
-    ptimer_stop(s->ptimer_1Hz);
-}
-
-static const MemoryRegionOps exynos4210_rtc_ops = {
-    .read = exynos4210_rtc_read,
-    .write = exynos4210_rtc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * RTC timer initialization
- */
-static int exynos4210_rtc_init(SysBusDevice *dev)
-{
-    Exynos4210RTCState *s = FROM_SYSBUS(Exynos4210RTCState, dev);
-    QEMUBH *bh;
-
-    bh = qemu_bh_new(exynos4210_rtc_tick, s);
-    s->ptimer = ptimer_init(bh);
-    ptimer_set_freq(s->ptimer, RTC_BASE_FREQ);
-    exynos4210_rtc_update_freq(s, 0);
-
-    bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
-    s->ptimer_1Hz = ptimer_init(bh);
-    ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
-
-    sysbus_init_irq(dev, &s->alm_irq);
-    sysbus_init_irq(dev, &s->tick_irq);
-
-    memory_region_init_io(&s->iomem, &exynos4210_rtc_ops, s, "exynos4210-rtc",
-            EXYNOS4210_RTC_REG_MEM_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_rtc_init;
-    dc->reset = exynos4210_rtc_reset;
-    dc->vmsd = &vmstate_exynos4210_rtc_state;
-}
-
-static const TypeInfo exynos4210_rtc_info = {
-    .name          = "exynos4210.rtc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210RTCState),
-    .class_init    = exynos4210_rtc_class_init,
-};
-
-static void exynos4210_rtc_register_types(void)
-{
-    type_register_static(&exynos4210_rtc_info);
-}
-
-type_init(exynos4210_rtc_register_types)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
deleted file mode 100644 (file)
index 7043a34..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * QEMU GRLIB GPTimer Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-
-#include "trace.h"
-
-#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
-#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
-
-#define GPTIMER_MAX_TIMERS 8
-
-/* GPTimer Config register fields */
-#define GPTIMER_ENABLE      (1 << 0)
-#define GPTIMER_RESTART     (1 << 1)
-#define GPTIMER_LOAD        (1 << 2)
-#define GPTIMER_INT_ENABLE  (1 << 3)
-#define GPTIMER_INT_PENDING (1 << 4)
-#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
-#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
-
-/* Memory mapped register offsets */
-#define SCALER_OFFSET         0x00
-#define SCALER_RELOAD_OFFSET  0x04
-#define CONFIG_OFFSET         0x08
-#define COUNTER_OFFSET        0x00
-#define COUNTER_RELOAD_OFFSET 0x04
-#define TIMER_BASE            0x10
-
-typedef struct GPTimer     GPTimer;
-typedef struct GPTimerUnit GPTimerUnit;
-
-struct GPTimer {
-    QEMUBH *bh;
-    struct ptimer_state *ptimer;
-
-    qemu_irq     irq;
-    int          id;
-    GPTimerUnit *unit;
-
-    /* registers */
-    uint32_t counter;
-    uint32_t reload;
-    uint32_t config;
-};
-
-struct GPTimerUnit {
-    SysBusDevice  busdev;
-    MemoryRegion iomem;
-
-    uint32_t nr_timers;         /* Number of timers available */
-    uint32_t freq_hz;           /* System frequency */
-    uint32_t irq_line;          /* Base irq line */
-
-    GPTimer *timers;
-
-    /* registers */
-    uint32_t scaler;
-    uint32_t reload;
-    uint32_t config;
-};
-
-static void grlib_gptimer_enable(GPTimer *timer)
-{
-    assert(timer != NULL);
-
-
-    ptimer_stop(timer->ptimer);
-
-    if (!(timer->config & GPTIMER_ENABLE)) {
-        /* Timer disabled */
-        trace_grlib_gptimer_disabled(timer->id, timer->config);
-        return;
-    }
-
-    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
-       underflow. Set count + 1 to simulate the GPTimer behavior. */
-
-    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
-
-    ptimer_set_count(timer->ptimer, timer->counter + 1);
-    ptimer_run(timer->ptimer, 1);
-}
-
-static void grlib_gptimer_restart(GPTimer *timer)
-{
-    assert(timer != NULL);
-
-    trace_grlib_gptimer_restart(timer->id, timer->reload);
-
-    timer->counter = timer->reload;
-    grlib_gptimer_enable(timer);
-}
-
-static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
-{
-    int i = 0;
-    uint32_t value = 0;
-
-    assert(unit != NULL);
-
-    if (scaler > 0) {
-        value = unit->freq_hz / (scaler + 1);
-    } else {
-        value = unit->freq_hz;
-    }
-
-    trace_grlib_gptimer_set_scaler(scaler, value);
-
-    for (i = 0; i < unit->nr_timers; i++) {
-        ptimer_set_freq(unit->timers[i].ptimer, value);
-    }
-}
-
-static void grlib_gptimer_hit(void *opaque)
-{
-    GPTimer *timer = opaque;
-    assert(timer != NULL);
-
-    trace_grlib_gptimer_hit(timer->id);
-
-    /* Timer expired */
-
-    if (timer->config & GPTIMER_INT_ENABLE) {
-        /* Set the pending bit (only unset by write in the config register) */
-        timer->config |= GPTIMER_INT_PENDING;
-        qemu_irq_pulse(timer->irq);
-    }
-
-    if (timer->config & GPTIMER_RESTART) {
-        grlib_gptimer_restart(timer);
-    }
-}
-
-static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    GPTimerUnit        *unit  = opaque;
-    hwaddr  timer_addr;
-    int                 id;
-    uint32_t            value = 0;
-
-    addr &= 0xff;
-
-    /* Unit registers */
-    switch (addr) {
-    case SCALER_OFFSET:
-        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
-        return unit->scaler;
-
-    case SCALER_RELOAD_OFFSET:
-        trace_grlib_gptimer_readl(-1, addr, unit->reload);
-        return unit->reload;
-
-    case CONFIG_OFFSET:
-        trace_grlib_gptimer_readl(-1, addr, unit->config);
-        return unit->config;
-
-    default:
-        break;
-    }
-
-    timer_addr = (addr % TIMER_BASE);
-    id         = (addr - TIMER_BASE) / TIMER_BASE;
-
-    if (id >= 0 && id < unit->nr_timers) {
-
-        /* GPTimer registers */
-        switch (timer_addr) {
-        case COUNTER_OFFSET:
-            value = ptimer_get_count(unit->timers[id].ptimer);
-            trace_grlib_gptimer_readl(id, addr, value);
-            return value;
-
-        case COUNTER_RELOAD_OFFSET:
-            value = unit->timers[id].reload;
-            trace_grlib_gptimer_readl(id, addr, value);
-            return value;
-
-        case CONFIG_OFFSET:
-            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
-            return unit->timers[id].config;
-
-        default:
-            break;
-        }
-
-    }
-
-    trace_grlib_gptimer_readl(-1, addr, 0);
-    return 0;
-}
-
-static void grlib_gptimer_write(void *opaque, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    GPTimerUnit        *unit = opaque;
-    hwaddr  timer_addr;
-    int                 id;
-
-    addr &= 0xff;
-
-    /* Unit registers */
-    switch (addr) {
-    case SCALER_OFFSET:
-        value &= 0xFFFF; /* clean up the value */
-        unit->scaler = value;
-        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
-        return;
-
-    case SCALER_RELOAD_OFFSET:
-        value &= 0xFFFF; /* clean up the value */
-        unit->reload = value;
-        trace_grlib_gptimer_writel(-1, addr, unit->reload);
-        grlib_gptimer_set_scaler(unit, value);
-        return;
-
-    case CONFIG_OFFSET:
-        /* Read Only (disable timer freeze not supported) */
-        trace_grlib_gptimer_writel(-1, addr, 0);
-        return;
-
-    default:
-        break;
-    }
-
-    timer_addr = (addr % TIMER_BASE);
-    id         = (addr - TIMER_BASE) / TIMER_BASE;
-
-    if (id >= 0 && id < unit->nr_timers) {
-
-        /* GPTimer registers */
-        switch (timer_addr) {
-        case COUNTER_OFFSET:
-            trace_grlib_gptimer_writel(id, addr, value);
-            unit->timers[id].counter = value;
-            grlib_gptimer_enable(&unit->timers[id]);
-            return;
-
-        case COUNTER_RELOAD_OFFSET:
-            trace_grlib_gptimer_writel(id, addr, value);
-            unit->timers[id].reload = value;
-            return;
-
-        case CONFIG_OFFSET:
-            trace_grlib_gptimer_writel(id, addr, value);
-
-            if (value & GPTIMER_INT_PENDING) {
-                /* clear pending bit */
-                value &= ~GPTIMER_INT_PENDING;
-            } else {
-                /* keep pending bit */
-                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
-            }
-
-            unit->timers[id].config = value;
-
-            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
-               bits are present, we just have to call restart. */
-
-            if (value & GPTIMER_LOAD) {
-                grlib_gptimer_restart(&unit->timers[id]);
-            } else if (value & GPTIMER_ENABLE) {
-                grlib_gptimer_enable(&unit->timers[id]);
-            }
-
-            /* These fields must always be read as 0 */
-            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
-
-            unit->timers[id].config = value;
-            return;
-
-        default:
-            break;
-        }
-
-    }
-
-    trace_grlib_gptimer_writel(-1, addr, value);
-}
-
-static const MemoryRegionOps grlib_gptimer_ops = {
-    .read = grlib_gptimer_read,
-    .write = grlib_gptimer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void grlib_gptimer_reset(DeviceState *d)
-{
-    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
-    int          i    = 0;
-
-    assert(unit != NULL);
-
-    unit->scaler = 0;
-    unit->reload = 0;
-    unit->config = 0;
-
-    unit->config  = unit->nr_timers;
-    unit->config |= unit->irq_line << 3;
-    unit->config |= 1 << 8;     /* separate interrupt */
-    unit->config |= 1 << 9;     /* Disable timer freeze */
-
-
-    for (i = 0; i < unit->nr_timers; i++) {
-        GPTimer *timer = &unit->timers[i];
-
-        timer->counter = 0;
-        timer->reload = 0;
-        timer->config = 0;
-        ptimer_stop(timer->ptimer);
-        ptimer_set_count(timer->ptimer, 0);
-        ptimer_set_freq(timer->ptimer, unit->freq_hz);
-    }
-}
-
-static int grlib_gptimer_init(SysBusDevice *dev)
-{
-    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
-    unsigned int  i;
-
-    assert(unit->nr_timers > 0);
-    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
-
-    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
-
-    for (i = 0; i < unit->nr_timers; i++) {
-        GPTimer *timer = &unit->timers[i];
-
-        timer->unit   = unit;
-        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
-        timer->ptimer = ptimer_init(timer->bh);
-        timer->id     = i;
-
-        /* One IRQ line for each timer */
-        sysbus_init_irq(dev, &timer->irq);
-
-        ptimer_set_freq(timer->ptimer, unit->freq_hz);
-    }
-
-    memory_region_init_io(&unit->iomem, &grlib_gptimer_ops, unit, "gptimer",
-                          UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
-
-    sysbus_init_mmio(dev, &unit->iomem);
-    return 0;
-}
-
-static Property grlib_gptimer_properties[] = {
-    DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
-    DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
-    DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = grlib_gptimer_init;
-    dc->reset = grlib_gptimer_reset;
-    dc->props = grlib_gptimer_properties;
-}
-
-static const TypeInfo grlib_gptimer_info = {
-    .name          = "grlib,gptimer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(GPTimerUnit),
-    .class_init    = grlib_gptimer_class_init,
-};
-
-static void grlib_gptimer_register_types(void)
-{
-    type_register_static(&grlib_gptimer_info);
-}
-
-type_init(grlib_gptimer_register_types)
diff --git a/hw/imx_timer.c b/hw/imx_timer.c
deleted file mode 100644 (file)
index 03197e3..0000000
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
- * IMX31 Timer
- *
- * Copyright (c) 2008 OK Labs
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- * Updated by Peter Chubb
- *
- * This code is licensed under GPL version 2 or later.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "hw/arm/imx.h"
-
-//#define DEBUG_TIMER 1
-#ifdef DEBUG_TIMER
-#  define DPRINTF(fmt, args...) \
-      do { printf("imx_timer: " fmt , ##args); } while (0)
-#else
-#  define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-#define DEBUG_IMPLEMENTATION 1
-#if DEBUG_IMPLEMENTATION
-#  define IPRINTF(fmt, args...)                                         \
-    do  { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
-#else
-#  define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * GPT : General purpose timer
- *
- * This timer counts up continuously while it is enabled, resetting itself
- * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
- * reaches the value of ocr1 (in periodic mode).  WE simulate this using a
- * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
- * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
- * waiting_rov is set when counting from TIMER_MAX.
- *
- * In the real hardware, there are three comparison registers that can
- * trigger interrupts, and compare channel 1 can be used to
- * force-reset the timer. However, this is a `bare-bones'
- * implementation: only what Linux 3.x uses has been implemented
- * (free-running timer from 0 to OCR1 or TIMER_MAX) .
- */
-
-
-#define TIMER_MAX  0XFFFFFFFFUL
-
-/* Control register.  Not all of these bits have any effect (yet) */
-#define GPT_CR_EN     (1 << 0)  /* GPT Enable */
-#define GPT_CR_ENMOD  (1 << 1)  /* GPT Enable Mode */
-#define GPT_CR_DBGEN  (1 << 2)  /* GPT Debug mode enable */
-#define GPT_CR_WAITEN (1 << 3)  /* GPT Wait Mode Enable  */
-#define GPT_CR_DOZEN  (1 << 4)  /* GPT Doze mode enable */
-#define GPT_CR_STOPEN (1 << 5)  /* GPT Stop Mode Enable */
-#define GPT_CR_CLKSRC_SHIFT (6)
-#define GPT_CR_CLKSRC_MASK  (0x7)
-
-#define GPT_CR_FRR    (1 << 9)  /* Freerun or Restart */
-#define GPT_CR_SWR    (1 << 15) /* Software Reset */
-#define GPT_CR_IM1    (3 << 16) /* Input capture channel 1 mode (2 bits) */
-#define GPT_CR_IM2    (3 << 18) /* Input capture channel 2 mode (2 bits) */
-#define GPT_CR_OM1    (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
-#define GPT_CR_OM2    (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
-#define GPT_CR_OM3    (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
-#define GPT_CR_FO1    (1 << 29) /* Force Output Compare Channel 1 */
-#define GPT_CR_FO2    (1 << 30) /* Force Output Compare Channel 2 */
-#define GPT_CR_FO3    (1 << 31) /* Force Output Compare Channel 3 */
-
-#define GPT_SR_OF1  (1 << 0)
-#define GPT_SR_ROV  (1 << 5)
-
-#define GPT_IR_OF1IE  (1 << 0)
-#define GPT_IR_ROVIE  (1 << 5)
-
-typedef struct {
-    SysBusDevice busdev;
-    ptimer_state *timer;
-    MemoryRegion iomem;
-    DeviceState *ccm;
-
-    uint32_t cr;
-    uint32_t pr;
-    uint32_t sr;
-    uint32_t ir;
-    uint32_t ocr1;
-    uint32_t cnt;
-
-    uint32_t waiting_rov;
-    qemu_irq irq;
-} IMXTimerGState;
-
-static const VMStateDescription vmstate_imx_timerg = {
-    .name = "imx-timerg",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(cr, IMXTimerGState),
-        VMSTATE_UINT32(pr, IMXTimerGState),
-        VMSTATE_UINT32(sr, IMXTimerGState),
-        VMSTATE_UINT32(ir, IMXTimerGState),
-        VMSTATE_UINT32(ocr1, IMXTimerGState),
-        VMSTATE_UINT32(cnt, IMXTimerGState),
-        VMSTATE_UINT32(waiting_rov, IMXTimerGState),
-        VMSTATE_PTIMER(timer, IMXTimerGState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const IMXClk imx_timerg_clocks[] = {
-    NOCLK,    /* 000 No clock source */
-    IPG,      /* 001 ipg_clk, 532MHz*/
-    IPG,      /* 010 ipg_clk_highfreq */
-    NOCLK,    /* 011 not defined */
-    CLK_32k,  /* 100 ipg_clk_32k */
-    NOCLK,    /* 101 not defined */
-    NOCLK,    /* 110 not defined */
-    NOCLK,    /* 111 not defined */
-};
-
-
-static void imx_timerg_set_freq(IMXTimerGState *s)
-{
-    int clksrc;
-    uint32_t freq;
-
-    clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
-    freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
-
-    DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
-    if (freq) {
-        ptimer_set_freq(s->timer, freq);
-    }
-}
-
-static void imx_timerg_update(IMXTimerGState *s)
-{
-    uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
-
-    DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
-            s->sr & GPT_SR_OF1 ? "OF1" : "",
-            s->sr & GPT_SR_ROV ? "ROV" : "",
-            s->ir & GPT_SR_OF1 ? "OF1" : "",
-            s->ir & GPT_SR_ROV ? "ROV" : "",
-            s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
-
-
-    qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
-}
-
-static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
-{
-    uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
-    uint64_t cnt = ptimer_get_count(s->timer);
-    s->cnt = target - cnt;
-    return s->cnt;
-}
-
-static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
-{
-    uint64_t diff_cnt;
-
-    if (!(s->cr & GPT_CR_FRR)) {
-        IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
-        return;
-    }
-
-    /*
-     * For small timeouts, qemu sometimes runs too slow.
-     * Better deliver a late interrupt than none.
-     *
-     * In Reset mode (FRR bit clear)
-     * the ptimer reloads itself from OCR1;
-     * in free-running mode we need to fake
-     * running from 0 to ocr1 to TIMER_MAX
-     */
-    if (timeout > s->cnt) {
-        diff_cnt = timeout - s->cnt;
-    } else {
-        diff_cnt = 0;
-    }
-    ptimer_set_count(s->timer, diff_cnt);
-}
-
-static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXTimerGState *s = (IMXTimerGState *)opaque;
-
-    DPRINTF("g-read(offset=%x)", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* Control Register */
-        DPRINTF(" cr = %x\n", s->cr);
-        return s->cr;
-
-    case 1: /* prescaler */
-        DPRINTF(" pr = %x\n", s->pr);
-        return s->pr;
-
-    case 2: /* Status Register */
-        DPRINTF(" sr = %x\n", s->sr);
-        return s->sr;
-
-    case 3: /* Interrupt Register */
-        DPRINTF(" ir = %x\n", s->ir);
-        return s->ir;
-
-    case 4: /* Output Compare Register 1 */
-        DPRINTF(" ocr1 = %x\n", s->ocr1);
-        return s->ocr1;
-
-
-    case 9: /* cnt */
-        imx_timerg_update_counts(s);
-        DPRINTF(" cnt = %x\n", s->cnt);
-        return s->cnt;
-    }
-
-    IPRINTF("imx_timerg_read: Bad offset %x\n",
-            (int)offset >> 2);
-    return 0;
-}
-
-static void imx_timerg_reset(DeviceState *dev)
-{
-    IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
-
-    /*
-     * Soft reset doesn't touch some bits; hard reset clears them
-     */
-    s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
-    s->sr = 0;
-    s->pr = 0;
-    s->ir = 0;
-    s->cnt = 0;
-    s->ocr1 = TIMER_MAX;
-    ptimer_stop(s->timer);
-    ptimer_set_limit(s->timer, TIMER_MAX, 1);
-    imx_timerg_set_freq(s);
-}
-
-static void imx_timerg_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    IMXTimerGState *s = (IMXTimerGState *)opaque;
-    DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
-            (unsigned int)value);
-
-    switch (offset >> 2) {
-    case 0: {
-        uint32_t oldcr = s->cr;
-        /* CR */
-        if (value & GPT_CR_SWR) { /* force reset */
-            value &= ~GPT_CR_SWR;
-            imx_timerg_reset(&s->busdev.qdev);
-            imx_timerg_update(s);
-        }
-
-        s->cr = value & ~0x7c00;
-        imx_timerg_set_freq(s);
-        if ((oldcr ^ value) & GPT_CR_EN) {
-            if (value & GPT_CR_EN) {
-                if (value & GPT_CR_ENMOD) {
-                    ptimer_set_count(s->timer, s->ocr1);
-                    s->cnt = 0;
-                }
-                ptimer_run(s->timer,
-                           (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
-            } else {
-                ptimer_stop(s->timer);
-            };
-        }
-        return;
-    }
-
-    case 1: /* Prescaler */
-        s->pr = value & 0xfff;
-        imx_timerg_set_freq(s);
-        return;
-
-    case 2: /* SR */
-        /*
-         * No point in implementing the status register bits to do with
-         * external interrupt sources.
-         */
-        value &= GPT_SR_OF1 | GPT_SR_ROV;
-        s->sr &= ~value;
-        imx_timerg_update(s);
-        return;
-
-    case 3: /* IR -- interrupt register */
-        s->ir = value & 0x3f;
-        imx_timerg_update(s);
-        return;
-
-    case 4: /* OCR1 -- output compare register */
-        /* In non-freerun mode, reset count when this register is written */
-        if (!(s->cr & GPT_CR_FRR)) {
-            s->waiting_rov = 0;
-            ptimer_set_limit(s->timer, value, 1);
-        } else {
-            imx_timerg_update_counts(s);
-            if (value > s->cnt) {
-                s->waiting_rov = 0;
-                imx_timerg_reload(s, value);
-            } else {
-                s->waiting_rov = 1;
-                imx_timerg_reload(s, TIMER_MAX - s->cnt);
-            }
-        }
-        s->ocr1 = value;
-        return;
-
-    default:
-        IPRINTF("imx_timerg_write: Bad offset %x\n",
-                (int)offset >> 2);
-    }
-}
-
-static void imx_timerg_timeout(void *opaque)
-{
-    IMXTimerGState *s = (IMXTimerGState *)opaque;
-
-    DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
-    if (s->cr & GPT_CR_FRR) {
-        /*
-         * Free running timer from 0 -> TIMERMAX
-         * Generates interrupt at TIMER_MAX and at cnt==ocr1
-         * If ocr1 == TIMER_MAX, then no need to reload timer.
-         */
-        if (s->ocr1 == TIMER_MAX) {
-            DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
-            s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
-            imx_timerg_update(s);
-            return;
-        }
-
-        if (s->waiting_rov) {
-            /*
-             * We were waiting for cnt==TIMER_MAX
-             */
-            s->sr |= GPT_SR_ROV;
-            s->waiting_rov = 0;
-            s->cnt = 0;
-            imx_timerg_reload(s, s->ocr1);
-        } else {
-            /* Must have got a cnt==ocr1 timeout. */
-            s->sr |= GPT_SR_OF1;
-            s->cnt = s->ocr1;
-            s->waiting_rov = 1;
-            imx_timerg_reload(s, TIMER_MAX);
-        }
-        imx_timerg_update(s);
-        return;
-    }
-
-    s->sr |= GPT_SR_OF1;
-    imx_timerg_update(s);
-}
-
-static const MemoryRegionOps imx_timerg_ops = {
-    .read = imx_timerg_read,
-    .write = imx_timerg_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-
-static int imx_timerg_init(SysBusDevice *dev)
-{
-    IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev);
-    QEMUBH *bh;
-
-    sysbus_init_irq(dev, &s->irq);
-    memory_region_init_io(&s->iomem, &imx_timerg_ops,
-                          s, "imxg-timer",
-                          0x00001000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    bh = qemu_bh_new(imx_timerg_timeout, s);
-    s->timer = ptimer_init(bh);
-
-    /* Hard reset resets extra bits in CR */
-    s->cr = 0;
-    return 0;
-}
-
-
-
-/*
- * EPIT: Enhanced periodic interrupt timer
- */
-
-#define CR_EN       (1 << 0)
-#define CR_ENMOD    (1 << 1)
-#define CR_OCIEN    (1 << 2)
-#define CR_RLD      (1 << 3)
-#define CR_PRESCALE_SHIFT (4)
-#define CR_PRESCALE_MASK  (0xfff)
-#define CR_SWR      (1 << 16)
-#define CR_IOVW     (1 << 17)
-#define CR_DBGEN    (1 << 18)
-#define CR_EPIT     (1 << 19)
-#define CR_DOZEN    (1 << 20)
-#define CR_STOPEN   (1 << 21)
-#define CR_CLKSRC_SHIFT (24)
-#define CR_CLKSRC_MASK  (0x3 << CR_CLKSRC_SHIFT)
-
-
-/*
- * Exact clock frequencies vary from board to board.
- * These are typical.
- */
-static const IMXClk imx_timerp_clocks[] =  {
-    0,        /* disabled */
-    IPG, /* ipg_clk, ~532MHz */
-    IPG, /* ipg_clk_highfreq */
-    CLK_32k,    /* ipg_clk_32k -- ~32kHz */
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    ptimer_state *timer;
-    MemoryRegion iomem;
-    DeviceState *ccm;
-
-    uint32_t cr;
-    uint32_t lr;
-    uint32_t cmp;
-
-    uint32_t freq;
-    int int_level;
-    qemu_irq irq;
-} IMXTimerPState;
-
-/*
- * Update interrupt status
- */
-static void imx_timerp_update(IMXTimerPState *s)
-{
-    if (s->int_level && (s->cr & CR_OCIEN)) {
-        qemu_irq_raise(s->irq);
-    } else {
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static void imx_timerp_reset(DeviceState *dev)
-{
-    IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
-
-    s->cr = 0;
-    s->lr = TIMER_MAX;
-    s->int_level = 0;
-    s->cmp = 0;
-    ptimer_stop(s->timer);
-    ptimer_set_count(s->timer, TIMER_MAX);
-}
-
-static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXTimerPState *s = (IMXTimerPState *)opaque;
-
-    DPRINTF("p-read(offset=%x)", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* Control Register */
-        DPRINTF("cr %x\n", s->cr);
-        return s->cr;
-
-    case 1: /* Status Register */
-        DPRINTF("int_level %x\n", s->int_level);
-        return s->int_level;
-
-    case 2: /* LR - ticks*/
-        DPRINTF("lr %x\n", s->lr);
-        return s->lr;
-
-    case 3: /* CMP */
-        DPRINTF("cmp %x\n", s->cmp);
-        return s->cmp;
-
-    case 4: /* CNT */
-        return ptimer_get_count(s->timer);
-    }
-    IPRINTF("imx_timerp_read: Bad offset %x\n",
-            (int)offset >> 2);
-    return 0;
-}
-
-static void set_timerp_freq(IMXTimerPState *s)
-{
-    int clksrc;
-    unsigned prescaler;
-    uint32_t freq;
-
-    clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
-    prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
-    freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
-
-    s->freq = freq;
-    DPRINTF("Setting ptimer frequency to %u\n", freq);
-
-    if (freq) {
-        ptimer_set_freq(s->timer, freq);
-    }
-}
-
-static void imx_timerp_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    IMXTimerPState *s = (IMXTimerPState *)opaque;
-    DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
-            (unsigned int)value);
-
-    switch (offset >> 2) {
-    case 0: /* CR */
-        if (value & CR_SWR) {
-            imx_timerp_reset(&s->busdev.qdev);
-            value &= ~CR_SWR;
-        }
-        s->cr = value & 0x03ffffff;
-        set_timerp_freq(s);
-
-        if (s->freq && (s->cr & CR_EN)) {
-            if (!(s->cr & CR_ENMOD)) {
-                ptimer_set_count(s->timer, s->lr);
-            }
-            ptimer_run(s->timer, 0);
-        } else {
-            ptimer_stop(s->timer);
-        }
-        break;
-
-    case 1: /* SR - ACK*/
-        s->int_level = 0;
-        imx_timerp_update(s);
-        break;
-
-    case 2: /* LR - set ticks */
-        s->lr = value;
-        ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW));
-        break;
-
-    case 3: /* CMP */
-        s->cmp = value;
-        if (value) {
-            IPRINTF(
-                "Values for EPIT comparison other than zero not supported\n"
-            );
-        }
-        break;
-
-    default:
-        IPRINTF("imx_timerp_write: Bad offset %x\n",
-                   (int)offset >> 2);
-    }
-}
-
-static void imx_timerp_tick(void *opaque)
-{
-    IMXTimerPState *s = (IMXTimerPState *)opaque;
-
-   DPRINTF("imxp tick\n");
-    if (!(s->cr & CR_RLD)) {
-        ptimer_set_count(s->timer, TIMER_MAX);
-    }
-    s->int_level = 1;
-    imx_timerp_update(s);
-}
-
-void imx_timerp_create(const hwaddr addr,
-                              qemu_irq irq,
-                              DeviceState *ccm)
-{
-    IMXTimerPState *pp;
-    DeviceState *dev;
-
-    dev = sysbus_create_simple("imx_timerp", addr, irq);
-    pp = container_of(dev, IMXTimerPState, busdev.qdev);
-    pp->ccm = ccm;
-}
-
-static const MemoryRegionOps imx_timerp_ops = {
-  .read = imx_timerp_read,
-  .write = imx_timerp_write,
-  .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_imx_timerp = {
-    .name = "imx-timerp",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(cr, IMXTimerPState),
-        VMSTATE_UINT32(lr, IMXTimerPState),
-        VMSTATE_UINT32(cmp, IMXTimerPState),
-        VMSTATE_UINT32(freq, IMXTimerPState),
-        VMSTATE_INT32(int_level, IMXTimerPState),
-        VMSTATE_PTIMER(timer, IMXTimerPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int imx_timerp_init(SysBusDevice *dev)
-{
-    IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
-    QEMUBH *bh;
-
-    DPRINTF("imx_timerp_init\n");
-
-    sysbus_init_irq(dev, &s->irq);
-    memory_region_init_io(&s->iomem, &imx_timerp_ops,
-                          s, "imxp-timer",
-                          0x00001000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    bh = qemu_bh_new(imx_timerp_tick, s);
-    s->timer = ptimer_init(bh);
-
-    return 0;
-}
-
-
-void imx_timerg_create(const hwaddr addr,
-                              qemu_irq irq,
-                              DeviceState *ccm)
-{
-    IMXTimerGState *pp;
-    DeviceState *dev;
-
-    dev = sysbus_create_simple("imx_timerg", addr, irq);
-    pp = container_of(dev, IMXTimerGState, busdev.qdev);
-    pp->ccm = ccm;
-}
-
-static void imx_timerg_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc  = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = imx_timerg_init;
-    dc->vmsd = &vmstate_imx_timerg;
-    dc->reset = imx_timerg_reset;
-    dc->desc = "i.MX general timer";
-}
-
-static void imx_timerp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc  = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = imx_timerp_init;
-    dc->vmsd = &vmstate_imx_timerp;
-    dc->reset = imx_timerp_reset;
-    dc->desc = "i.MX periodic timer";
-}
-
-static const TypeInfo imx_timerp_info = {
-    .name = "imx_timerp",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXTimerPState),
-    .class_init = imx_timerp_class_init,
-};
-
-static const TypeInfo imx_timerg_info = {
-    .name = "imx_timerg",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXTimerGState),
-    .class_init = imx_timerg_class_init,
-};
-
-static void imx_timer_register_types(void)
-{
-    type_register_static(&imx_timerp_info);
-    type_register_static(&imx_timerg_info);
-}
-
-type_init(imx_timer_register_types)
index 824997e367e11c1ee405a980c2dbaaca3f1ca3ed..e8c80b9de288dd76d501999ad29ac5a3a3173f64 100644 (file)
@@ -7,3 +7,7 @@ common-obj-y += ps2.o
 common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
 common-obj-$(CONFIG_TSC2005) += tsc2005.o
 common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
+
+obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o
+obj-$(CONFIG_TSC210X) += tsc210x.o
diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c
new file mode 100644 (file)
index 0000000..3edab4f
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *  QEMU model of the Milkymist SoftUSB block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "ui/console.h"
+#include "hw/input/hid.h"
+#include "qemu/error-report.h"
+
+enum {
+    R_CTRL = 0,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+#define COMLOC_DEBUG_PRODUCE 0x1000
+#define COMLOC_DEBUG_BASE    0x1001
+#define COMLOC_MEVT_PRODUCE  0x1101
+#define COMLOC_MEVT_BASE     0x1102
+#define COMLOC_KEVT_PRODUCE  0x1142
+#define COMLOC_KEVT_BASE     0x1143
+
+struct MilkymistSoftUsbState {
+    SysBusDevice busdev;
+    HIDState hid_kbd;
+    HIDState hid_mouse;
+
+    MemoryRegion regs_region;
+    MemoryRegion pmem;
+    MemoryRegion dmem;
+    qemu_irq irq;
+
+    void *pmem_ptr;
+    void *dmem_ptr;
+
+    /* device properties */
+    uint32_t pmem_size;
+    uint32_t dmem_size;
+
+    /* device registers */
+    uint32_t regs[R_MAX];
+
+    /* mouse state */
+    uint8_t mouse_hid_buffer[4];
+
+    /* keyboard state */
+    uint8_t kbd_hid_buffer[8];
+};
+typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
+
+static uint64_t softusb_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    MilkymistSoftUsbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_softusb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_softusb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+softusb_write(void *opaque, hwaddr addr, uint64_t value,
+              unsigned size)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    trace_milkymist_softusb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_softusb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps softusb_mmio_ops = {
+    .read = softusb_read,
+    .write = softusb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: read dmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        memset(buf, 0, len);
+        return;
+    }
+
+    memcpy(buf, s->dmem_ptr + offset, len);
+}
+
+static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: write dmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    memcpy(s->dmem_ptr + offset, buf, len);
+}
+
+static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: read pmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        memset(buf, 0, len);
+        return;
+    }
+
+    memcpy(buf, s->pmem_ptr + offset, len);
+}
+
+static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: write pmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    memcpy(s->pmem_ptr + offset, buf, len);
+}
+
+static void softusb_mouse_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_mevt(m);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
+    m = (m + 1) & 0xf;
+    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_kevt(m);
+    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
+    m = (m + 1) & 0x7;
+    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_hid_datain(HIDState *hs)
+{
+    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
+    int len;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
+
+    if (len == 8) {
+        softusb_kbd_changed(s);
+    }
+}
+
+static void softusb_mouse_hid_datain(HIDState *hs)
+{
+    MilkymistSoftUsbState *s =
+            container_of(hs, MilkymistSoftUsbState, hid_mouse);
+    int len;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
+            sizeof(s->mouse_hid_buffer));
+
+    if (len == 4) {
+        softusb_mouse_changed(s);
+    }
+}
+
+static void milkymist_softusb_reset(DeviceState *d)
+{
+    MilkymistSoftUsbState *s =
+            container_of(d, MilkymistSoftUsbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
+    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
+
+    hid_reset(&s->hid_kbd);
+    hid_reset(&s->hid_mouse);
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+}
+
+static int milkymist_softusb_init(SysBusDevice *dev)
+{
+    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
+                          "milkymist-softusb", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    /* register pmem and dmem */
+    memory_region_init_ram(&s->pmem, "milkymist-softusb.pmem",
+                           s->pmem_size);
+    vmstate_register_ram_global(&s->pmem);
+    s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
+    sysbus_init_mmio(dev, &s->pmem);
+    memory_region_init_ram(&s->dmem, "milkymist-softusb.dmem",
+                           s->dmem_size);
+    vmstate_register_ram_global(&s->dmem);
+    s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
+    sysbus_init_mmio(dev, &s->dmem);
+
+    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
+    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_softusb = {
+    .name = "milkymist-softusb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
+        VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
+        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_softusb_properties[] = {
+    DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
+    DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_softusb_init;
+    dc->reset = milkymist_softusb_reset;
+    dc->vmsd = &vmstate_milkymist_softusb;
+    dc->props = milkymist_softusb_properties;
+}
+
+static const TypeInfo milkymist_softusb_info = {
+    .name          = "milkymist-softusb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistSoftUsbState),
+    .class_init    = milkymist_softusb_class_init,
+};
+
+static void milkymist_softusb_register_types(void)
+{
+    type_register_static(&milkymist_softusb_info);
+}
+
+type_init(milkymist_softusb_register_types)
diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c
new file mode 100644 (file)
index 0000000..1fd5f20
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Intel PXA27X Keypad Controller emulation.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc
+ * Written by Armin Kuster <akuster@kama-aina.net>
+ *              or  <Akuster@mvista.com>
+ *
+ * This code is licensed under the GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "hw/hw.h"
+#include "hw/arm/pxa.h"
+#include "ui/console.h"
+
+/*
+ * Keypad
+ */
+#define KPC         0x00    /* Keypad Interface Control register */
+#define KPDK        0x08    /* Keypad Interface Direct Key register */
+#define KPREC       0x10    /* Keypad Interface Rotary Encoder register */
+#define KPMK        0x18    /* Keypad Interface Matrix Key register */
+#define KPAS        0x20    /* Keypad Interface Automatic Scan register */
+#define KPASMKP0    0x28    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 0 */
+#define KPASMKP1    0x30    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 1 */
+#define KPASMKP2    0x38    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 2 */
+#define KPASMKP3    0x40    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 3 */
+#define KPKDI       0x48    /* Keypad Interface Key Debounce Interval
+                                register */
+
+/* Keypad defines */
+#define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
+#define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
+#define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
+#define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
+#define KPC_MS7         (0x1 << 20)  /* Matrix scan line 7 */
+#define KPC_MS6         (0x1 << 19)  /* Matrix scan line 6 */
+#define KPC_MS5         (0x1 << 18)  /* Matrix scan line 5 */
+#define KPC_MS4         (0x1 << 17)  /* Matrix scan line 4 */
+#define KPC_MS3         (0x1 << 16)  /* Matrix scan line 3 */
+#define KPC_MS2         (0x1 << 15)  /* Matrix scan line 2 */
+#define KPC_MS1         (0x1 << 14)  /* Matrix scan line 1 */
+#define KPC_MS0         (0x1 << 13)  /* Matrix scan line 0 */
+#define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
+#define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
+#define KPC_DK_DEB_SEL  (0x1 <<  9)  /* Direct Keypad Debounce Select */
+#define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
+#define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
+#define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
+#define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
+#define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
+#define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
+
+#define KPDK_DKP        (0x1 << 31)
+#define KPDK_DK7        (0x1 <<  7)
+#define KPDK_DK6        (0x1 <<  6)
+#define KPDK_DK5        (0x1 <<  5)
+#define KPDK_DK4        (0x1 <<  4)
+#define KPDK_DK3        (0x1 <<  3)
+#define KPDK_DK2        (0x1 <<  2)
+#define KPDK_DK1        (0x1 <<  1)
+#define KPDK_DK0        (0x1 <<  0)
+
+#define KPREC_OF1       (0x1 << 31)
+#define KPREC_UF1       (0x1 << 30)
+#define KPREC_OF0       (0x1 << 15)
+#define KPREC_UF0       (0x1 << 14)
+
+#define KPMK_MKP        (0x1 << 31)
+#define KPAS_SO         (0x1 << 31)
+#define KPASMKPx_SO     (0x1 << 31)
+
+
+#define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
+
+#define PXAKBD_MAXROW   8
+#define PXAKBD_MAXCOL   8
+
+struct PXA2xxKeyPadState {
+    MemoryRegion iomem;
+    qemu_irq    irq;
+    struct  keymap *map;
+    int         pressed_cnt;
+    int         alt_code;
+
+    uint32_t    kpc;
+    uint32_t    kpdk;
+    uint32_t    kprec;
+    uint32_t    kpmk;
+    uint32_t    kpas;
+    uint32_t    kpasmkp[4];
+    uint32_t    kpkdi;
+};
+
+static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
+{
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+        *col = i * 2;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << *row))
+                return;
+        }
+        *col = i * 2 + 1;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << (*row + 16)))
+                return;
+        }
+    }
+}
+
+static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
+{
+    int row, col, rel, assert_irq = 0;
+    uint32_t val;
+
+    if (keycode == 0xe0) {
+        kp->alt_code = 1;
+        return;
+    }
+
+    if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
+        return;
+
+    rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
+    keycode &= ~0x80; /* strip qemu key release bit */
+    if (kp->alt_code) {
+        keycode |= 0x80;
+        kp->alt_code = 0;
+    }
+
+    row = kp->map[keycode].row;
+    col = kp->map[keycode].column;
+    if (row == -1 || col == -1) {
+        return;
+    }
+
+    val = KPASMKPx_MKC(row, col);
+    if (rel) {
+        if (kp->kpasmkp[col / 2] & val) {
+            kp->kpasmkp[col / 2] &= ~val;
+            kp->pressed_cnt--;
+            assert_irq = 1;
+        }
+    } else {
+        if (!(kp->kpasmkp[col / 2] & val)) {
+            kp->kpasmkp[col / 2] |= val;
+            kp->pressed_cnt++;
+            assert_irq = 1;
+        }
+    }
+    kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
+    if (kp->pressed_cnt == 1) {
+        kp->kpas &= ~((0xf << 4) | 0xf);
+        if (rel) {
+            pxa27x_keypad_find_pressed_key(kp, &row, &col);
+        }
+        kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
+    }
+
+    if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
+        assert_irq = 0;
+
+    if (assert_irq && (kp->kpc & KPC_MIE)) {
+        kp->kpc |= KPC_MI;
+        qemu_irq_raise(kp->irq);
+    }
+}
+
+static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
+    uint32_t tmp;
+
+    switch (offset) {
+    case KPC:
+        tmp = s->kpc;
+        if(tmp & KPC_MI)
+            s->kpc &= ~(KPC_MI);
+        if(tmp & KPC_DI)
+            s->kpc &= ~(KPC_DI);
+        qemu_irq_lower(s->irq);
+        return tmp;
+        break;
+    case KPDK:
+        return s->kpdk;
+        break;
+    case KPREC:
+        tmp = s->kprec;
+        if(tmp & KPREC_OF1)
+            s->kprec &= ~(KPREC_OF1);
+        if(tmp & KPREC_UF1)
+            s->kprec &= ~(KPREC_UF1);
+        if(tmp & KPREC_OF0)
+            s->kprec &= ~(KPREC_OF0);
+        if(tmp & KPREC_UF0)
+            s->kprec &= ~(KPREC_UF0);
+        return tmp;
+        break;
+    case KPMK:
+        tmp = s->kpmk;
+        if(tmp & KPMK_MKP)
+            s->kpmk &= ~(KPMK_MKP);
+        return tmp;
+        break;
+    case KPAS:
+        return s->kpas;
+        break;
+    case KPASMKP0:
+        return s->kpasmkp[0];
+        break;
+    case KPASMKP1:
+        return s->kpasmkp[1];
+        break;
+    case KPASMKP2:
+        return s->kpasmkp[2];
+        break;
+    case KPASMKP3:
+        return s->kpasmkp[3];
+        break;
+    case KPKDI:
+        return s->kpkdi;
+        break;
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
+
+    switch (offset) {
+    case KPC:
+        s->kpc = value;
+        if (s->kpc & KPC_AS) {
+            s->kpc &= ~(KPC_AS);
+        }
+        break;
+    case KPDK:
+        s->kpdk = value;
+        break;
+    case KPREC:
+        s->kprec = value;
+        break;
+    case KPMK:
+        s->kpmk = value;
+        break;
+    case KPAS:
+        s->kpas = value;
+        break;
+    case KPASMKP0:
+        s->kpasmkp[0] = value;
+        break;
+    case KPASMKP1:
+        s->kpasmkp[1] = value;
+        break;
+    case KPASMKP2:
+        s->kpasmkp[2] = value;
+        break;
+    case KPASMKP3:
+        s->kpasmkp[3] = value;
+        break;
+    case KPKDI:
+        s->kpkdi = value;
+        break;
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_keypad_ops = {
+    .read = pxa2xx_keypad_read,
+    .write = pxa2xx_keypad_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_pxa2xx_keypad = {
+    .name = "pxa2xx_keypad",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
+        VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
+        VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
+                                      hwaddr base,
+                                      qemu_irq irq)
+{
+    PXA2xxKeyPadState *s;
+
+    s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
+    s->irq = irq;
+
+    memory_region_init_io(&s->iomem, &pxa2xx_keypad_ops, s,
+                          "pxa2xx-keypad", 0x00100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
+
+    return s;
+}
+
+void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
+        int size)
+{
+    if(!map || size < 0x80) {
+        fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
+        exit(-1);
+    }
+
+    kp->map = map;
+    qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
+}
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
new file mode 100644 (file)
index 0000000..e6c217c
--- /dev/null
@@ -0,0 +1,1293 @@
+/*
+ * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
+ * TI TSC2301 (touchscreen/sensors/keypad).
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "audio/audio.h"
+#include "qemu/timer.h"
+#include "ui/console.h"
+#include "hw/arm/omap.h"       /* For I2SCodec and uWireSlave */
+#include "hw/arm/devices.h"
+
+#define TSC_DATA_REGISTERS_PAGE                0x0
+#define TSC_CONTROL_REGISTERS_PAGE     0x1
+#define TSC_AUDIO_REGISTERS_PAGE       0x2
+
+#define TSC_VERBOSE
+
+#define TSC_CUT_RESOLUTION(value, p)   ((value) >> (16 - resolution[p]))
+
+typedef struct {
+    qemu_irq pint;
+    qemu_irq kbint;
+    qemu_irq davint;
+    QEMUTimer *timer;
+    QEMUSoundCard card;
+    uWireSlave chip;
+    I2SCodec codec;
+    uint8_t in_fifo[16384];
+    uint8_t out_fifo[16384];
+    uint16_t model;
+
+    int x, y;
+    int pressure;
+
+    int state, page, offset, irq;
+    uint16_t command, dav;
+
+    int busy;
+    int enabled;
+    int host_mode;
+    int function;
+    int nextfunction;
+    int precision;
+    int nextprecision;
+    int filter;
+    int pin_func;
+    int ref;
+    int timing;
+    int noise;
+
+    uint16_t audio_ctrl1;
+    uint16_t audio_ctrl2;
+    uint16_t audio_ctrl3;
+    uint16_t pll[3];
+    uint16_t volume;
+    int64_t volume_change;
+    int softstep;
+    uint16_t dac_power;
+    int64_t powerdown;
+    uint16_t filter_data[0x14];
+
+    const char *name;
+    SWVoiceIn *adc_voice[1];
+    SWVoiceOut *dac_voice[1];
+    int i2s_rx_rate;
+    int i2s_tx_rate;
+
+    int tr[8];
+
+    struct {
+        uint16_t down;
+        uint16_t mask;
+        int scan;
+        int debounce;
+        int mode;
+        int intr;
+    } kb;
+} TSC210xState;
+
+static const int resolution[4] = { 12, 8, 10, 12 };
+
+#define TSC_MODE_NO_SCAN       0x0
+#define TSC_MODE_XY_SCAN       0x1
+#define TSC_MODE_XYZ_SCAN      0x2
+#define TSC_MODE_X             0x3
+#define TSC_MODE_Y             0x4
+#define TSC_MODE_Z             0x5
+#define TSC_MODE_BAT1          0x6
+#define TSC_MODE_BAT2          0x7
+#define TSC_MODE_AUX           0x8
+#define TSC_MODE_AUX_SCAN      0x9
+#define TSC_MODE_TEMP1         0xa
+#define TSC_MODE_PORT_SCAN     0xb
+#define TSC_MODE_TEMP2         0xc
+#define TSC_MODE_XX_DRV                0xd
+#define TSC_MODE_YY_DRV                0xe
+#define TSC_MODE_YX_DRV                0xf
+
+static const uint16_t mode_regs[16] = {
+    0x0000,    /* No scan */
+    0x0600,    /* X, Y scan */
+    0x0780,    /* X, Y, Z scan */
+    0x0400,    /* X */
+    0x0200,    /* Y */
+    0x0180,    /* Z */
+    0x0040,    /* BAT1 */
+    0x0030,    /* BAT2 */
+    0x0010,    /* AUX */
+    0x0010,    /* AUX scan */
+    0x0004,    /* TEMP1 */
+    0x0070,    /* Port scan */
+    0x0002,    /* TEMP2 */
+    0x0000,    /* X+, X- drivers */
+    0x0000,    /* Y+, Y- drivers */
+    0x0000,    /* Y+, X- drivers */
+};
+
+#define X_TRANSFORM(s)                 \
+    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
+#define Y_TRANSFORM(s)                 \
+    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
+#define Z1_TRANSFORM(s)                        \
+    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
+#define Z2_TRANSFORM(s)                        \
+    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+
+#define BAT1_VAL                       0x8660
+#define BAT2_VAL                       0x0000
+#define AUX1_VAL                       0x35c0
+#define AUX2_VAL                       0xffff
+#define TEMP1_VAL                      0x8c70
+#define TEMP2_VAL                      0xa5b0
+
+#define TSC_POWEROFF_DELAY             50
+#define TSC_SOFTSTEP_DELAY             50
+
+static void tsc210x_reset(TSC210xState *s)
+{
+    s->state = 0;
+    s->pin_func = 2;
+    s->enabled = 0;
+    s->busy = 0;
+    s->nextfunction = 0;
+    s->ref = 0;
+    s->timing = 0;
+    s->irq = 0;
+    s->dav = 0;
+
+    s->audio_ctrl1 = 0x0000;
+    s->audio_ctrl2 = 0x4410;
+    s->audio_ctrl3 = 0x0000;
+    s->pll[0] = 0x1004;
+    s->pll[1] = 0x0000;
+    s->pll[2] = 0x1fff;
+    s->volume = 0xffff;
+    s->dac_power = 0x8540;
+    s->softstep = 1;
+    s->volume_change = 0;
+    s->powerdown = 0;
+    s->filter_data[0x00] = 0x6be3;
+    s->filter_data[0x01] = 0x9666;
+    s->filter_data[0x02] = 0x675d;
+    s->filter_data[0x03] = 0x6be3;
+    s->filter_data[0x04] = 0x9666;
+    s->filter_data[0x05] = 0x675d;
+    s->filter_data[0x06] = 0x7d83;
+    s->filter_data[0x07] = 0x84ee;
+    s->filter_data[0x08] = 0x7d83;
+    s->filter_data[0x09] = 0x84ee;
+    s->filter_data[0x0a] = 0x6be3;
+    s->filter_data[0x0b] = 0x9666;
+    s->filter_data[0x0c] = 0x675d;
+    s->filter_data[0x0d] = 0x6be3;
+    s->filter_data[0x0e] = 0x9666;
+    s->filter_data[0x0f] = 0x675d;
+    s->filter_data[0x10] = 0x7d83;
+    s->filter_data[0x11] = 0x84ee;
+    s->filter_data[0x12] = 0x7d83;
+    s->filter_data[0x13] = 0x84ee;
+
+    s->i2s_tx_rate = 0;
+    s->i2s_rx_rate = 0;
+
+    s->kb.scan = 1;
+    s->kb.debounce = 0;
+    s->kb.mask = 0x0000;
+    s->kb.mode = 3;
+    s->kb.intr = 0;
+
+    qemu_set_irq(s->pint, !s->irq);
+    qemu_set_irq(s->davint, !s->dav);
+    qemu_irq_raise(s->kbint);
+}
+
+typedef struct {
+    int rate;
+    int dsor;
+    int fsref;
+} TSC210xRateInfo;
+
+/*  { rate,  dsor,  fsref } */
+static const TSC210xRateInfo tsc2101_rates[] = {
+    /* Fsref / 6.0 */
+    { 7350,    7,      1 },
+    { 8000,    7,      0 },
+    /* Fsref / 5.5 */
+    { 8018,    6,      1 },
+    { 8727,    6,      0 },
+    /* Fsref / 5.0 */
+    { 8820,    5,      1 },
+    { 9600,    5,      0 },
+    /* Fsref / 4.0 */
+    { 11025,   4,      1 },
+    { 12000,   4,      0 },
+    /* Fsref / 3.0 */
+    { 14700,   3,      1 },
+    { 16000,   3,      0 },
+    /* Fsref / 2.0 */
+    { 22050,   2,      1 },
+    { 24000,   2,      0 },
+    /* Fsref / 1.5 */
+    { 29400,   1,      1 },
+    { 32000,   1,      0 },
+    /* Fsref */
+    { 44100,   0,      1 },
+    { 48000,   0,      0 },
+
+    { 0,       0,      0 },
+};
+
+/*  { rate,   dsor, fsref }    */
+static const TSC210xRateInfo tsc2102_rates[] = {
+    /* Fsref / 6.0 */
+    { 7350,    63,     1 },
+    { 8000,    63,     0 },
+    /* Fsref / 6.0 */
+    { 7350,    54,     1 },
+    { 8000,    54,     0 },
+    /* Fsref / 5.0 */
+    { 8820,    45,     1 },
+    { 9600,    45,     0 },
+    /* Fsref / 4.0 */
+    { 11025,   36,     1 },
+    { 12000,   36,     0 },
+    /* Fsref / 3.0 */
+    { 14700,   27,     1 },
+    { 16000,   27,     0 },
+    /* Fsref / 2.0 */
+    { 22050,   18,     1 },
+    { 24000,   18,     0 },
+    /* Fsref / 1.5 */
+    { 29400,   9,      1 },
+    { 32000,   9,      0 },
+    /* Fsref */
+    { 44100,   0,      1 },
+    { 48000,   0,      0 },
+
+    { 0,       0,      0 },
+};
+
+static inline void tsc210x_out_flush(TSC210xState *s, int len)
+{
+    uint8_t *data = s->codec.out.fifo + s->codec.out.start;
+    uint8_t *end = data + len;
+
+    while (data < end)
+        data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
+
+    s->codec.out.len -= len;
+    if (s->codec.out.len)
+        memmove(s->codec.out.fifo, end, s->codec.out.len);
+    s->codec.out.start = 0;
+}
+
+static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
+{
+    if (s->codec.out.len >= free_b) {
+        tsc210x_out_flush(s, free_b);
+        return;
+    }
+
+    s->codec.out.size = MIN(free_b, 16384);
+    qemu_irq_raise(s->codec.tx_start);
+}
+
+static void tsc2102_audio_rate_update(TSC210xState *s)
+{
+    const TSC210xRateInfo *rate;
+
+    s->codec.tx_rate = 0;
+    s->codec.rx_rate = 0;
+    if (s->dac_power & (1 << 15))                              /* PWDNC */
+        return;
+
+    for (rate = tsc2102_rates; rate->rate; rate ++)
+        if (rate->dsor == (s->audio_ctrl1 & 0x3f) &&           /* DACFS */
+                        rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
+            break;
+    if (!rate->rate) {
+        printf("%s: unknown sampling rate configured\n", __FUNCTION__);
+        return;
+    }
+
+    s->codec.tx_rate = rate->rate;
+}
+
+static void tsc2102_audio_output_update(TSC210xState *s)
+{
+    int enable;
+    struct audsettings fmt;
+
+    if (s->dac_voice[0]) {
+        tsc210x_out_flush(s, s->codec.out.len);
+        s->codec.out.size = 0;
+        AUD_set_active_out(s->dac_voice[0], 0);
+        AUD_close_out(&s->card, s->dac_voice[0]);
+        s->dac_voice[0] = NULL;
+    }
+    s->codec.cts = 0;
+
+    enable =
+            (~s->dac_power & (1 << 15)) &&                     /* PWDNC */
+            (~s->dac_power & (1 << 10));                       /* DAPWDN */
+    if (!enable || !s->codec.tx_rate)
+        return;
+
+    /* Force our own sampling rate even in slave DAC mode */
+    fmt.endianness = 0;
+    fmt.nchannels = 2;
+    fmt.freq = s->codec.tx_rate;
+    fmt.fmt = AUD_FMT_S16;
+
+    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
+                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
+    if (s->dac_voice[0]) {
+        s->codec.cts = 1;
+        AUD_set_active_out(s->dac_voice[0], 1);
+    }
+}
+
+static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
+{
+    switch (reg) {
+    case 0x00: /* X */
+        s->dav &= 0xfbff;
+        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
+                (s->noise & 3);
+
+    case 0x01: /* Y */
+        s->noise ++;
+        s->dav &= 0xfdff;
+        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
+                (s->noise & 3);
+
+    case 0x02: /* Z1 */
+        s->dav &= 0xfeff;
+        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
+                (s->noise & 3);
+
+    case 0x03: /* Z2 */
+        s->dav &= 0xff7f;
+        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
+                (s->noise & 3);
+
+    case 0x04: /* KPData */
+        if ((s->model & 0xff00) == 0x2300) {
+            if (s->kb.intr && (s->kb.mode & 2)) {
+                s->kb.intr = 0;
+                qemu_irq_raise(s->kbint);
+            }
+            return s->kb.down;
+        }
+
+        return 0xffff;
+
+    case 0x05: /* BAT1 */
+        s->dav &= 0xffbf;
+        return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
+                (s->noise & 6);
+
+    case 0x06: /* BAT2 */
+        s->dav &= 0xffdf;
+        return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
+
+    case 0x07: /* AUX1 */
+        s->dav &= 0xffef;
+        return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
+
+    case 0x08: /* AUX2 */
+        s->dav &= 0xfff7;
+        return 0xffff;
+
+    case 0x09: /* TEMP1 */
+        s->dav &= 0xfffb;
+        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
+                (s->noise & 5);
+
+    case 0x0a: /* TEMP2 */
+        s->dav &= 0xfffd;
+        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
+                (s->noise & 3);
+
+    case 0x0b: /* DAC */
+        s->dav &= 0xfffe;
+        return 0xffff;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_data_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static uint16_t tsc2102_control_register_read(
+                TSC210xState *s, int reg)
+{
+    switch (reg) {
+    case 0x00: /* TSC ADC */
+        return (s->pressure << 15) | ((!s->busy) << 14) |
+                (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; 
+
+    case 0x01: /* Status / Keypad Control */
+        if ((s->model & 0xff00) == 0x2100)
+            return (s->pin_func << 14) | ((!s->enabled) << 13) |
+                    (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
+        else
+            return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
+                    (s->kb.debounce << 11);
+
+    case 0x02: /* DAC Control */
+        if ((s->model & 0xff00) == 0x2300)
+            return s->dac_power & 0x8000;
+        else
+            goto bad_reg;
+
+    case 0x03: /* Reference */
+        return s->ref;
+
+    case 0x04: /* Reset */
+        return 0xffff;
+
+    case 0x05: /* Configuration */
+        return s->timing;
+
+    case 0x06: /* Secondary configuration */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
+
+    case 0x10: /* Keypad Mask */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        return s->kb.mask;
+
+    default:
+    bad_reg:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_control_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
+{
+    int l_ch, r_ch;
+    uint16_t val;
+
+    switch (reg) {
+    case 0x00: /* Audio Control 1 */
+        return s->audio_ctrl1;
+
+    case 0x01:
+        return 0xff00;
+
+    case 0x02: /* DAC Volume Control */
+        return s->volume;
+
+    case 0x03:
+        return 0x8b00;
+
+    case 0x04: /* Audio Control 2 */
+        l_ch = 1;
+        r_ch = 1;
+        if (s->softstep && !(s->dac_power & (1 << 10))) {
+            l_ch = (qemu_get_clock_ns(vm_clock) >
+                            s->volume_change + TSC_SOFTSTEP_DELAY);
+            r_ch = (qemu_get_clock_ns(vm_clock) >
+                            s->volume_change + TSC_SOFTSTEP_DELAY);
+        }
+
+        return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
+
+    case 0x05: /* Stereo DAC Power Control */
+        return 0x2aa0 | s->dac_power |
+                (((s->dac_power & (1 << 10)) &&
+                  (qemu_get_clock_ns(vm_clock) >
+                   s->powerdown + TSC_POWEROFF_DELAY)) << 6);
+
+    case 0x06: /* Audio Control 3 */
+        val = s->audio_ctrl3 | 0x0001;
+        s->audio_ctrl3 &= 0xff3f;
+        return val;
+
+    case 0x07: /* LCH_BASS_BOOST_N0 */
+    case 0x08: /* LCH_BASS_BOOST_N1 */
+    case 0x09: /* LCH_BASS_BOOST_N2 */
+    case 0x0a: /* LCH_BASS_BOOST_N3 */
+    case 0x0b: /* LCH_BASS_BOOST_N4 */
+    case 0x0c: /* LCH_BASS_BOOST_N5 */
+    case 0x0d: /* LCH_BASS_BOOST_D1 */
+    case 0x0e: /* LCH_BASS_BOOST_D2 */
+    case 0x0f: /* LCH_BASS_BOOST_D4 */
+    case 0x10: /* LCH_BASS_BOOST_D5 */
+    case 0x11: /* RCH_BASS_BOOST_N0 */
+    case 0x12: /* RCH_BASS_BOOST_N1 */
+    case 0x13: /* RCH_BASS_BOOST_N2 */
+    case 0x14: /* RCH_BASS_BOOST_N3 */
+    case 0x15: /* RCH_BASS_BOOST_N4 */
+    case 0x16: /* RCH_BASS_BOOST_N5 */
+    case 0x17: /* RCH_BASS_BOOST_D1 */
+    case 0x18: /* RCH_BASS_BOOST_D2 */
+    case 0x19: /* RCH_BASS_BOOST_D4 */
+    case 0x1a: /* RCH_BASS_BOOST_D5 */
+        return s->filter_data[reg - 0x07];
+
+    case 0x1b: /* PLL Programmability 1 */
+        return s->pll[0];
+
+    case 0x1c: /* PLL Programmability 2 */
+        return s->pll[1];
+
+    case 0x1d: /* Audio Control 4 */
+        return (!s->softstep) << 14;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_audio_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static void tsc2102_data_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* X */
+    case 0x01: /* Y */
+    case 0x02: /* Z1 */
+    case 0x03: /* Z2 */
+    case 0x05: /* BAT1 */
+    case 0x06: /* BAT2 */
+    case 0x07: /* AUX1 */
+    case 0x08: /* AUX2 */
+    case 0x09: /* TEMP1 */
+    case 0x0a: /* TEMP2 */
+        return;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_data_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+static void tsc2102_control_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* TSC ADC */
+        s->host_mode = value >> 15;
+        s->enabled = !(value & 0x4000);
+        if (s->busy && !s->enabled)
+            qemu_del_timer(s->timer);
+        s->busy &= s->enabled;
+        s->nextfunction = (value >> 10) & 0xf;
+        s->nextprecision = (value >> 8) & 3;
+        s->filter = value & 0xff;
+        return;
+
+    case 0x01: /* Status / Keypad Control */
+        if ((s->model & 0xff00) == 0x2100)
+            s->pin_func = value >> 14;
+       else {
+            s->kb.scan = (value >> 14) & 1;
+            s->kb.debounce = (value >> 11) & 7;
+            if (s->kb.intr && s->kb.scan) {
+                s->kb.intr = 0;
+                qemu_irq_raise(s->kbint);
+            }
+        }
+        return;
+
+    case 0x02: /* DAC Control */
+        if ((s->model & 0xff00) == 0x2300) {
+            s->dac_power &= 0x7fff;
+            s->dac_power |= 0x8000 & value;
+        } else
+            goto bad_reg;
+        break;
+
+    case 0x03: /* Reference */
+        s->ref = value & 0x1f;
+        return;
+
+    case 0x04: /* Reset */
+        if (value == 0xbb00) {
+            if (s->busy)
+                qemu_del_timer(s->timer);
+            tsc210x_reset(s);
+#ifdef TSC_VERBOSE
+        } else {
+            fprintf(stderr, "tsc2102_control_register_write: "
+                            "wrong value written into RESET\n");
+#endif
+        }
+        return;
+
+    case 0x05: /* Configuration */
+        s->timing = value & 0x3f;
+#ifdef TSC_VERBOSE
+        if (value & ~0x3f)
+            fprintf(stderr, "tsc2102_control_register_write: "
+                            "wrong value written into CONFIG\n");
+#endif
+        return;
+
+    case 0x06: /* Secondary configuration */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        s->kb.mode = value >> 14;
+        s->pll[2] = value & 0x3ffff;
+        return;
+
+    case 0x10: /* Keypad Mask */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        s->kb.mask = value;
+        return;
+
+    default:
+    bad_reg:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_control_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+static void tsc2102_audio_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* Audio Control 1 */
+        s->audio_ctrl1 = value & 0x0f3f;
+#ifdef TSC_VERBOSE
+        if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 1\n");
+#endif
+        tsc2102_audio_rate_update(s);
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x01:
+#ifdef TSC_VERBOSE
+        if (value != 0xff00)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into reg 0x01\n");
+#endif
+        return;
+
+    case 0x02: /* DAC Volume Control */
+        s->volume = value;
+        s->volume_change = qemu_get_clock_ns(vm_clock);
+        return;
+
+    case 0x03:
+#ifdef TSC_VERBOSE
+        if (value != 0x8b00)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into reg 0x03\n");
+#endif
+        return;
+
+    case 0x04: /* Audio Control 2 */
+        s->audio_ctrl2 = value & 0xf7f2;
+#ifdef TSC_VERBOSE
+        if (value & ~0xf7fd)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 2\n");
+#endif
+        return;
+
+    case 0x05: /* Stereo DAC Power Control */
+        if ((value & ~s->dac_power) & (1 << 10))
+            s->powerdown = qemu_get_clock_ns(vm_clock);
+
+        s->dac_power = value & 0x9543;
+#ifdef TSC_VERBOSE
+        if ((value & ~0x9543) != 0x2aa0)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Power\n");
+#endif
+        tsc2102_audio_rate_update(s);
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x06: /* Audio Control 3 */
+        s->audio_ctrl3 &= 0x00c0;
+        s->audio_ctrl3 |= value & 0xf800;
+#ifdef TSC_VERBOSE
+        if (value & ~0xf8c7)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 3\n");
+#endif
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x07: /* LCH_BASS_BOOST_N0 */
+    case 0x08: /* LCH_BASS_BOOST_N1 */
+    case 0x09: /* LCH_BASS_BOOST_N2 */
+    case 0x0a: /* LCH_BASS_BOOST_N3 */
+    case 0x0b: /* LCH_BASS_BOOST_N4 */
+    case 0x0c: /* LCH_BASS_BOOST_N5 */
+    case 0x0d: /* LCH_BASS_BOOST_D1 */
+    case 0x0e: /* LCH_BASS_BOOST_D2 */
+    case 0x0f: /* LCH_BASS_BOOST_D4 */
+    case 0x10: /* LCH_BASS_BOOST_D5 */
+    case 0x11: /* RCH_BASS_BOOST_N0 */
+    case 0x12: /* RCH_BASS_BOOST_N1 */
+    case 0x13: /* RCH_BASS_BOOST_N2 */
+    case 0x14: /* RCH_BASS_BOOST_N3 */
+    case 0x15: /* RCH_BASS_BOOST_N4 */
+    case 0x16: /* RCH_BASS_BOOST_N5 */
+    case 0x17: /* RCH_BASS_BOOST_D1 */
+    case 0x18: /* RCH_BASS_BOOST_D2 */
+    case 0x19: /* RCH_BASS_BOOST_D4 */
+    case 0x1a: /* RCH_BASS_BOOST_D5 */
+        s->filter_data[reg - 0x07] = value;
+        return;
+
+    case 0x1b: /* PLL Programmability 1 */
+        s->pll[0] = value & 0xfffc;
+#ifdef TSC_VERBOSE
+        if (value & ~0xfffc)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into PLL 1\n");
+#endif
+        return;
+
+    case 0x1c: /* PLL Programmability 2 */
+        s->pll[1] = value & 0xfffc;
+#ifdef TSC_VERBOSE
+        if (value & ~0xfffc)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into PLL 2\n");
+#endif
+        return;
+
+    case 0x1d: /* Audio Control 4 */
+        s->softstep = !(value & 0x4000);
+#ifdef TSC_VERBOSE
+        if (value & ~0x4000)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 4\n");
+#endif
+        return;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_audio_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+/* This handles most of the chip logic.  */
+static void tsc210x_pin_update(TSC210xState *s)
+{
+    int64_t expires;
+    int pin_state;
+
+    switch (s->pin_func) {
+    case 0:
+        pin_state = s->pressure;
+        break;
+    case 1:
+        pin_state = !!s->dav;
+        break;
+    case 2:
+    default:
+        pin_state = s->pressure && !s->dav;
+    }
+
+    if (!s->enabled)
+        pin_state = 0;
+
+    if (pin_state != s->irq) {
+        s->irq = pin_state;
+        qemu_set_irq(s->pint, !s->irq);
+    }
+
+    switch (s->nextfunction) {
+    case TSC_MODE_XY_SCAN:
+    case TSC_MODE_XYZ_SCAN:
+        if (!s->pressure)
+            return;
+        break;
+
+    case TSC_MODE_X:
+    case TSC_MODE_Y:
+    case TSC_MODE_Z:
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_BAT1:
+    case TSC_MODE_BAT2:
+    case TSC_MODE_AUX:
+    case TSC_MODE_TEMP1:
+    case TSC_MODE_TEMP2:
+        if (s->dav)
+            s->enabled = 0;
+        break;
+
+    case TSC_MODE_AUX_SCAN:
+    case TSC_MODE_PORT_SCAN:
+        break;
+
+    case TSC_MODE_NO_SCAN:
+    case TSC_MODE_XX_DRV:
+    case TSC_MODE_YY_DRV:
+    case TSC_MODE_YX_DRV:
+    default:
+        return;
+    }
+
+    if (!s->enabled || s->busy || s->dav)
+        return;
+
+    s->busy = 1;
+    s->precision = s->nextprecision;
+    s->function = s->nextfunction;
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10);
+    qemu_mod_timer(s->timer, expires);
+}
+
+static uint16_t tsc210x_read(TSC210xState *s)
+{
+    uint16_t ret = 0x0000;
+
+    if (!s->command)
+        fprintf(stderr, "tsc210x_read: SPI underrun!\n");
+
+    switch (s->page) {
+    case TSC_DATA_REGISTERS_PAGE:
+        ret = tsc2102_data_register_read(s, s->offset);
+        if (!s->dav)
+            qemu_irq_raise(s->davint);
+        break;
+    case TSC_CONTROL_REGISTERS_PAGE:
+        ret = tsc2102_control_register_read(s, s->offset);
+        break;
+    case TSC_AUDIO_REGISTERS_PAGE:
+        ret = tsc2102_audio_register_read(s, s->offset);
+        break;
+    default:
+        hw_error("tsc210x_read: wrong memory page\n");
+    }
+
+    tsc210x_pin_update(s);
+
+    /* Allow sequential reads.  */
+    s->offset ++;
+    s->state = 0;
+    return ret;
+}
+
+static void tsc210x_write(TSC210xState *s, uint16_t value)
+{
+    /*
+     * This is a two-state state machine for reading
+     * command and data every second time.
+     */
+    if (!s->state) {
+        s->command = value >> 15;
+        s->page = (value >> 11) & 0x0f;
+        s->offset = (value >> 5) & 0x3f;
+        s->state = 1;
+    } else {
+        if (s->command)
+            fprintf(stderr, "tsc210x_write: SPI overrun!\n");
+        else
+            switch (s->page) {
+            case TSC_DATA_REGISTERS_PAGE:
+                tsc2102_data_register_write(s, s->offset, value);
+                break;
+            case TSC_CONTROL_REGISTERS_PAGE:
+                tsc2102_control_register_write(s, s->offset, value);
+                break;
+            case TSC_AUDIO_REGISTERS_PAGE:
+                tsc2102_audio_register_write(s, s->offset, value);
+                break;
+            default:
+                hw_error("tsc210x_write: wrong memory page\n");
+            }
+
+        tsc210x_pin_update(s);
+        s->state = 0;
+    }
+}
+
+uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
+{
+    TSC210xState *s = opaque;
+    uint32_t ret = 0;
+
+    if (len != 16)
+        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
+
+    /* TODO: sequential reads etc - how do we make sure the host doesn't
+     * unintentionally read out a conversion result from a register while
+     * transmitting the command word of the next command?  */
+    if (!value || (s->state && s->command))
+        ret = tsc210x_read(s);
+    if (value || (s->state && !s->command))
+        tsc210x_write(s, value);
+
+    return ret;
+}
+
+static void tsc210x_timer_tick(void *opaque)
+{
+    TSC210xState *s = opaque;
+
+    /* Timer ticked -- a set of conversions has been finished.  */
+
+    if (!s->busy)
+        return;
+
+    s->busy = 0;
+    s->dav |= mode_regs[s->function];
+    tsc210x_pin_update(s);
+    qemu_irq_lower(s->davint);
+}
+
+static void tsc210x_touchscreen_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    TSC210xState *s = opaque;
+    int p = s->pressure;
+
+    if (buttons_state) {
+        s->x = x;
+        s->y = y;
+    }
+    s->pressure = !!buttons_state;
+
+    /*
+     * Note: We would get better responsiveness in the guest by
+     * signaling TS events immediately, but for now we simulate
+     * the first conversion delay for sake of correctness.
+     */
+    if (p != s->pressure)
+        tsc210x_pin_update(s);
+}
+
+static void tsc210x_i2s_swallow(TSC210xState *s)
+{
+    if (s->dac_voice[0])
+        tsc210x_out_flush(s, s->codec.out.len);
+    else
+        s->codec.out.len = 0;
+}
+
+static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
+{
+    s->i2s_tx_rate = out;
+    s->i2s_rx_rate = in;
+}
+
+static void tsc210x_save(QEMUFile *f, void *opaque)
+{
+    TSC210xState *s = (TSC210xState *) opaque;
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    qemu_put_be16(f, s->x);
+    qemu_put_be16(f, s->y);
+    qemu_put_byte(f, s->pressure);
+
+    qemu_put_byte(f, s->state);
+    qemu_put_byte(f, s->page);
+    qemu_put_byte(f, s->offset);
+    qemu_put_byte(f, s->command);
+
+    qemu_put_byte(f, s->irq);
+    qemu_put_be16s(f, &s->dav);
+
+    qemu_put_timer(f, s->timer);
+    qemu_put_byte(f, s->enabled);
+    qemu_put_byte(f, s->host_mode);
+    qemu_put_byte(f, s->function);
+    qemu_put_byte(f, s->nextfunction);
+    qemu_put_byte(f, s->precision);
+    qemu_put_byte(f, s->nextprecision);
+    qemu_put_byte(f, s->filter);
+    qemu_put_byte(f, s->pin_func);
+    qemu_put_byte(f, s->ref);
+    qemu_put_byte(f, s->timing);
+    qemu_put_be32(f, s->noise);
+
+    qemu_put_be16s(f, &s->audio_ctrl1);
+    qemu_put_be16s(f, &s->audio_ctrl2);
+    qemu_put_be16s(f, &s->audio_ctrl3);
+    qemu_put_be16s(f, &s->pll[0]);
+    qemu_put_be16s(f, &s->pll[1]);
+    qemu_put_be16s(f, &s->volume);
+    qemu_put_sbe64(f, (s->volume_change - now));
+    qemu_put_sbe64(f, (s->powerdown - now));
+    qemu_put_byte(f, s->softstep);
+    qemu_put_be16s(f, &s->dac_power);
+
+    for (i = 0; i < 0x14; i ++)
+        qemu_put_be16s(f, &s->filter_data[i]);
+}
+
+static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
+{
+    TSC210xState *s = (TSC210xState *) opaque;
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    s->x = qemu_get_be16(f);
+    s->y = qemu_get_be16(f);
+    s->pressure = qemu_get_byte(f);
+
+    s->state = qemu_get_byte(f);
+    s->page = qemu_get_byte(f);
+    s->offset = qemu_get_byte(f);
+    s->command = qemu_get_byte(f);
+
+    s->irq = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dav);
+
+    qemu_get_timer(f, s->timer);
+    s->enabled = qemu_get_byte(f);
+    s->host_mode = qemu_get_byte(f);
+    s->function = qemu_get_byte(f);
+    s->nextfunction = qemu_get_byte(f);
+    s->precision = qemu_get_byte(f);
+    s->nextprecision = qemu_get_byte(f);
+    s->filter = qemu_get_byte(f);
+    s->pin_func = qemu_get_byte(f);
+    s->ref = qemu_get_byte(f);
+    s->timing = qemu_get_byte(f);
+    s->noise = qemu_get_be32(f);
+
+    qemu_get_be16s(f, &s->audio_ctrl1);
+    qemu_get_be16s(f, &s->audio_ctrl2);
+    qemu_get_be16s(f, &s->audio_ctrl3);
+    qemu_get_be16s(f, &s->pll[0]);
+    qemu_get_be16s(f, &s->pll[1]);
+    qemu_get_be16s(f, &s->volume);
+    s->volume_change = qemu_get_sbe64(f) + now;
+    s->powerdown = qemu_get_sbe64(f) + now;
+    s->softstep = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dac_power);
+
+    for (i = 0; i < 0x14; i ++)
+        qemu_get_be16s(f, &s->filter_data[i]);
+
+    s->busy = qemu_timer_pending(s->timer);
+    qemu_set_irq(s->pint, !s->irq);
+    qemu_set_irq(s->davint, !s->dav);
+
+    return 0;
+}
+
+uWireSlave *tsc2102_init(qemu_irq pint)
+{
+    TSC210xState *s;
+
+    s = (TSC210xState *)
+            g_malloc0(sizeof(TSC210xState));
+    memset(s, 0, sizeof(TSC210xState));
+    s->x = 160;
+    s->y = 160;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
+    s->pint = pint;
+    s->model = 0x2102;
+    s->name = "tsc2102";
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    s->chip.opaque = s;
+    s->chip.send = (void *) tsc210x_write;
+    s->chip.receive = (void *) tsc210x_read;
+
+    s->codec.opaque = s;
+    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
+    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
+    s->codec.in.fifo = s->in_fifo;
+    s->codec.out.fifo = s->out_fifo;
+
+    tsc210x_reset(s);
+
+    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
+                    "QEMU TSC2102-driven Touchscreen");
+
+    AUD_register_card(s->name, &s->card);
+
+    qemu_register_reset((void *) tsc210x_reset, s);
+    register_savevm(NULL, s->name, -1, 0,
+                    tsc210x_save, tsc210x_load, s);
+
+    return &s->chip;
+}
+
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
+{
+    TSC210xState *s;
+
+    s = (TSC210xState *)
+            g_malloc0(sizeof(TSC210xState));
+    memset(s, 0, sizeof(TSC210xState));
+    s->x = 400;
+    s->y = 240;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
+    s->pint = penirq;
+    s->kbint = kbirq;
+    s->davint = dav;
+    s->model = 0x2301;
+    s->name = "tsc2301";
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    s->chip.opaque = s;
+    s->chip.send = (void *) tsc210x_write;
+    s->chip.receive = (void *) tsc210x_read;
+
+    s->codec.opaque = s;
+    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
+    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
+    s->codec.in.fifo = s->in_fifo;
+    s->codec.out.fifo = s->out_fifo;
+
+    tsc210x_reset(s);
+
+    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
+                    "QEMU TSC2301-driven Touchscreen");
+
+    AUD_register_card(s->name, &s->card);
+
+    qemu_register_reset((void *) tsc210x_reset, s);
+    register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
+
+    return &s->chip;
+}
+
+I2SCodec *tsc210x_codec(uWireSlave *chip)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+
+    return &s->codec;
+}
+
+/*
+ * Use tslib generated calibration data to generate ADC input values
+ * from the touchscreen.  Assuming 12-bit precision was used during
+ * tslib calibration.
+ */
+void tsc210x_set_transform(uWireSlave *chip,
+                MouseTransformInfo *info)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+#if 0
+    int64_t ltr[8];
+
+    ltr[0] = (int64_t) info->a[1] * info->y;
+    ltr[1] = (int64_t) info->a[4] * info->x;
+    ltr[2] = (int64_t) info->a[1] * info->a[3] -
+            (int64_t) info->a[4] * info->a[0];
+    ltr[3] = (int64_t) info->a[2] * info->a[4] -
+            (int64_t) info->a[5] * info->a[1];
+    ltr[4] = (int64_t) info->a[0] * info->y;
+    ltr[5] = (int64_t) info->a[3] * info->x;
+    ltr[6] = (int64_t) info->a[4] * info->a[0] -
+            (int64_t) info->a[1] * info->a[3];
+    ltr[7] = (int64_t) info->a[2] * info->a[3] -
+            (int64_t) info->a[5] * info->a[0];
+
+    /* Avoid integer overflow */
+    s->tr[0] = ltr[0] >> 11;
+    s->tr[1] = ltr[1] >> 11;
+    s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
+    s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
+    s->tr[4] = ltr[4] >> 11;
+    s->tr[5] = ltr[5] >> 11;
+    s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
+    s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
+#else
+
+    /* This version assumes touchscreen X & Y axis are parallel or
+     * perpendicular to LCD's  X & Y axis in some way.  */
+    if (abs(info->a[0]) > abs(info->a[1])) {
+        s->tr[0] = 0;
+        s->tr[1] = -info->a[6] * info->x;
+        s->tr[2] = info->a[0];
+        s->tr[3] = -info->a[2] / info->a[0];
+        s->tr[4] = info->a[6] * info->y;
+        s->tr[5] = 0;
+        s->tr[6] = info->a[4];
+        s->tr[7] = -info->a[5] / info->a[4];
+    } else {
+        s->tr[0] = info->a[6] * info->y;
+        s->tr[1] = 0;
+        s->tr[2] = info->a[1];
+        s->tr[3] = -info->a[2] / info->a[1];
+        s->tr[4] = 0;
+        s->tr[5] = -info->a[6] * info->x;
+        s->tr[6] = info->a[3];
+        s->tr[7] = -info->a[5] / info->a[3];
+    }
+
+    s->tr[0] >>= 11;
+    s->tr[1] >>= 11;
+    s->tr[3] <<= 4;
+    s->tr[4] >>= 11;
+    s->tr[5] >>= 11;
+    s->tr[7] <<= 4;
+#endif
+}
+
+void tsc210x_key_event(uWireSlave *chip, int key, int down)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+
+    if (down)
+        s->kb.down |= 1 << key;
+    else
+        s->kb.down &= ~(1 << key);
+
+    if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
+        s->kb.intr = 1;
+        qemu_irq_lower(s->kbint);
+    } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
+                    !(s->kb.mode & 1)) {
+        s->kb.intr = 0;
+        qemu_irq_raise(s->kbint);
+    }
+}
index e1161566adf376f799acc7a9d610447c6b13ce50..f911ac61d1ef40bdaf89d3ed02c54214cccc0e3e 100644 (file)
@@ -1,12 +1,9 @@
 # LM32 peripherals
 obj-y += lm32_pic.o
-obj-y += lm32_timer.o
 obj-y += lm32_sys.o
 obj-y += milkymist-hpdmc.o
 obj-y += milkymist-memcard.o
 obj-y += milkymist-pfpu.o
-obj-y += milkymist-softusb.o
-obj-y += milkymist-sysctl.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
deleted file mode 100644 (file)
index e06fac7..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- *  QEMU model of the LatticeMico32 timer block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- *   http://www.latticesemi.com/documents/mico32timer.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/error-report.h"
-
-#define DEFAULT_FREQUENCY (50*1000000)
-
-enum {
-    R_SR = 0,
-    R_CR,
-    R_PERIOD,
-    R_SNAPSHOT,
-    R_MAX
-};
-
-enum {
-    SR_TO    = (1 << 0),
-    SR_RUN   = (1 << 1),
-};
-
-enum {
-    CR_ITO   = (1 << 0),
-    CR_CONT  = (1 << 1),
-    CR_START = (1 << 2),
-    CR_STOP  = (1 << 3),
-};
-
-struct LM32TimerState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    QEMUBH *bh;
-    ptimer_state *ptimer;
-
-    qemu_irq irq;
-    uint32_t freq_hz;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct LM32TimerState LM32TimerState;
-
-static void timer_update_irq(LM32TimerState *s)
-{
-    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
-
-    trace_lm32_timer_irq_state(state);
-    qemu_set_irq(s->irq, state);
-}
-
-static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
-{
-    LM32TimerState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SR:
-    case R_CR:
-    case R_PERIOD:
-        r = s->regs[addr];
-        break;
-    case R_SNAPSHOT:
-        r = (uint32_t)ptimer_get_count(s->ptimer);
-        break;
-    default:
-        error_report("lm32_timer: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_lm32_timer_memory_read(addr << 2, r);
-    return r;
-}
-
-static void timer_write(void *opaque, hwaddr addr,
-                        uint64_t value, unsigned size)
-{
-    LM32TimerState *s = opaque;
-
-    trace_lm32_timer_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SR:
-        s->regs[R_SR] &= ~SR_TO;
-        break;
-    case R_CR:
-        s->regs[R_CR] = value;
-        if (s->regs[R_CR] & CR_START) {
-            ptimer_run(s->ptimer, 1);
-        }
-        if (s->regs[R_CR] & CR_STOP) {
-            ptimer_stop(s->ptimer);
-        }
-        break;
-    case R_PERIOD:
-        s->regs[R_PERIOD] = value;
-        ptimer_set_count(s->ptimer, value);
-        break;
-    case R_SNAPSHOT:
-        error_report("lm32_timer: write access to read only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    default:
-        error_report("lm32_timer: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-    timer_update_irq(s);
-}
-
-static const MemoryRegionOps timer_ops = {
-    .read = timer_read,
-    .write = timer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void timer_hit(void *opaque)
-{
-    LM32TimerState *s = opaque;
-
-    trace_lm32_timer_hit();
-
-    s->regs[R_SR] |= SR_TO;
-
-    if (s->regs[R_CR] & CR_CONT) {
-        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
-        ptimer_run(s->ptimer, 1);
-    }
-    timer_update_irq(s);
-}
-
-static void timer_reset(DeviceState *d)
-{
-    LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    ptimer_stop(s->ptimer);
-}
-
-static int lm32_timer_init(SysBusDevice *dev)
-{
-    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    s->bh = qemu_bh_new(timer_hit, s);
-    s->ptimer = ptimer_init(s->bh);
-    ptimer_set_freq(s->ptimer, s->freq_hz);
-
-    memory_region_init_io(&s->iomem, &timer_ops, s, "timer", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_timer = {
-    .name = "lm32-timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PTIMER(ptimer, LM32TimerState),
-        VMSTATE_UINT32(freq_hz, LM32TimerState),
-        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property lm32_timer_properties[] = {
-    DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_timer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lm32_timer_init;
-    dc->reset = timer_reset;
-    dc->vmsd = &vmstate_lm32_timer;
-    dc->props = lm32_timer_properties;
-}
-
-static const TypeInfo lm32_timer_info = {
-    .name          = "lm32-timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(LM32TimerState),
-    .class_init    = lm32_timer_class_init,
-};
-
-static void lm32_timer_register_types(void)
-{
-    type_register_static(&lm32_timer_info);
-}
-
-type_init(lm32_timer_register_types)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
deleted file mode 100644 (file)
index 3edab4f..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- *  QEMU model of the Milkymist SoftUSB block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- *   not available yet
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "hw/input/hid.h"
-#include "qemu/error-report.h"
-
-enum {
-    R_CTRL = 0,
-    R_MAX
-};
-
-enum {
-    CTRL_RESET = (1<<0),
-};
-
-#define COMLOC_DEBUG_PRODUCE 0x1000
-#define COMLOC_DEBUG_BASE    0x1001
-#define COMLOC_MEVT_PRODUCE  0x1101
-#define COMLOC_MEVT_BASE     0x1102
-#define COMLOC_KEVT_PRODUCE  0x1142
-#define COMLOC_KEVT_BASE     0x1143
-
-struct MilkymistSoftUsbState {
-    SysBusDevice busdev;
-    HIDState hid_kbd;
-    HIDState hid_mouse;
-
-    MemoryRegion regs_region;
-    MemoryRegion pmem;
-    MemoryRegion dmem;
-    qemu_irq irq;
-
-    void *pmem_ptr;
-    void *dmem_ptr;
-
-    /* device properties */
-    uint32_t pmem_size;
-    uint32_t dmem_size;
-
-    /* device registers */
-    uint32_t regs[R_MAX];
-
-    /* mouse state */
-    uint8_t mouse_hid_buffer[4];
-
-    /* keyboard state */
-    uint8_t kbd_hid_buffer[8];
-};
-typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
-
-static uint64_t softusb_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    MilkymistSoftUsbState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_softusb: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_softusb_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void
-softusb_write(void *opaque, hwaddr addr, uint64_t value,
-              unsigned size)
-{
-    MilkymistSoftUsbState *s = opaque;
-
-    trace_milkymist_softusb_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_softusb: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps softusb_mmio_ops = {
-    .read = softusb_read,
-    .write = softusb_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->dmem_size) {
-        error_report("milkymist_softusb: read dmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        memset(buf, 0, len);
-        return;
-    }
-
-    memcpy(buf, s->dmem_ptr + offset, len);
-}
-
-static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->dmem_size) {
-        error_report("milkymist_softusb: write dmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        return;
-    }
-
-    memcpy(s->dmem_ptr + offset, buf, len);
-}
-
-static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->pmem_size) {
-        error_report("milkymist_softusb: read pmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        memset(buf, 0, len);
-        return;
-    }
-
-    memcpy(buf, s->pmem_ptr + offset, len);
-}
-
-static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->pmem_size) {
-        error_report("milkymist_softusb: write pmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        return;
-    }
-
-    memcpy(s->pmem_ptr + offset, buf, len);
-}
-
-static void softusb_mouse_changed(MilkymistSoftUsbState *s)
-{
-    uint8_t m;
-
-    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
-    trace_milkymist_softusb_mevt(m);
-    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
-    m = (m + 1) & 0xf;
-    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
-
-    trace_milkymist_softusb_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_changed(MilkymistSoftUsbState *s)
-{
-    uint8_t m;
-
-    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
-    trace_milkymist_softusb_kevt(m);
-    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
-    m = (m + 1) & 0x7;
-    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
-
-    trace_milkymist_softusb_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_hid_datain(HIDState *hs)
-{
-    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
-    int len;
-
-    /* if device is in reset, do nothing */
-    if (s->regs[R_CTRL] & CTRL_RESET) {
-        return;
-    }
-
-    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
-
-    if (len == 8) {
-        softusb_kbd_changed(s);
-    }
-}
-
-static void softusb_mouse_hid_datain(HIDState *hs)
-{
-    MilkymistSoftUsbState *s =
-            container_of(hs, MilkymistSoftUsbState, hid_mouse);
-    int len;
-
-    /* if device is in reset, do nothing */
-    if (s->regs[R_CTRL] & CTRL_RESET) {
-        return;
-    }
-
-    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
-            sizeof(s->mouse_hid_buffer));
-
-    if (len == 4) {
-        softusb_mouse_changed(s);
-    }
-}
-
-static void milkymist_softusb_reset(DeviceState *d)
-{
-    MilkymistSoftUsbState *s =
-            container_of(d, MilkymistSoftUsbState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
-    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
-
-    hid_reset(&s->hid_kbd);
-    hid_reset(&s->hid_mouse);
-
-    /* defaults */
-    s->regs[R_CTRL] = CTRL_RESET;
-}
-
-static int milkymist_softusb_init(SysBusDevice *dev)
-{
-    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
-                          "milkymist-softusb", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    /* register pmem and dmem */
-    memory_region_init_ram(&s->pmem, "milkymist-softusb.pmem",
-                           s->pmem_size);
-    vmstate_register_ram_global(&s->pmem);
-    s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
-    sysbus_init_mmio(dev, &s->pmem);
-    memory_region_init_ram(&s->dmem, "milkymist-softusb.dmem",
-                           s->dmem_size);
-    vmstate_register_ram_global(&s->dmem);
-    s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
-    sysbus_init_mmio(dev, &s->dmem);
-
-    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
-    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_softusb = {
-    .name = "milkymist-softusb",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
-        VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
-        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
-        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
-        VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_softusb_properties[] = {
-    DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
-    DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_softusb_init;
-    dc->reset = milkymist_softusb_reset;
-    dc->vmsd = &vmstate_milkymist_softusb;
-    dc->props = milkymist_softusb_properties;
-}
-
-static const TypeInfo milkymist_softusb_info = {
-    .name          = "milkymist-softusb",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MilkymistSoftUsbState),
-    .class_init    = milkymist_softusb_class_init,
-};
-
-static void milkymist_softusb_register_types(void)
-{
-    type_register_static(&milkymist_softusb_info);
-}
-
-type_init(milkymist_softusb_register_types)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
deleted file mode 100644 (file)
index e083a28..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- *  QEMU model of the Milkymist System Controller.
- *
- *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/sysctl.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/error-report.h"
-
-enum {
-    CTRL_ENABLE      = (1<<0),
-    CTRL_AUTORESTART = (1<<1),
-};
-
-enum {
-    ICAP_READY       = (1<<0),
-};
-
-enum {
-    R_GPIO_IN         = 0,
-    R_GPIO_OUT,
-    R_GPIO_INTEN,
-    R_TIMER0_CONTROL  = 4,
-    R_TIMER0_COMPARE,
-    R_TIMER0_COUNTER,
-    R_TIMER1_CONTROL  = 8,
-    R_TIMER1_COMPARE,
-    R_TIMER1_COUNTER,
-    R_ICAP = 16,
-    R_DBG_SCRATCHPAD  = 20,
-    R_DBG_WRITE_LOCK,
-    R_CLK_FREQUENCY   = 29,
-    R_CAPABILITIES,
-    R_SYSTEM_ID,
-    R_MAX
-};
-
-struct MilkymistSysctlState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-
-    QEMUBH *bh0;
-    QEMUBH *bh1;
-    ptimer_state *ptimer0;
-    ptimer_state *ptimer1;
-
-    uint32_t freq_hz;
-    uint32_t capabilities;
-    uint32_t systemid;
-    uint32_t strappings;
-
-    uint32_t regs[R_MAX];
-
-    qemu_irq gpio_irq;
-    qemu_irq timer0_irq;
-    qemu_irq timer1_irq;
-};
-typedef struct MilkymistSysctlState MilkymistSysctlState;
-
-static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
-{
-    trace_milkymist_sysctl_icap_write(value);
-    switch (value & 0xffff) {
-    case 0x000e:
-        qemu_system_shutdown_request();
-        break;
-    }
-}
-
-static uint64_t sysctl_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    MilkymistSysctlState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_TIMER0_COUNTER:
-        r = (uint32_t)ptimer_get_count(s->ptimer0);
-        /* milkymist timer counts up */
-        r = s->regs[R_TIMER0_COMPARE] - r;
-        break;
-    case R_TIMER1_COUNTER:
-        r = (uint32_t)ptimer_get_count(s->ptimer1);
-        /* milkymist timer counts up */
-        r = s->regs[R_TIMER1_COMPARE] - r;
-        break;
-    case R_GPIO_IN:
-    case R_GPIO_OUT:
-    case R_GPIO_INTEN:
-    case R_TIMER0_CONTROL:
-    case R_TIMER0_COMPARE:
-    case R_TIMER1_CONTROL:
-    case R_TIMER1_COMPARE:
-    case R_ICAP:
-    case R_DBG_SCRATCHPAD:
-    case R_DBG_WRITE_LOCK:
-    case R_CLK_FREQUENCY:
-    case R_CAPABILITIES:
-    case R_SYSTEM_ID:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_sysctl: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_sysctl_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
-                         unsigned size)
-{
-    MilkymistSysctlState *s = opaque;
-
-    trace_milkymist_sysctl_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_GPIO_OUT:
-    case R_GPIO_INTEN:
-    case R_TIMER0_COUNTER:
-    case R_TIMER1_COUNTER:
-    case R_DBG_SCRATCHPAD:
-        s->regs[addr] = value;
-        break;
-    case R_TIMER0_COMPARE:
-        ptimer_set_limit(s->ptimer0, value, 0);
-        s->regs[addr] = value;
-        break;
-    case R_TIMER1_COMPARE:
-        ptimer_set_limit(s->ptimer1, value, 0);
-        s->regs[addr] = value;
-        break;
-    case R_TIMER0_CONTROL:
-        s->regs[addr] = value;
-        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
-            trace_milkymist_sysctl_start_timer0();
-            ptimer_set_count(s->ptimer0,
-                    s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
-            ptimer_run(s->ptimer0, 0);
-        } else {
-            trace_milkymist_sysctl_stop_timer0();
-            ptimer_stop(s->ptimer0);
-        }
-        break;
-    case R_TIMER1_CONTROL:
-        s->regs[addr] = value;
-        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
-            trace_milkymist_sysctl_start_timer1();
-            ptimer_set_count(s->ptimer1,
-                    s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
-            ptimer_run(s->ptimer1, 0);
-        } else {
-            trace_milkymist_sysctl_stop_timer1();
-            ptimer_stop(s->ptimer1);
-        }
-        break;
-    case R_ICAP:
-        sysctl_icap_write(s, value);
-        break;
-    case R_DBG_WRITE_LOCK:
-        s->regs[addr] = 1;
-        break;
-    case R_SYSTEM_ID:
-        qemu_system_reset_request();
-        break;
-
-    case R_GPIO_IN:
-    case R_CLK_FREQUENCY:
-    case R_CAPABILITIES:
-        error_report("milkymist_sysctl: write to read-only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-
-    default:
-        error_report("milkymist_sysctl: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps sysctl_mmio_ops = {
-    .read = sysctl_read,
-    .write = sysctl_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timer0_hit(void *opaque)
-{
-    MilkymistSysctlState *s = opaque;
-
-    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
-        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
-        trace_milkymist_sysctl_stop_timer0();
-        ptimer_stop(s->ptimer0);
-    }
-
-    trace_milkymist_sysctl_pulse_irq_timer0();
-    qemu_irq_pulse(s->timer0_irq);
-}
-
-static void timer1_hit(void *opaque)
-{
-    MilkymistSysctlState *s = opaque;
-
-    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
-        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
-        trace_milkymist_sysctl_stop_timer1();
-        ptimer_stop(s->ptimer1);
-    }
-
-    trace_milkymist_sysctl_pulse_irq_timer1();
-    qemu_irq_pulse(s->timer1_irq);
-}
-
-static void milkymist_sysctl_reset(DeviceState *d)
-{
-    MilkymistSysctlState *s =
-            container_of(d, MilkymistSysctlState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    ptimer_stop(s->ptimer0);
-    ptimer_stop(s->ptimer1);
-
-    /* defaults */
-    s->regs[R_ICAP] = ICAP_READY;
-    s->regs[R_SYSTEM_ID] = s->systemid;
-    s->regs[R_CLK_FREQUENCY] = s->freq_hz;
-    s->regs[R_CAPABILITIES] = s->capabilities;
-    s->regs[R_GPIO_IN] = s->strappings;
-}
-
-static int milkymist_sysctl_init(SysBusDevice *dev)
-{
-    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->gpio_irq);
-    sysbus_init_irq(dev, &s->timer0_irq);
-    sysbus_init_irq(dev, &s->timer1_irq);
-
-    s->bh0 = qemu_bh_new(timer0_hit, s);
-    s->bh1 = qemu_bh_new(timer1_hit, s);
-    s->ptimer0 = ptimer_init(s->bh0);
-    s->ptimer1 = ptimer_init(s->bh1);
-    ptimer_set_freq(s->ptimer0, s->freq_hz);
-    ptimer_set_freq(s->ptimer1, s->freq_hz);
-
-    memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
-            "milkymist-sysctl", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_sysctl = {
-    .name = "milkymist-sysctl",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
-        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
-        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_sysctl_properties[] = {
-    DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
-    freq_hz, 80000000),
-    DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
-    capabilities, 0x00000000),
-    DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
-    systemid, 0x10014d31),
-    DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
-    strappings, 0x00000001),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_sysctl_init;
-    dc->reset = milkymist_sysctl_reset;
-    dc->vmsd = &vmstate_milkymist_sysctl;
-    dc->props = milkymist_sysctl_properties;
-}
-
-static const TypeInfo milkymist_sysctl_info = {
-    .name          = "milkymist-sysctl",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MilkymistSysctlState),
-    .class_init    = milkymist_sysctl_class_init,
-};
-
-static void milkymist_sysctl_register_types(void)
-{
-    type_register_static(&milkymist_sysctl_info);
-}
-
-type_init(milkymist_sysctl_register_types)
diff --git a/hw/omap_gptimer.c b/hw/omap_gptimer.c
deleted file mode 100644 (file)
index 9b0e9dd..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * TI OMAP2 general purpose timers emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-
-/* GP timers */
-struct omap_gp_timer_s {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq wkup;
-    qemu_irq in;
-    qemu_irq out;
-    omap_clk clk;
-    QEMUTimer *timer;
-    QEMUTimer *match;
-    struct omap_target_agent_s *ta;
-
-    int in_val;
-    int out_val;
-    int64_t time;
-    int64_t rate;
-    int64_t ticks_per_sec;
-
-    int16_t config;
-    int status;
-    int it_ena;
-    int wu_ena;
-    int enable;
-    int inout;
-    int capt2;
-    int pt;
-    enum {
-        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
-    } trigger;
-    enum {
-        gpt_capture_none, gpt_capture_rising,
-        gpt_capture_falling, gpt_capture_both
-    } capture;
-    int scpwm;
-    int ce;
-    int pre;
-    int ptv;
-    int ar;
-    int st;
-    int posted;
-    uint32_t val;
-    uint32_t load_val;
-    uint32_t capture_val[2];
-    uint32_t match_val;
-    int capt_num;
-
-    uint16_t writeh;   /* LSB */
-    uint16_t readh;    /* MSB */
-};
-
-#define GPT_TCAR_IT    (1 << 2)
-#define GPT_OVF_IT     (1 << 1)
-#define GPT_MAT_IT     (1 << 0)
-
-static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
-{
-    if (timer->it_ena & it) {
-        if (!timer->status)
-            qemu_irq_raise(timer->irq);
-
-        timer->status |= it;
-        /* Or are the status bits set even when masked?
-         * i.e. is masking applied before or after the status register?  */
-    }
-
-    if (timer->wu_ena & it)
-        qemu_irq_pulse(timer->wkup);
-}
-
-static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
-{
-    if (!timer->inout && timer->out_val != level) {
-        timer->out_val = level;
-        qemu_set_irq(timer->out, level);
-    }
-}
-
-static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
-{
-    uint64_t distance;
-
-    if (timer->st && timer->rate) {
-        distance = qemu_get_clock_ns(vm_clock) - timer->time;
-        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
-
-        if (distance >= 0xffffffff - timer->val)
-            return 0xffffffff;
-        else
-            return timer->val + distance;
-    } else
-        return timer->val;
-}
-
-static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
-{
-    if (timer->st) {
-        timer->val = omap_gp_timer_read(timer);
-        timer->time = qemu_get_clock_ns(vm_clock);
-    }
-}
-
-static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
-{
-    int64_t expires, matches;
-
-    if (timer->st && timer->rate) {
-        expires = muldiv64(0x100000000ll - timer->val,
-                        timer->ticks_per_sec, timer->rate);
-        qemu_mod_timer(timer->timer, timer->time + expires);
-
-        if (timer->ce && timer->match_val >= timer->val) {
-            matches = muldiv64(timer->match_val - timer->val,
-                            timer->ticks_per_sec, timer->rate);
-            qemu_mod_timer(timer->match, timer->time + matches);
-        } else
-            qemu_del_timer(timer->match);
-    } else {
-        qemu_del_timer(timer->timer);
-        qemu_del_timer(timer->match);
-        omap_gp_timer_out(timer, timer->scpwm);
-    }
-}
-
-static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
-{
-    if (timer->pt)
-        /* TODO in overflow-and-match mode if the first event to
-         * occur is the match, don't toggle.  */
-        omap_gp_timer_out(timer, !timer->out_val);
-    else
-        /* TODO inverted pulse on timer->out_val == 1?  */
-        qemu_irq_pulse(timer->out);
-}
-
-static void omap_gp_timer_tick(void *opaque)
-{
-    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
-    if (!timer->ar) {
-        timer->st = 0;
-        timer->val = 0;
-    } else {
-        timer->val = timer->load_val;
-        timer->time = qemu_get_clock_ns(vm_clock);
-    }
-
-    if (timer->trigger == gpt_trigger_overflow ||
-                    timer->trigger == gpt_trigger_both)
-        omap_gp_timer_trigger(timer);
-
-    omap_gp_timer_intr(timer, GPT_OVF_IT);
-    omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_match(void *opaque)
-{
-    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
-    if (timer->trigger == gpt_trigger_both)
-        omap_gp_timer_trigger(timer);
-
-    omap_gp_timer_intr(timer, GPT_MAT_IT);
-}
-
-static void omap_gp_timer_input(void *opaque, int line, int on)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-    int trigger;
-
-    switch (s->capture) {
-    default:
-    case gpt_capture_none:
-        trigger = 0;
-        break;
-    case gpt_capture_rising:
-        trigger = !s->in_val && on;
-        break;
-    case gpt_capture_falling:
-        trigger = s->in_val && !on;
-        break;
-    case gpt_capture_both:
-        trigger = (s->in_val == !on);
-        break;
-    }
-    s->in_val = on;
-
-    if (s->inout && trigger && s->capt_num < 2) {
-        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
-
-        if (s->capt2 == s->capt_num ++)
-            omap_gp_timer_intr(s, GPT_TCAR_IT);
-    }
-}
-
-static void omap_gp_timer_clk_update(void *opaque, int line, int on)
-{
-    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
-    omap_gp_timer_sync(timer);
-    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
-    omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
-{
-    omap_clk_adduser(timer->clk,
-                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
-    timer->rate = omap_clk_getrate(timer->clk);
-}
-
-void omap_gp_timer_reset(struct omap_gp_timer_s *s)
-{
-    s->config = 0x000;
-    s->status = 0;
-    s->it_ena = 0;
-    s->wu_ena = 0;
-    s->inout = 0;
-    s->capt2 = 0;
-    s->capt_num = 0;
-    s->pt = 0;
-    s->trigger = gpt_trigger_none;
-    s->capture = gpt_capture_none;
-    s->scpwm = 0;
-    s->ce = 0;
-    s->pre = 0;
-    s->ptv = 0;
-    s->ar = 0;
-    s->st = 0;
-    s->posted = 1;
-    s->val = 0x00000000;
-    s->load_val = 0x00000000;
-    s->capture_val[0] = 0x00000000;
-    s->capture_val[1] = 0x00000000;
-    s->match_val = 0x00000000;
-    omap_gp_timer_update(s);
-}
-
-static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* TIDR */
-        return 0x21;
-
-    case 0x10: /* TIOCP_CFG */
-        return s->config;
-
-    case 0x14: /* TISTAT */
-        /* ??? When's this bit reset? */
-        return 1;                                              /* RESETDONE */
-
-    case 0x18: /* TISR */
-        return s->status;
-
-    case 0x1c: /* TIER */
-        return s->it_ena;
-
-    case 0x20: /* TWER */
-        return s->wu_ena;
-
-    case 0x24: /* TCLR */
-        return (s->inout << 14) |
-                (s->capt2 << 13) |
-                (s->pt << 12) |
-                (s->trigger << 10) |
-                (s->capture << 8) |
-                (s->scpwm << 7) |
-                (s->ce << 6) |
-                (s->pre << 5) |
-                (s->ptv << 2) |
-                (s->ar << 1) |
-                (s->st << 0);
-
-    case 0x28: /* TCRR */
-        return omap_gp_timer_read(s);
-
-    case 0x2c: /* TLDR */
-        return s->load_val;
-
-    case 0x30: /* TTGR */
-        return 0xffffffff;
-
-    case 0x34: /* TWPS */
-        return 0x00000000;     /* No posted writes pending.  */
-
-    case 0x38: /* TMAR */
-        return s->match_val;
-
-    case 0x3c: /* TCAR1 */
-        return s->capture_val[0];
-
-    case 0x40: /* TSICR */
-        return s->posted << 2;
-
-    case 0x44: /* TCAR2 */
-        return s->capture_val[1];
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-    uint32_t ret;
-
-    if (addr & 2)
-        return s->readh;
-    else {
-        ret = omap_gp_timer_readw(opaque, addr);
-        s->readh = ret >> 16;
-        return ret & 0xffff;
-    }
-}
-
-static void omap_gp_timer_write(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* TIDR */
-    case 0x14: /* TISTAT */
-    case 0x34: /* TWPS */
-    case 0x3c: /* TCAR1 */
-    case 0x44: /* TCAR2 */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* TIOCP_CFG */
-        s->config = value & 0x33d;
-        if (((value >> 3) & 3) == 3)                           /* IDLEMODE */
-            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
-                            __FUNCTION__);
-        if (value & 2)                                         /* SOFTRESET */
-            omap_gp_timer_reset(s);
-        break;
-
-    case 0x18: /* TISR */
-        if (value & GPT_TCAR_IT)
-            s->capt_num = 0;
-        if (s->status && !(s->status &= ~value))
-            qemu_irq_lower(s->irq);
-        break;
-
-    case 0x1c: /* TIER */
-        s->it_ena = value & 7;
-        break;
-
-    case 0x20: /* TWER */
-        s->wu_ena = value & 7;
-        break;
-
-    case 0x24: /* TCLR */
-        omap_gp_timer_sync(s);
-        s->inout = (value >> 14) & 1;
-        s->capt2 = (value >> 13) & 1;
-        s->pt = (value >> 12) & 1;
-        s->trigger = (value >> 10) & 3;
-        if (s->capture == gpt_capture_none &&
-                        ((value >> 8) & 3) != gpt_capture_none)
-            s->capt_num = 0;
-        s->capture = (value >> 8) & 3;
-        s->scpwm = (value >> 7) & 1;
-        s->ce = (value >> 6) & 1;
-        s->pre = (value >> 5) & 1;
-        s->ptv = (value >> 2) & 7;
-        s->ar = (value >> 1) & 1;
-        s->st = (value >> 0) & 1;
-        if (s->inout && s->trigger != gpt_trigger_none)
-            fprintf(stderr, "%s: GP timer pin must be an output "
-                            "for this trigger mode\n", __FUNCTION__);
-        if (!s->inout && s->capture != gpt_capture_none)
-            fprintf(stderr, "%s: GP timer pin must be an input "
-                            "for this capture mode\n", __FUNCTION__);
-        if (s->trigger == gpt_trigger_none)
-            omap_gp_timer_out(s, s->scpwm);
-        /* TODO: make sure this doesn't overflow 32-bits */
-        s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x28: /* TCRR */
-        s->time = qemu_get_clock_ns(vm_clock);
-        s->val = value;
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x2c: /* TLDR */
-        s->load_val = value;
-        break;
-
-    case 0x30: /* TTGR */
-        s->time = qemu_get_clock_ns(vm_clock);
-        s->val = s->load_val;
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x38: /* TMAR */
-        omap_gp_timer_sync(s);
-        s->match_val = value;
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x40: /* TSICR */
-        s->posted = (value >> 2) & 1;
-        if (value & 2) /* How much exactly are we supposed to reset? */
-            omap_gp_timer_reset(s);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
-    if (addr & 2)
-        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
-    else
-        s->writeh = (uint16_t) value;
-}
-
-static const MemoryRegionOps omap_gp_timer_ops = {
-    .old_mmio = {
-        .read = {
-            omap_badwidth_read32,
-            omap_gp_timer_readh,
-            omap_gp_timer_readw,
-        },
-        .write = {
-            omap_badwidth_write32,
-            omap_gp_timer_writeh,
-            omap_gp_timer_write,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
-            g_malloc0(sizeof(struct omap_gp_timer_s));
-
-    s->ta = ta;
-    s->irq = irq;
-    s->clk = fclk;
-    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
-    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
-    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
-    omap_gp_timer_reset(s);
-    omap_gp_timer_clk_setup(s);
-
-    memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    return s;
-}
diff --git a/hw/omap_synctimer.c b/hw/omap_synctimer.c
deleted file mode 100644 (file)
index a24f35c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * TI OMAP2 32kHz sync timer emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-struct omap_synctimer_s {
-    MemoryRegion iomem;
-    uint32_t val;
-    uint16_t readh;
-};
-
-/* 32-kHz Sync Timer of the OMAP2 */
-static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
-    return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec());
-}
-
-void omap_synctimer_reset(struct omap_synctimer_s *s)
-{
-    s->val = omap_synctimer_read(s);
-}
-
-static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
-{
-    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* 32KSYNCNT_REV */
-        return 0x21;
-
-    case 0x10: /* CR */
-        return omap_synctimer_read(s) - s->val;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
-{
-    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
-    uint32_t ret;
-
-    if (addr & 2)
-        return s->readh;
-    else {
-        ret = omap_synctimer_readw(opaque, addr);
-        s->readh = ret >> 16;
-        return ret & 0xffff;
-    }
-}
-
-static void omap_synctimer_write(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_synctimer_ops = {
-    .old_mmio = {
-        .read = {
-            omap_badwidth_read32,
-            omap_synctimer_readh,
-            omap_synctimer_readw,
-        },
-        .write = {
-            omap_badwidth_write32,
-            omap_synctimer_write,
-            omap_synctimer_write,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
-                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
-
-    omap_synctimer_reset(s);
-    memory_region_init_io(&s->iomem, &omap_synctimer_ops, s, "omap.synctimer",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    return s;
-}
diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c
deleted file mode 100644 (file)
index 1fd5f20..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Intel PXA27X Keypad Controller emulation.
- *
- * Copyright (c) 2007 MontaVista Software, Inc
- * Written by Armin Kuster <akuster@kama-aina.net>
- *              or  <Akuster@mvista.com>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "ui/console.h"
-
-/*
- * Keypad
- */
-#define KPC         0x00    /* Keypad Interface Control register */
-#define KPDK        0x08    /* Keypad Interface Direct Key register */
-#define KPREC       0x10    /* Keypad Interface Rotary Encoder register */
-#define KPMK        0x18    /* Keypad Interface Matrix Key register */
-#define KPAS        0x20    /* Keypad Interface Automatic Scan register */
-#define KPASMKP0    0x28    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 0 */
-#define KPASMKP1    0x30    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 1 */
-#define KPASMKP2    0x38    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 2 */
-#define KPASMKP3    0x40    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 3 */
-#define KPKDI       0x48    /* Keypad Interface Key Debounce Interval
-                                register */
-
-/* Keypad defines */
-#define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
-#define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
-#define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
-#define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
-#define KPC_MS7         (0x1 << 20)  /* Matrix scan line 7 */
-#define KPC_MS6         (0x1 << 19)  /* Matrix scan line 6 */
-#define KPC_MS5         (0x1 << 18)  /* Matrix scan line 5 */
-#define KPC_MS4         (0x1 << 17)  /* Matrix scan line 4 */
-#define KPC_MS3         (0x1 << 16)  /* Matrix scan line 3 */
-#define KPC_MS2         (0x1 << 15)  /* Matrix scan line 2 */
-#define KPC_MS1         (0x1 << 14)  /* Matrix scan line 1 */
-#define KPC_MS0         (0x1 << 13)  /* Matrix scan line 0 */
-#define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
-#define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
-#define KPC_DK_DEB_SEL  (0x1 <<  9)  /* Direct Keypad Debounce Select */
-#define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
-#define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
-#define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
-#define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
-#define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
-#define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
-
-#define KPDK_DKP        (0x1 << 31)
-#define KPDK_DK7        (0x1 <<  7)
-#define KPDK_DK6        (0x1 <<  6)
-#define KPDK_DK5        (0x1 <<  5)
-#define KPDK_DK4        (0x1 <<  4)
-#define KPDK_DK3        (0x1 <<  3)
-#define KPDK_DK2        (0x1 <<  2)
-#define KPDK_DK1        (0x1 <<  1)
-#define KPDK_DK0        (0x1 <<  0)
-
-#define KPREC_OF1       (0x1 << 31)
-#define KPREC_UF1       (0x1 << 30)
-#define KPREC_OF0       (0x1 << 15)
-#define KPREC_UF0       (0x1 << 14)
-
-#define KPMK_MKP        (0x1 << 31)
-#define KPAS_SO         (0x1 << 31)
-#define KPASMKPx_SO     (0x1 << 31)
-
-
-#define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
-
-#define PXAKBD_MAXROW   8
-#define PXAKBD_MAXCOL   8
-
-struct PXA2xxKeyPadState {
-    MemoryRegion iomem;
-    qemu_irq    irq;
-    struct  keymap *map;
-    int         pressed_cnt;
-    int         alt_code;
-
-    uint32_t    kpc;
-    uint32_t    kpdk;
-    uint32_t    kprec;
-    uint32_t    kpmk;
-    uint32_t    kpas;
-    uint32_t    kpasmkp[4];
-    uint32_t    kpkdi;
-};
-
-static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
-{
-    int i;
-    for (i = 0; i < 4; i++)
-    {
-        *col = i * 2;
-        for (*row = 0; *row < 8; (*row)++) {
-            if (kp->kpasmkp[i] & (1 << *row))
-                return;
-        }
-        *col = i * 2 + 1;
-        for (*row = 0; *row < 8; (*row)++) {
-            if (kp->kpasmkp[i] & (1 << (*row + 16)))
-                return;
-        }
-    }
-}
-
-static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
-{
-    int row, col, rel, assert_irq = 0;
-    uint32_t val;
-
-    if (keycode == 0xe0) {
-        kp->alt_code = 1;
-        return;
-    }
-
-    if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
-        return;
-
-    rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
-    keycode &= ~0x80; /* strip qemu key release bit */
-    if (kp->alt_code) {
-        keycode |= 0x80;
-        kp->alt_code = 0;
-    }
-
-    row = kp->map[keycode].row;
-    col = kp->map[keycode].column;
-    if (row == -1 || col == -1) {
-        return;
-    }
-
-    val = KPASMKPx_MKC(row, col);
-    if (rel) {
-        if (kp->kpasmkp[col / 2] & val) {
-            kp->kpasmkp[col / 2] &= ~val;
-            kp->pressed_cnt--;
-            assert_irq = 1;
-        }
-    } else {
-        if (!(kp->kpasmkp[col / 2] & val)) {
-            kp->kpasmkp[col / 2] |= val;
-            kp->pressed_cnt++;
-            assert_irq = 1;
-        }
-    }
-    kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
-    if (kp->pressed_cnt == 1) {
-        kp->kpas &= ~((0xf << 4) | 0xf);
-        if (rel) {
-            pxa27x_keypad_find_pressed_key(kp, &row, &col);
-        }
-        kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
-    }
-
-    if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
-        assert_irq = 0;
-
-    if (assert_irq && (kp->kpc & KPC_MIE)) {
-        kp->kpc |= KPC_MI;
-        qemu_irq_raise(kp->irq);
-    }
-}
-
-static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-    uint32_t tmp;
-
-    switch (offset) {
-    case KPC:
-        tmp = s->kpc;
-        if(tmp & KPC_MI)
-            s->kpc &= ~(KPC_MI);
-        if(tmp & KPC_DI)
-            s->kpc &= ~(KPC_DI);
-        qemu_irq_lower(s->irq);
-        return tmp;
-        break;
-    case KPDK:
-        return s->kpdk;
-        break;
-    case KPREC:
-        tmp = s->kprec;
-        if(tmp & KPREC_OF1)
-            s->kprec &= ~(KPREC_OF1);
-        if(tmp & KPREC_UF1)
-            s->kprec &= ~(KPREC_UF1);
-        if(tmp & KPREC_OF0)
-            s->kprec &= ~(KPREC_OF0);
-        if(tmp & KPREC_UF0)
-            s->kprec &= ~(KPREC_UF0);
-        return tmp;
-        break;
-    case KPMK:
-        tmp = s->kpmk;
-        if(tmp & KPMK_MKP)
-            s->kpmk &= ~(KPMK_MKP);
-        return tmp;
-        break;
-    case KPAS:
-        return s->kpas;
-        break;
-    case KPASMKP0:
-        return s->kpasmkp[0];
-        break;
-    case KPASMKP1:
-        return s->kpasmkp[1];
-        break;
-    case KPASMKP2:
-        return s->kpasmkp[2];
-        break;
-    case KPASMKP3:
-        return s->kpasmkp[3];
-        break;
-    case KPKDI:
-        return s->kpkdi;
-        break;
-    default:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
-    switch (offset) {
-    case KPC:
-        s->kpc = value;
-        if (s->kpc & KPC_AS) {
-            s->kpc &= ~(KPC_AS);
-        }
-        break;
-    case KPDK:
-        s->kpdk = value;
-        break;
-    case KPREC:
-        s->kprec = value;
-        break;
-    case KPMK:
-        s->kpmk = value;
-        break;
-    case KPAS:
-        s->kpas = value;
-        break;
-    case KPASMKP0:
-        s->kpasmkp[0] = value;
-        break;
-    case KPASMKP1:
-        s->kpasmkp[1] = value;
-        break;
-    case KPASMKP2:
-        s->kpasmkp[2] = value;
-        break;
-    case KPASMKP3:
-        s->kpasmkp[3] = value;
-        break;
-    case KPKDI:
-        s->kpkdi = value;
-        break;
-
-    default:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_keypad_ops = {
-    .read = pxa2xx_keypad_read,
-    .write = pxa2xx_keypad_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_keypad = {
-    .name = "pxa2xx_keypad",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
-        VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
-        VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
-                                      hwaddr base,
-                                      qemu_irq irq)
-{
-    PXA2xxKeyPadState *s;
-
-    s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
-    s->irq = irq;
-
-    memory_region_init_io(&s->iomem, &pxa2xx_keypad_ops, s,
-                          "pxa2xx-keypad", 0x00100000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
-
-    return s;
-}
-
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
-        int size)
-{
-    if(!map || size < 0x80) {
-        fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
-        exit(-1);
-    }
-
-    kp->map = map;
-    qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
-}
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
deleted file mode 100644 (file)
index 8ea2416..0000000
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * Intel XScale PXA255/270 OS Timers.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-
-#define OSMR0  0x00
-#define OSMR1  0x04
-#define OSMR2  0x08
-#define OSMR3  0x0c
-#define OSMR4  0x80
-#define OSMR5  0x84
-#define OSMR6  0x88
-#define OSMR7  0x8c
-#define OSMR8  0x90
-#define OSMR9  0x94
-#define OSMR10 0x98
-#define OSMR11 0x9c
-#define OSCR   0x10    /* OS Timer Count */
-#define OSCR4  0x40
-#define OSCR5  0x44
-#define OSCR6  0x48
-#define OSCR7  0x4c
-#define OSCR8  0x50
-#define OSCR9  0x54
-#define OSCR10 0x58
-#define OSCR11 0x5c
-#define OSSR   0x14    /* Timer status register */
-#define OWER   0x18
-#define OIER   0x1c    /* Interrupt enable register  3-0 to E3-E0 */
-#define OMCR4  0xc0    /* OS Match Control registers */
-#define OMCR5  0xc4
-#define OMCR6  0xc8
-#define OMCR7  0xcc
-#define OMCR8  0xd0
-#define OMCR9  0xd4
-#define OMCR10 0xd8
-#define OMCR11 0xdc
-#define OSNR   0x20
-
-#define PXA25X_FREQ    3686400 /* 3.6864 MHz */
-#define PXA27X_FREQ    3250000 /* 3.25 MHz */
-
-static int pxa2xx_timer4_freq[8] = {
-    [0] = 0,
-    [1] = 32768,
-    [2] = 1000,
-    [3] = 1,
-    [4] = 1000000,
-    /* [5] is the "Externally supplied clock".  Assign if necessary.  */
-    [5 ... 7] = 0,
-};
-
-typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
-
-typedef struct {
-    uint32_t value;
-    qemu_irq irq;
-    QEMUTimer *qtimer;
-    int num;
-    PXA2xxTimerInfo *info;
-} PXA2xxTimer0;
-
-typedef struct {
-    PXA2xxTimer0 tm;
-    int32_t oldclock;
-    int32_t clock;
-    uint64_t lastload;
-    uint32_t freq;
-    uint32_t control;
-} PXA2xxTimer4;
-
-struct PXA2xxTimerInfo {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t flags;
-
-    int32_t clock;
-    int32_t oldclock;
-    uint64_t lastload;
-    uint32_t freq;
-    PXA2xxTimer0 timer[4];
-    uint32_t events;
-    uint32_t irq_enabled;
-    uint32_t reset3;
-    uint32_t snapshot;
-
-    qemu_irq irq4;
-    PXA2xxTimer4 tm4[8];
-};
-
-#define PXA2XX_TIMER_HAVE_TM4  0
-
-static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
-{
-    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
-}
-
-static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    int i;
-    uint32_t now_vm;
-    uint64_t new_qemu;
-
-    now_vm = s->clock +
-            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
-
-    for (i = 0; i < 4; i ++) {
-        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
-                        get_ticks_per_sec(), s->freq);
-        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
-    }
-}
-
-static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    uint32_t now_vm;
-    uint64_t new_qemu;
-    static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
-    int counter;
-
-    if (s->tm4[n].control & (1 << 7))
-        counter = n;
-    else
-        counter = counters[n];
-
-    if (!s->tm4[counter].freq) {
-        qemu_del_timer(s->tm4[n].tm.qtimer);
-        return;
-    }
-
-    now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
-                    s->tm4[counter].lastload,
-                    s->tm4[counter].freq, get_ticks_per_sec());
-
-    new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
-                    get_ticks_per_sec(), s->tm4[counter].freq);
-    qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
-}
-
-static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
-                                  unsigned size)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    int tm = 0;
-
-    switch (offset) {
-    case OSMR3:  tm ++;
-        /* fall through */
-    case OSMR2:  tm ++;
-        /* fall through */
-    case OSMR1:  tm ++;
-        /* fall through */
-    case OSMR0:
-        return s->timer[tm].value;
-    case OSMR11: tm ++;
-        /* fall through */
-    case OSMR10: tm ++;
-        /* fall through */
-    case OSMR9:  tm ++;
-        /* fall through */
-    case OSMR8:  tm ++;
-        /* fall through */
-    case OSMR7:  tm ++;
-        /* fall through */
-    case OSMR6:  tm ++;
-        /* fall through */
-    case OSMR5:  tm ++;
-        /* fall through */
-    case OSMR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        return s->tm4[tm].tm.value;
-    case OSCR:
-        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
-                        s->lastload, s->freq, get_ticks_per_sec());
-    case OSCR11: tm ++;
-        /* fall through */
-    case OSCR10: tm ++;
-        /* fall through */
-    case OSCR9:  tm ++;
-        /* fall through */
-    case OSCR8:  tm ++;
-        /* fall through */
-    case OSCR7:  tm ++;
-        /* fall through */
-    case OSCR6:  tm ++;
-        /* fall through */
-    case OSCR5:  tm ++;
-        /* fall through */
-    case OSCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-
-        if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
-            if (s->tm4[tm - 1].freq)
-                s->snapshot = s->tm4[tm - 1].clock + muldiv64(
-                                qemu_get_clock_ns(vm_clock) -
-                                s->tm4[tm - 1].lastload,
-                                s->tm4[tm - 1].freq, get_ticks_per_sec());
-            else
-                s->snapshot = s->tm4[tm - 1].clock;
-        }
-
-        if (!s->tm4[tm].freq)
-            return s->tm4[tm].clock;
-        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
-                        s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
-    case OIER:
-        return s->irq_enabled;
-    case OSSR: /* Status register */
-        return s->events;
-    case OWER:
-        return s->reset3;
-    case OMCR11: tm ++;
-        /* fall through */
-    case OMCR10: tm ++;
-        /* fall through */
-    case OMCR9:  tm ++;
-        /* fall through */
-    case OMCR8:  tm ++;
-        /* fall through */
-    case OMCR7:  tm ++;
-        /* fall through */
-    case OMCR6:  tm ++;
-        /* fall through */
-    case OMCR5:  tm ++;
-        /* fall through */
-    case OMCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        return s->tm4[tm].control;
-    case OSNR:
-        return s->snapshot;
-    default:
-    badreg:
-        hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_timer_write(void *opaque, hwaddr offset,
-                               uint64_t value, unsigned size)
-{
-    int i, tm = 0;
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-
-    switch (offset) {
-    case OSMR3:  tm ++;
-        /* fall through */
-    case OSMR2:  tm ++;
-        /* fall through */
-    case OSMR1:  tm ++;
-        /* fall through */
-    case OSMR0:
-        s->timer[tm].value = value;
-        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
-        break;
-    case OSMR11: tm ++;
-        /* fall through */
-    case OSMR10: tm ++;
-        /* fall through */
-    case OSMR9:  tm ++;
-        /* fall through */
-    case OSMR8:  tm ++;
-        /* fall through */
-    case OSMR7:  tm ++;
-        /* fall through */
-    case OSMR6:  tm ++;
-        /* fall through */
-    case OSMR5:  tm ++;
-        /* fall through */
-    case OSMR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].tm.value = value;
-        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
-        break;
-    case OSCR:
-        s->oldclock = s->clock;
-        s->lastload = qemu_get_clock_ns(vm_clock);
-        s->clock = value;
-        pxa2xx_timer_update(s, s->lastload);
-        break;
-    case OSCR11: tm ++;
-        /* fall through */
-    case OSCR10: tm ++;
-        /* fall through */
-    case OSCR9:  tm ++;
-        /* fall through */
-    case OSCR8:  tm ++;
-        /* fall through */
-    case OSCR7:  tm ++;
-        /* fall through */
-    case OSCR6:  tm ++;
-        /* fall through */
-    case OSCR5:  tm ++;
-        /* fall through */
-    case OSCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].oldclock = s->tm4[tm].clock;
-        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
-        s->tm4[tm].clock = value;
-        pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
-        break;
-    case OIER:
-        s->irq_enabled = value & 0xfff;
-        break;
-    case OSSR: /* Status register */
-        value &= s->events;
-        s->events &= ~value;
-        for (i = 0; i < 4; i ++, value >>= 1)
-            if (value & 1)
-                qemu_irq_lower(s->timer[i].irq);
-        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
-            qemu_irq_lower(s->irq4);
-        break;
-    case OWER: /* XXX: Reset on OSMR3 match? */
-        s->reset3 = value;
-        break;
-    case OMCR7:  tm ++;
-        /* fall through */
-    case OMCR6:  tm ++;
-        /* fall through */
-    case OMCR5:  tm ++;
-        /* fall through */
-    case OMCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].control = value & 0x0ff;
-        /* XXX Stop if running (shouldn't happen) */
-        if ((value & (1 << 7)) || tm == 0)
-            s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
-        else {
-            s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
-        }
-        break;
-    case OMCR11: tm ++;
-        /* fall through */
-    case OMCR10: tm ++;
-        /* fall through */
-    case OMCR9:  tm ++;
-        /* fall through */
-    case OMCR8:  tm += 4;
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].control = value & 0x3ff;
-        /* XXX Stop if running (shouldn't happen) */
-        if ((value & (1 << 7)) || !(tm & 1))
-            s->tm4[tm].freq =
-                    pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
-        else {
-            s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
-        }
-        break;
-    default:
-    badreg:
-        hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_timer_ops = {
-    .read = pxa2xx_timer_read,
-    .write = pxa2xx_timer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_timer_tick(void *opaque)
-{
-    PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
-    PXA2xxTimerInfo *i = t->info;
-
-    if (i->irq_enabled & (1 << t->num)) {
-        i->events |= 1 << t->num;
-        qemu_irq_raise(t->irq);
-    }
-
-    if (t->num == 3)
-        if (i->reset3 & 1) {
-            i->reset3 = 0;
-            qemu_system_reset_request();
-        }
-}
-
-static void pxa2xx_timer_tick4(void *opaque)
-{
-    PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
-    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
-
-    pxa2xx_timer_tick(&t->tm);
-    if (t->control & (1 << 3))
-        t->clock = 0;
-    if (t->control & (1 << 6))
-        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
-    if (i->events & 0xff0)
-        qemu_irq_raise(i->irq4);
-}
-
-static int pxa25x_timer_post_load(void *opaque, int version_id)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    int64_t now;
-    int i;
-
-    now = qemu_get_clock_ns(vm_clock);
-    pxa2xx_timer_update(s, now);
-
-    if (pxa2xx_timer_has_tm4(s))
-        for (i = 0; i < 8; i ++)
-            pxa2xx_timer_update4(s, now, i);
-
-    return 0;
-}
-
-static int pxa2xx_timer_init(SysBusDevice *dev)
-{
-    int i;
-    PXA2xxTimerInfo *s;
-
-    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
-    s->irq_enabled = 0;
-    s->oldclock = 0;
-    s->clock = 0;
-    s->lastload = qemu_get_clock_ns(vm_clock);
-    s->reset3 = 0;
-
-    for (i = 0; i < 4; i ++) {
-        s->timer[i].value = 0;
-        sysbus_init_irq(dev, &s->timer[i].irq);
-        s->timer[i].info = s;
-        s->timer[i].num = i;
-        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
-                        pxa2xx_timer_tick, &s->timer[i]);
-    }
-    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
-        sysbus_init_irq(dev, &s->irq4);
-
-        for (i = 0; i < 8; i ++) {
-            s->tm4[i].tm.value = 0;
-            s->tm4[i].tm.info = s;
-            s->tm4[i].tm.num = i + 4;
-            s->tm4[i].freq = 0;
-            s->tm4[i].control = 0x0;
-            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
-                        pxa2xx_timer_tick4, &s->tm4[i]);
-        }
-    }
-
-    memory_region_init_io(&s->iomem, &pxa2xx_timer_ops, s,
-                          "pxa2xx-timer", 0x00001000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
-    .name = "pxa2xx_timer0",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(value, PXA2xxTimer0),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
-    .name = "pxa2xx_timer4",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
-                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
-        VMSTATE_INT32(oldclock, PXA2xxTimer4),
-        VMSTATE_INT32(clock, PXA2xxTimer4),
-        VMSTATE_UINT64(lastload, PXA2xxTimer4),
-        VMSTATE_UINT32(freq, PXA2xxTimer4),
-        VMSTATE_UINT32(control, PXA2xxTimer4),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
-{
-    return pxa2xx_timer_has_tm4(opaque);
-}
-
-static const VMStateDescription vmstate_pxa2xx_timer_regs = {
-    .name = "pxa2xx_timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = pxa25x_timer_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(clock, PXA2xxTimerInfo),
-        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
-        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
-        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
-                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
-        VMSTATE_UINT32(events, PXA2xxTimerInfo),
-        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
-        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
-        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
-        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
-                        pxa2xx_timer_has_tm4_test, 0,
-                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
-        VMSTATE_END_OF_LIST(),
-    }
-};
-
-static Property pxa25x_timer_dev_properties[] = {
-    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
-    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
-    PXA2XX_TIMER_HAVE_TM4, false),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pxa2xx_timer_init;
-    dc->desc = "PXA25x timer";
-    dc->vmsd = &vmstate_pxa2xx_timer_regs;
-    dc->props = pxa25x_timer_dev_properties;
-}
-
-static const TypeInfo pxa25x_timer_dev_info = {
-    .name          = "pxa25x-timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PXA2xxTimerInfo),
-    .class_init    = pxa25x_timer_dev_class_init,
-};
-
-static Property pxa27x_timer_dev_properties[] = {
-    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
-    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
-    PXA2XX_TIMER_HAVE_TM4, true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pxa2xx_timer_init;
-    dc->desc = "PXA27x timer";
-    dc->vmsd = &vmstate_pxa2xx_timer_regs;
-    dc->props = pxa27x_timer_dev_properties;
-}
-
-static const TypeInfo pxa27x_timer_dev_info = {
-    .name          = "pxa27x-timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PXA2xxTimerInfo),
-    .class_init    = pxa27x_timer_dev_class_init,
-};
-
-static void pxa2xx_timer_register_types(void)
-{
-    type_register_static(&pxa25x_timer_dev_info);
-    type_register_static(&pxa27x_timer_dev_info);
-}
-
-type_init(pxa2xx_timer_register_types)
index 10c971a3006ebf4b280bf2ceb899c4d08943b46b..76b37bbf6bd95eb25e2712ae6cdbdb9e72277cd4 100644 (file)
@@ -1,4 +1,4 @@
-obj-y += sh_timer.o sh_intc.o sh_pci.o
+obj-y += sh_intc.o sh_pci.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/sh_timer.c b/hw/sh_timer.c
deleted file mode 100644 (file)
index f92ff4f..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * SuperH Timer modules.
- *
- * Copyright (c) 2007 Magnus Damm
- * Based on arm_timer.c by Paul Brook
- * Copyright (c) 2005-2006 CodeSourcery.
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-#include "hw/ptimer.h"
-
-//#define DEBUG_TIMER
-
-#define TIMER_TCR_TPSC          (7 << 0)
-#define TIMER_TCR_CKEG          (3 << 3)
-#define TIMER_TCR_UNIE          (1 << 5)
-#define TIMER_TCR_ICPE          (3 << 6)
-#define TIMER_TCR_UNF           (1 << 8)
-#define TIMER_TCR_ICPF          (1 << 9)
-#define TIMER_TCR_RESERVED      (0x3f << 10)
-
-#define TIMER_FEAT_CAPT   (1 << 0)
-#define TIMER_FEAT_EXTCLK (1 << 1)
-
-#define OFFSET_TCOR   0
-#define OFFSET_TCNT   1
-#define OFFSET_TCR    2
-#define OFFSET_TCPR   3
-
-typedef struct {
-    ptimer_state *timer;
-    uint32_t tcnt;
-    uint32_t tcor;
-    uint32_t tcr;
-    uint32_t tcpr;
-    int freq;
-    int int_level;
-    int old_level;
-    int feat;
-    int enabled;
-    qemu_irq irq;
-} sh_timer_state;
-
-/* Check all active timers, and schedule the next timer interrupt. */
-
-static void sh_timer_update(sh_timer_state *s)
-{
-    int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
-
-    if (new_level != s->old_level)
-      qemu_set_irq (s->irq, new_level);
-
-    s->old_level = s->int_level;
-    s->int_level = new_level;
-}
-
-static uint32_t sh_timer_read(void *opaque, hwaddr offset)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-
-    switch (offset >> 2) {
-    case OFFSET_TCOR:
-        return s->tcor;
-    case OFFSET_TCNT:
-        return ptimer_get_count(s->timer);
-    case OFFSET_TCR:
-        return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
-    case OFFSET_TCPR:
-        if (s->feat & TIMER_FEAT_CAPT)
-            return s->tcpr;
-    default:
-        hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void sh_timer_write(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-    int freq;
-
-    switch (offset >> 2) {
-    case OFFSET_TCOR:
-        s->tcor = value;
-        ptimer_set_limit(s->timer, s->tcor, 0);
-        break;
-    case OFFSET_TCNT:
-        s->tcnt = value;
-        ptimer_set_count(s->timer, s->tcnt);
-        break;
-    case OFFSET_TCR:
-        if (s->enabled) {
-            /* Pause the timer if it is running.  This may cause some
-               inaccuracy dure to rounding, but avoids a whole lot of other
-               messyness.  */
-            ptimer_stop(s->timer);
-        }
-        freq = s->freq;
-        /* ??? Need to recalculate expiry time after changing divisor.  */
-        switch (value & TIMER_TCR_TPSC) {
-        case 0: freq >>= 2; break;
-        case 1: freq >>= 4; break;
-        case 2: freq >>= 6; break;
-        case 3: freq >>= 8; break;
-        case 4: freq >>= 10; break;
-       case 6:
-       case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
-       default: hw_error("sh_timer_write: Reserved TPSC value\n"); break;
-        }
-        switch ((value & TIMER_TCR_CKEG) >> 3) {
-       case 0: break;
-        case 1:
-        case 2:
-        case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
-       default: hw_error("sh_timer_write: Reserved CKEG value\n"); break;
-        }
-        switch ((value & TIMER_TCR_ICPE) >> 6) {
-       case 0: break;
-        case 2:
-        case 3: if (s->feat & TIMER_FEAT_CAPT) break;
-       default: hw_error("sh_timer_write: Reserved ICPE value\n"); break;
-        }
-       if ((value & TIMER_TCR_UNF) == 0)
-            s->int_level = 0;
-
-       value &= ~TIMER_TCR_UNF;
-
-       if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
-            hw_error("sh_timer_write: Reserved ICPF value\n");
-
-       value &= ~TIMER_TCR_ICPF; /* capture not supported */
-
-       if (value & TIMER_TCR_RESERVED)
-            hw_error("sh_timer_write: Reserved TCR bits set\n");
-        s->tcr = value;
-        ptimer_set_limit(s->timer, s->tcor, 0);
-        ptimer_set_freq(s->timer, freq);
-        if (s->enabled) {
-            /* Restart the timer if still enabled.  */
-            ptimer_run(s->timer, 0);
-        }
-        break;
-    case OFFSET_TCPR:
-        if (s->feat & TIMER_FEAT_CAPT) {
-            s->tcpr = value;
-           break;
-       }
-    default:
-        hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
-    }
-    sh_timer_update(s);
-}
-
-static void sh_timer_start_stop(void *opaque, int enable)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-
-#ifdef DEBUG_TIMER
-    printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
-#endif
-
-    if (s->enabled && !enable) {
-        ptimer_stop(s->timer);
-    }
-    if (!s->enabled && enable) {
-        ptimer_run(s->timer, 0);
-    }
-    s->enabled = !!enable;
-
-#ifdef DEBUG_TIMER
-    printf("sh_timer_start_stop done %d\n", s->enabled);
-#endif
-}
-
-static void sh_timer_tick(void *opaque)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-    s->int_level = s->enabled;
-    sh_timer_update(s);
-}
-
-static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
-{
-    sh_timer_state *s;
-    QEMUBH *bh;
-
-    s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
-    s->freq = freq;
-    s->feat = feat;
-    s->tcor = 0xffffffff;
-    s->tcnt = 0xffffffff;
-    s->tcpr = 0xdeadbeef;
-    s->tcr = 0;
-    s->enabled = 0;
-    s->irq = irq;
-
-    bh = qemu_bh_new(sh_timer_tick, s);
-    s->timer = ptimer_init(bh);
-
-    sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
-    sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
-    sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr);
-    sh_timer_write(s, OFFSET_TCR  >> 2, s->tcpr);
-    /* ??? Save/restore.  */
-    return s;
-}
-
-typedef struct {
-    MemoryRegion iomem;
-    MemoryRegion iomem_p4;
-    MemoryRegion iomem_a7;
-    void *timer[3];
-    int level[3];
-    uint32_t tocr;
-    uint32_t tstr;
-    int feat;
-} tmu012_state;
-
-static uint64_t tmu012_read(void *opaque, hwaddr offset,
-                            unsigned size)
-{
-    tmu012_state *s = (tmu012_state *)opaque;
-
-#ifdef DEBUG_TIMER
-    printf("tmu012_read 0x%lx\n", (unsigned long) offset);
-#endif
-
-    if (offset >= 0x20) {
-        if (!(s->feat & TMU012_FEAT_3CHAN))
-           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
-        return sh_timer_read(s->timer[2], offset - 0x20);
-    }
-
-    if (offset >= 0x14)
-        return sh_timer_read(s->timer[1], offset - 0x14);
-
-    if (offset >= 0x08)
-        return sh_timer_read(s->timer[0], offset - 0x08);
-
-    if (offset == 4)
-        return s->tstr;
-
-    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
-        return s->tocr;
-
-    hw_error("tmu012_write: Bad offset %x\n", (int)offset);
-    return 0;
-}
-
-static void tmu012_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    tmu012_state *s = (tmu012_state *)opaque;
-
-#ifdef DEBUG_TIMER
-    printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
-#endif
-
-    if (offset >= 0x20) {
-        if (!(s->feat & TMU012_FEAT_3CHAN))
-           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
-        sh_timer_write(s->timer[2], offset - 0x20, value);
-       return;
-    }
-
-    if (offset >= 0x14) {
-        sh_timer_write(s->timer[1], offset - 0x14, value);
-       return;
-    }
-
-    if (offset >= 0x08) {
-        sh_timer_write(s->timer[0], offset - 0x08, value);
-       return;
-    }
-
-    if (offset == 4) {
-        sh_timer_start_stop(s->timer[0], value & (1 << 0));
-        sh_timer_start_stop(s->timer[1], value & (1 << 1));
-        if (s->feat & TMU012_FEAT_3CHAN)
-            sh_timer_start_stop(s->timer[2], value & (1 << 2));
-       else
-            if (value & (1 << 2))
-                hw_error("tmu012_write: Bad channel\n");
-
-       s->tstr = value;
-       return;
-    }
-
-    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
-        s->tocr = value & (1 << 0);
-    }
-}
-
-static const MemoryRegionOps tmu012_ops = {
-    .read = tmu012_read,
-    .write = tmu012_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void tmu012_init(MemoryRegion *sysmem, hwaddr base,
-                 int feat, uint32_t freq,
-                qemu_irq ch0_irq, qemu_irq ch1_irq,
-                qemu_irq ch2_irq0, qemu_irq ch2_irq1)
-{
-    tmu012_state *s;
-    int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
-
-    s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
-    s->feat = feat;
-    s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
-    s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
-    if (feat & TMU012_FEAT_3CHAN)
-        s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
-                                   ch2_irq0); /* ch2_irq1 not supported */
-
-    memory_region_init_io(&s->iomem, &tmu012_ops, s,
-                          "timer", 0x100000000ULL);
-
-    memory_region_init_alias(&s->iomem_p4, "timer-p4",
-                             &s->iomem, 0, 0x1000);
-    memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
-
-    memory_region_init_alias(&s->iomem_a7, "timer-a7",
-                             &s->iomem, 0, 0x1000);
-    memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
-    /* ??? Save/restore.  */
-}
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
deleted file mode 100644 (file)
index 1145a87..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * QEMU Sparc SLAVIO timer controller emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sparc/sun4m.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * Registers of hardware timer in sun4m.
- *
- * This is the timer/counter part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
- * are zero. Bit 31 is 1 when count has been reached.
- *
- * Per-CPU timers interrupt local CPU, system timer uses normal
- * interrupt routing.
- *
- */
-
-#define MAX_CPUS 16
-
-typedef struct CPUTimerState {
-    qemu_irq irq;
-    ptimer_state *timer;
-    uint32_t count, counthigh, reached;
-    /* processor only */
-    uint32_t running;
-    uint64_t limit;
-} CPUTimerState;
-
-typedef struct SLAVIO_TIMERState {
-    SysBusDevice busdev;
-    uint32_t num_cpus;
-    uint32_t cputimer_mode;
-    CPUTimerState cputimer[MAX_CPUS + 1];
-} SLAVIO_TIMERState;
-
-typedef struct TimerContext {
-    MemoryRegion iomem;
-    SLAVIO_TIMERState *s;
-    unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
-} TimerContext;
-
-#define SYS_TIMER_SIZE 0x14
-#define CPU_TIMER_SIZE 0x10
-
-#define TIMER_LIMIT         0
-#define TIMER_COUNTER       1
-#define TIMER_COUNTER_NORST 2
-#define TIMER_STATUS        3
-#define TIMER_MODE          4
-
-#define TIMER_COUNT_MASK32 0xfffffe00
-#define TIMER_LIMIT_MASK32 0x7fffffff
-#define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
-#define TIMER_MAX_COUNT32  0x7ffffe00ULL
-#define TIMER_REACHED      0x80000000
-#define TIMER_PERIOD       500ULL // 500ns
-#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
-#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
-
-static int slavio_timer_is_user(TimerContext *tc)
-{
-    SLAVIO_TIMERState *s = tc->s;
-    unsigned int timer_index = tc->timer_index;
-
-    return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
-}
-
-// Update count, set irq, update expire_time
-// Convert from ptimer countdown units
-static void slavio_timer_get_out(CPUTimerState *t)
-{
-    uint64_t count, limit;
-
-    if (t->limit == 0) { /* free-run system or processor counter */
-        limit = TIMER_MAX_COUNT32;
-    } else {
-        limit = t->limit;
-    }
-    count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
-
-    trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
-    t->count = count & TIMER_COUNT_MASK32;
-    t->counthigh = count >> 32;
-}
-
-// timer callback
-static void slavio_timer_irq(void *opaque)
-{
-    TimerContext *tc = opaque;
-    SLAVIO_TIMERState *s = tc->s;
-    CPUTimerState *t = &s->cputimer[tc->timer_index];
-
-    slavio_timer_get_out(t);
-    trace_slavio_timer_irq(t->counthigh, t->count);
-    /* if limit is 0 (free-run), there will be no match */
-    if (t->limit != 0) {
-        t->reached = TIMER_REACHED;
-    }
-    /* there is no interrupt if user timer or free-run */
-    if (!slavio_timer_is_user(tc) && t->limit != 0) {
-        qemu_irq_raise(t->irq);
-    }
-}
-
-static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
-                                       unsigned size)
-{
-    TimerContext *tc = opaque;
-    SLAVIO_TIMERState *s = tc->s;
-    uint32_t saddr, ret;
-    unsigned int timer_index = tc->timer_index;
-    CPUTimerState *t = &s->cputimer[timer_index];
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case TIMER_LIMIT:
-        // read limit (system counter mode) or read most signifying
-        // part of counter (user mode)
-        if (slavio_timer_is_user(tc)) {
-            // read user timer MSW
-            slavio_timer_get_out(t);
-            ret = t->counthigh | t->reached;
-        } else {
-            // read limit
-            // clear irq
-            qemu_irq_lower(t->irq);
-            t->reached = 0;
-            ret = t->limit & TIMER_LIMIT_MASK32;
-        }
-        break;
-    case TIMER_COUNTER:
-        // read counter and reached bit (system mode) or read lsbits
-        // of counter (user mode)
-        slavio_timer_get_out(t);
-        if (slavio_timer_is_user(tc)) { // read user timer LSW
-            ret = t->count & TIMER_MAX_COUNT64;
-        } else { // read limit
-            ret = (t->count & TIMER_MAX_COUNT32) |
-                t->reached;
-        }
-        break;
-    case TIMER_STATUS:
-        // only available in processor counter/timer
-        // read start/stop status
-        if (timer_index > 0) {
-            ret = t->running;
-        } else {
-            ret = 0;
-        }
-        break;
-    case TIMER_MODE:
-        // only available in system counter
-        // read user/system mode
-        ret = s->cputimer_mode;
-        break;
-    default:
-        trace_slavio_timer_mem_readl_invalid(addr);
-        ret = 0;
-        break;
-    }
-    trace_slavio_timer_mem_readl(addr, ret);
-    return ret;
-}
-
-static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
-                                    uint64_t val, unsigned size)
-{
-    TimerContext *tc = opaque;
-    SLAVIO_TIMERState *s = tc->s;
-    uint32_t saddr;
-    unsigned int timer_index = tc->timer_index;
-    CPUTimerState *t = &s->cputimer[timer_index];
-
-    trace_slavio_timer_mem_writel(addr, val);
-    saddr = addr >> 2;
-    switch (saddr) {
-    case TIMER_LIMIT:
-        if (slavio_timer_is_user(tc)) {
-            uint64_t count;
-
-            // set user counter MSW, reset counter
-            t->limit = TIMER_MAX_COUNT64;
-            t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
-            t->reached = 0;
-            count = ((uint64_t)t->counthigh << 32) | t->count;
-            trace_slavio_timer_mem_writel_limit(timer_index, count);
-            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
-        } else {
-            // set limit, reset counter
-            qemu_irq_lower(t->irq);
-            t->limit = val & TIMER_MAX_COUNT32;
-            if (t->timer) {
-                if (t->limit == 0) { /* free-run */
-                    ptimer_set_limit(t->timer,
-                                     LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
-                } else {
-                    ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
-                }
-            }
-        }
-        break;
-    case TIMER_COUNTER:
-        if (slavio_timer_is_user(tc)) {
-            uint64_t count;
-
-            // set user counter LSW, reset counter
-            t->limit = TIMER_MAX_COUNT64;
-            t->count = val & TIMER_MAX_COUNT64;
-            t->reached = 0;
-            count = ((uint64_t)t->counthigh) << 32 | t->count;
-            trace_slavio_timer_mem_writel_limit(timer_index, count);
-            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
-        } else {
-            trace_slavio_timer_mem_writel_counter_invalid();
-        }
-        break;
-    case TIMER_COUNTER_NORST:
-        // set limit without resetting counter
-        t->limit = val & TIMER_MAX_COUNT32;
-        if (t->limit == 0) { /* free-run */
-            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
-        } else {
-            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
-        }
-        break;
-    case TIMER_STATUS:
-        if (slavio_timer_is_user(tc)) {
-            // start/stop user counter
-            if ((val & 1) && !t->running) {
-                trace_slavio_timer_mem_writel_status_start(timer_index);
-                ptimer_run(t->timer, 0);
-                t->running = 1;
-            } else if (!(val & 1) && t->running) {
-                trace_slavio_timer_mem_writel_status_stop(timer_index);
-                ptimer_stop(t->timer);
-                t->running = 0;
-            }
-        }
-        break;
-    case TIMER_MODE:
-        if (timer_index == 0) {
-            unsigned int i;
-
-            for (i = 0; i < s->num_cpus; i++) {
-                unsigned int processor = 1 << i;
-                CPUTimerState *curr_timer = &s->cputimer[i + 1];
-
-                // check for a change in timer mode for this processor
-                if ((val & processor) != (s->cputimer_mode & processor)) {
-                    if (val & processor) { // counter -> user timer
-                        qemu_irq_lower(curr_timer->irq);
-                        // counters are always running
-                        ptimer_stop(curr_timer->timer);
-                        curr_timer->running = 0;
-                        // user timer limit is always the same
-                        curr_timer->limit = TIMER_MAX_COUNT64;
-                        ptimer_set_limit(curr_timer->timer,
-                                         LIMIT_TO_PERIODS(curr_timer->limit),
-                                         1);
-                        // set this processors user timer bit in config
-                        // register
-                        s->cputimer_mode |= processor;
-                        trace_slavio_timer_mem_writel_mode_user(timer_index);
-                    } else { // user timer -> counter
-                        // stop the user timer if it is running
-                        if (curr_timer->running) {
-                            ptimer_stop(curr_timer->timer);
-                        }
-                        // start the counter
-                        ptimer_run(curr_timer->timer, 0);
-                        curr_timer->running = 1;
-                        // clear this processors user timer bit in config
-                        // register
-                        s->cputimer_mode &= ~processor;
-                        trace_slavio_timer_mem_writel_mode_counter(timer_index);
-                    }
-                }
-            }
-        } else {
-            trace_slavio_timer_mem_writel_mode_invalid();
-        }
-        break;
-    default:
-        trace_slavio_timer_mem_writel_invalid(addr);
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_timer_mem_ops = {
-    .read = slavio_timer_mem_readl,
-    .write = slavio_timer_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const VMStateDescription vmstate_timer = {
-    .name ="timer",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT64(limit, CPUTimerState),
-        VMSTATE_UINT32(count, CPUTimerState),
-        VMSTATE_UINT32(counthigh, CPUTimerState),
-        VMSTATE_UINT32(reached, CPUTimerState),
-        VMSTATE_UINT32(running, CPUTimerState),
-        VMSTATE_PTIMER(timer, CPUTimerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slavio_timer = {
-    .name ="slavio_timer",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
-                             vmstate_timer, CPUTimerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void slavio_timer_reset(DeviceState *d)
-{
-    SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
-    unsigned int i;
-    CPUTimerState *curr_timer;
-
-    for (i = 0; i <= MAX_CPUS; i++) {
-        curr_timer = &s->cputimer[i];
-        curr_timer->limit = 0;
-        curr_timer->count = 0;
-        curr_timer->reached = 0;
-        if (i <= s->num_cpus) {
-            ptimer_set_limit(curr_timer->timer,
-                             LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
-            ptimer_run(curr_timer->timer, 0);
-            curr_timer->running = 1;
-        }
-    }
-    s->cputimer_mode = 0;
-}
-
-static int slavio_timer_init1(SysBusDevice *dev)
-{
-    SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
-    QEMUBH *bh;
-    unsigned int i;
-    TimerContext *tc;
-
-    for (i = 0; i <= MAX_CPUS; i++) {
-        uint64_t size;
-        char timer_name[20];
-
-        tc = g_malloc0(sizeof(TimerContext));
-        tc->s = s;
-        tc->timer_index = i;
-
-        bh = qemu_bh_new(slavio_timer_irq, tc);
-        s->cputimer[i].timer = ptimer_init(bh);
-        ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
-
-        size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
-        snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
-        memory_region_init_io(&tc->iomem, &slavio_timer_mem_ops, tc,
-                              timer_name, size);
-        sysbus_init_mmio(dev, &tc->iomem);
-
-        sysbus_init_irq(dev, &s->cputimer[i].irq);
-    }
-
-    return 0;
-}
-
-static Property slavio_timer_properties[] = {
-    DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void slavio_timer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = slavio_timer_init1;
-    dc->reset = slavio_timer_reset;
-    dc->vmsd = &vmstate_slavio_timer;
-    dc->props = slavio_timer_properties;
-}
-
-static const TypeInfo slavio_timer_info = {
-    .name          = "slavio_timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SLAVIO_TIMERState),
-    .class_init    = slavio_timer_class_init,
-};
-
-static void slavio_timer_register_types(void)
-{
-    type_register_static(&slavio_timer_info);
-}
-
-type_init(slavio_timer_register_types)
index e18bc67fc7ebdbefad0b4b38e7f1a49c900b0af6..ab1d91c2b909f76a180b606c5dc2dbd6c6d7a8bf 100644 (file)
@@ -1,9 +1,9 @@
 obj-y = sun4m_iommu.o slavio_intctl.o
-obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o
+obj-y += slavio_misc.o sparc32_dma.o
 obj-y += eccmemctl.o sbi.o sun4c_intctl.o
 
 # GRLIB
-obj-y += grlib_gptimer.o grlib_irqmp.o
+obj-y += grlib_irqmp.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
index a1ef26cf34bf003b161ecfa2f514f3cd78443e41..e4bd17fbb7d0fd5ed71d2bea5710001b767fa46a 100644 (file)
@@ -8,5 +8,21 @@ common-obj-$(CONFIG_PL031) += pl031.o
 common-obj-$(CONFIG_PUV3) += puv3_ost.o
 common-obj-$(CONFIG_TWL92230) += twl92230.o
 common-obj-$(CONFIG_XILINX) += xilinx_timer.o
+common-obj-$(CONFIG_SLAVIO) += slavio_timer.o
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o
+common-obj-$(CONFIG_GRLIB) += grlib_gptimer.o
+common-obj-$(CONFIG_IMX) += imx_timer.o
+common-obj-$(CONFIG_LM32) += lm32_timer.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
 
+obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o
+obj-$(CONFIG_OMAP) += omap_gptimer.o
+obj-$(CONFIG_OMAP) += omap_synctimer.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
+obj-$(CONFIG_SH4) += sh_timer.o
+obj-$(CONFIG_TUSB6010) += tusb6010.o
+
+obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
new file mode 100644 (file)
index 0000000..317f5e4
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Paul Brook, Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+
+/* This device implements the per-cpu private timer and watchdog block
+ * which is used in both the ARM11MPCore and Cortex-A9MP.
+ */
+
+#define MAX_CPUS 4
+
+/* State of a single timer or watchdog block */
+typedef struct {
+    uint32_t count;
+    uint32_t load;
+    uint32_t control;
+    uint32_t status;
+    int64_t tick;
+    QEMUTimer *timer;
+    qemu_irq irq;
+    MemoryRegion iomem;
+} TimerBlock;
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t num_cpu;
+    TimerBlock timerblock[MAX_CPUS];
+    MemoryRegion iomem;
+} ARMMPTimerState;
+
+static inline int get_current_cpu(ARMMPTimerState *s)
+{
+    CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
+
+    if (cpu_single_cpu->cpu_index >= s->num_cpu) {
+        hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
+                 s->num_cpu, cpu_single_cpu->cpu_index);
+    }
+    return cpu_single_cpu->cpu_index;
+}
+
+static inline void timerblock_update_irq(TimerBlock *tb)
+{
+    qemu_set_irq(tb->irq, tb->status);
+}
+
+/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
+static inline uint32_t timerblock_scale(TimerBlock *tb)
+{
+    return (((tb->control >> 8) & 0xff) + 1) * 10;
+}
+
+static void timerblock_reload(TimerBlock *tb, int restart)
+{
+    if (tb->count == 0) {
+        return;
+    }
+    if (restart) {
+        tb->tick = qemu_get_clock_ns(vm_clock);
+    }
+    tb->tick += (int64_t)tb->count * timerblock_scale(tb);
+    qemu_mod_timer(tb->timer, tb->tick);
+}
+
+static void timerblock_tick(void *opaque)
+{
+    TimerBlock *tb = (TimerBlock *)opaque;
+    tb->status = 1;
+    if (tb->control & 2) {
+        tb->count = tb->load;
+        timerblock_reload(tb, 0);
+    } else {
+        tb->count = 0;
+    }
+    timerblock_update_irq(tb);
+}
+
+static uint64_t timerblock_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    TimerBlock *tb = (TimerBlock *)opaque;
+    int64_t val;
+    switch (addr) {
+    case 0: /* Load */
+        return tb->load;
+    case 4: /* Counter.  */
+        if (((tb->control & 1) == 0) || (tb->count == 0)) {
+            return 0;
+        }
+        /* Slow and ugly, but hopefully won't happen too often.  */
+        val = tb->tick - qemu_get_clock_ns(vm_clock);
+        val /= timerblock_scale(tb);
+        if (val < 0) {
+            val = 0;
+        }
+        return val;
+    case 8: /* Control.  */
+        return tb->control;
+    case 12: /* Interrupt status.  */
+        return tb->status;
+    default:
+        return 0;
+    }
+}
+
+static void timerblock_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    TimerBlock *tb = (TimerBlock *)opaque;
+    int64_t old;
+    switch (addr) {
+    case 0: /* Load */
+        tb->load = value;
+        /* Fall through.  */
+    case 4: /* Counter.  */
+        if ((tb->control & 1) && tb->count) {
+            /* Cancel the previous timer.  */
+            qemu_del_timer(tb->timer);
+        }
+        tb->count = value;
+        if (tb->control & 1) {
+            timerblock_reload(tb, 1);
+        }
+        break;
+    case 8: /* Control.  */
+        old = tb->control;
+        tb->control = value;
+        if (((old & 1) == 0) && (value & 1)) {
+            if (tb->count == 0 && (tb->control & 2)) {
+                tb->count = tb->load;
+            }
+            timerblock_reload(tb, 1);
+        }
+        break;
+    case 12: /* Interrupt status.  */
+        tb->status &= ~value;
+        timerblock_update_irq(tb);
+        break;
+    }
+}
+
+/* Wrapper functions to implement the "read timer/watchdog for
+ * the current CPU" memory regions.
+ */
+static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
+    int id = get_current_cpu(s);
+    return timerblock_read(&s->timerblock[id], addr, size);
+}
+
+static void arm_thistimer_write(void *opaque, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
+    int id = get_current_cpu(s);
+    timerblock_write(&s->timerblock[id], addr, value, size);
+}
+
+static const MemoryRegionOps arm_thistimer_ops = {
+    .read = arm_thistimer_read,
+    .write = arm_thistimer_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps timerblock_ops = {
+    .read = timerblock_read,
+    .write = timerblock_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timerblock_reset(TimerBlock *tb)
+{
+    tb->count = 0;
+    tb->load = 0;
+    tb->control = 0;
+    tb->status = 0;
+    tb->tick = 0;
+    if (tb->timer) {
+        qemu_del_timer(tb->timer);
+    }
+}
+
+static void arm_mptimer_reset(DeviceState *dev)
+{
+    ARMMPTimerState *s =
+        FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev));
+    int i;
+    for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
+        timerblock_reset(&s->timerblock[i]);
+    }
+}
+
+static int arm_mptimer_init(SysBusDevice *dev)
+{
+    ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, dev);
+    int i;
+    if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
+        hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
+    }
+    /* We implement one timer block per CPU, and expose multiple MMIO regions:
+     *  * region 0 is "timer for this core"
+     *  * region 1 is "timer for core 0"
+     *  * region 2 is "timer for core 1"
+     * and so on.
+     * The outgoing interrupt lines are
+     *  * timer for core 0
+     *  * timer for core 1
+     * and so on.
+     */
+    memory_region_init_io(&s->iomem, &arm_thistimer_ops, s,
+                          "arm_mptimer_timer", 0x20);
+    sysbus_init_mmio(dev, &s->iomem);
+    for (i = 0; i < s->num_cpu; i++) {
+        TimerBlock *tb = &s->timerblock[i];
+        tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
+        sysbus_init_irq(dev, &tb->irq);
+        memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
+                              "arm_mptimer_timerblock", 0x20);
+        sysbus_init_mmio(dev, &tb->iomem);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_timerblock = {
+    .name = "arm_mptimer_timerblock",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(count, TimerBlock),
+        VMSTATE_UINT32(load, TimerBlock),
+        VMSTATE_UINT32(control, TimerBlock),
+        VMSTATE_UINT32(status, TimerBlock),
+        VMSTATE_INT64(tick, TimerBlock),
+        VMSTATE_TIMER(timer, TimerBlock),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_arm_mptimer = {
+    .name = "arm_mptimer",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
+                                     2, vmstate_timerblock, TimerBlock),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property arm_mptimer_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void arm_mptimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = arm_mptimer_init;
+    dc->vmsd = &vmstate_arm_mptimer;
+    dc->reset = arm_mptimer_reset;
+    dc->no_user = 1;
+    dc->props = arm_mptimer_properties;
+}
+
+static const TypeInfo arm_mptimer_info = {
+    .name          = "arm_mptimer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ARMMPTimerState),
+    .class_init    = arm_mptimer_class_init,
+};
+
+static void arm_mptimer_register_types(void)
+{
+    type_register_static(&arm_mptimer_info);
+}
+
+type_init(arm_mptimer_register_types)
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
new file mode 100644 (file)
index 0000000..3cd9476
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * QEMU ETRAX Timers
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+
+#define D(x)
+
+#define RW_TMR0_DIV   0x00
+#define R_TMR0_DATA   0x04
+#define RW_TMR0_CTRL  0x08
+#define RW_TMR1_DIV   0x10
+#define R_TMR1_DATA   0x14
+#define RW_TMR1_CTRL  0x18
+#define R_TIME        0x38
+#define RW_WD_CTRL    0x40
+#define R_WD_STAT     0x44
+#define RW_INTR_MASK  0x48
+#define RW_ACK_INTR   0x4c
+#define R_INTR        0x50
+#define R_MASKED_INTR 0x54
+
+struct etrax_timer {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    qemu_irq nmi;
+
+    QEMUBH *bh_t0;
+    QEMUBH *bh_t1;
+    QEMUBH *bh_wd;
+    ptimer_state *ptimer_t0;
+    ptimer_state *ptimer_t1;
+    ptimer_state *ptimer_wd;
+
+    int wd_hits;
+
+    /* Control registers.  */
+    uint32_t rw_tmr0_div;
+    uint32_t r_tmr0_data;
+    uint32_t rw_tmr0_ctrl;
+
+    uint32_t rw_tmr1_div;
+    uint32_t r_tmr1_data;
+    uint32_t rw_tmr1_ctrl;
+
+    uint32_t rw_wd_ctrl;
+
+    uint32_t rw_intr_mask;
+    uint32_t rw_ack_intr;
+    uint32_t r_intr;
+    uint32_t r_masked_intr;
+};
+
+static uint64_t
+timer_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct etrax_timer *t = opaque;
+    uint32_t r = 0;
+
+    switch (addr) {
+    case R_TMR0_DATA:
+        r = ptimer_get_count(t->ptimer_t0);
+        break;
+    case R_TMR1_DATA:
+        r = ptimer_get_count(t->ptimer_t1);
+        break;
+    case R_TIME:
+        r = qemu_get_clock_ns(vm_clock) / 10;
+        break;
+    case RW_INTR_MASK:
+        r = t->rw_intr_mask;
+        break;
+    case R_MASKED_INTR:
+        r = t->r_intr & t->rw_intr_mask;
+        break;
+    default:
+        D(printf ("%s %x\n", __func__, addr));
+        break;
+    }
+    return r;
+}
+
+static void update_ctrl(struct etrax_timer *t, int tnum)
+{
+    unsigned int op;
+    unsigned int freq;
+    unsigned int freq_hz;
+    unsigned int div;
+    uint32_t ctrl;
+
+    ptimer_state *timer;
+
+    if (tnum == 0) {
+        ctrl = t->rw_tmr0_ctrl;
+        div = t->rw_tmr0_div;
+        timer = t->ptimer_t0;
+    } else {
+        ctrl = t->rw_tmr1_ctrl;
+        div = t->rw_tmr1_div;
+        timer = t->ptimer_t1;
+    }
+
+
+    op = ctrl & 3;
+    freq = ctrl >> 2;
+    freq_hz = 32000000;
+
+    switch (freq)
+    {
+    case 0:
+    case 1:
+        D(printf ("extern or disabled timer clock?\n"));
+        break;
+    case 4: freq_hz =  29493000; break;
+    case 5: freq_hz =  32000000; break;
+    case 6: freq_hz =  32768000; break;
+    case 7: freq_hz = 100000000; break;
+    default:
+        abort();
+        break;
+    }
+
+    D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
+    ptimer_set_freq(timer, freq_hz);
+    ptimer_set_limit(timer, div, 0);
+
+    switch (op)
+    {
+        case 0:
+            /* Load.  */
+            ptimer_set_limit(timer, div, 1);
+            break;
+        case 1:
+            /* Hold.  */
+            ptimer_stop(timer);
+            break;
+        case 2:
+            /* Run.  */
+            ptimer_run(timer, 0);
+            break;
+        default:
+            abort();
+            break;
+    }
+}
+
+static void timer_update_irq(struct etrax_timer *t)
+{
+    t->r_intr &= ~(t->rw_ack_intr);
+    t->r_masked_intr = t->r_intr & t->rw_intr_mask;
+
+    D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
+    qemu_set_irq(t->irq, !!t->r_masked_intr);
+}
+
+static void timer0_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    t->r_intr |= 1;
+    timer_update_irq(t);
+}
+
+static void timer1_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    t->r_intr |= 2;
+    timer_update_irq(t);
+}
+
+static void watchdog_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    if (t->wd_hits == 0) {
+        /* real hw gives a single tick before reseting but we are
+           a bit friendlier to compensate for our slower execution.  */
+        ptimer_set_count(t->ptimer_wd, 10);
+        ptimer_run(t->ptimer_wd, 1);
+        qemu_irq_raise(t->nmi);
+    }
+    else
+        qemu_system_reset_request();
+
+    t->wd_hits++;
+}
+
+static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
+{
+    unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
+    unsigned int wd_key = t->rw_wd_ctrl >> 9;
+    unsigned int wd_cnt = t->rw_wd_ctrl & 511;
+    unsigned int new_key = value >> 9 & ((1 << 7) - 1);
+    unsigned int new_cmd = (value >> 8) & 1;
+
+    /* If the watchdog is enabled, they written key must match the
+       complement of the previous.  */
+    wd_key = ~wd_key & ((1 << 7) - 1);
+
+    if (wd_en && wd_key != new_key)
+        return;
+
+    D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
+         wd_en, new_key, wd_key, new_cmd, wd_cnt));
+
+    if (t->wd_hits)
+        qemu_irq_lower(t->nmi);
+
+    t->wd_hits = 0;
+
+    ptimer_set_freq(t->ptimer_wd, 760);
+    if (wd_cnt == 0)
+        wd_cnt = 256;
+    ptimer_set_count(t->ptimer_wd, wd_cnt);
+    if (new_cmd)
+        ptimer_run(t->ptimer_wd, 1);
+    else
+        ptimer_stop(t->ptimer_wd);
+
+    t->rw_wd_ctrl = value;
+}
+
+static void
+timer_write(void *opaque, hwaddr addr,
+            uint64_t val64, unsigned int size)
+{
+    struct etrax_timer *t = opaque;
+    uint32_t value = val64;
+
+    switch (addr)
+    {
+        case RW_TMR0_DIV:
+            t->rw_tmr0_div = value;
+            break;
+        case RW_TMR0_CTRL:
+            D(printf ("RW_TMR0_CTRL=%x\n", value));
+            t->rw_tmr0_ctrl = value;
+            update_ctrl(t, 0);
+            break;
+        case RW_TMR1_DIV:
+            t->rw_tmr1_div = value;
+            break;
+        case RW_TMR1_CTRL:
+            D(printf ("RW_TMR1_CTRL=%x\n", value));
+            t->rw_tmr1_ctrl = value;
+            update_ctrl(t, 1);
+            break;
+        case RW_INTR_MASK:
+            D(printf ("RW_INTR_MASK=%x\n", value));
+            t->rw_intr_mask = value;
+            timer_update_irq(t);
+            break;
+        case RW_WD_CTRL:
+            timer_watchdog_update(t, value);
+            break;
+        case RW_ACK_INTR:
+            t->rw_ack_intr = value;
+            timer_update_irq(t);
+            t->rw_ack_intr = 0;
+            break;
+        default:
+            printf ("%s " TARGET_FMT_plx " %x\n",
+                __func__, addr, value);
+            break;
+    }
+}
+
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void etraxfs_timer_reset(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+
+    ptimer_stop(t->ptimer_t0);
+    ptimer_stop(t->ptimer_t1);
+    ptimer_stop(t->ptimer_wd);
+    t->rw_wd_ctrl = 0;
+    t->r_intr = 0;
+    t->rw_intr_mask = 0;
+    qemu_irq_lower(t->irq);
+}
+
+static int etraxfs_timer_init(SysBusDevice *dev)
+{
+    struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
+
+    t->bh_t0 = qemu_bh_new(timer0_hit, t);
+    t->bh_t1 = qemu_bh_new(timer1_hit, t);
+    t->bh_wd = qemu_bh_new(watchdog_hit, t);
+    t->ptimer_t0 = ptimer_init(t->bh_t0);
+    t->ptimer_t1 = ptimer_init(t->bh_t1);
+    t->ptimer_wd = ptimer_init(t->bh_wd);
+
+    sysbus_init_irq(dev, &t->irq);
+    sysbus_init_irq(dev, &t->nmi);
+
+    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
+    sysbus_init_mmio(dev, &t->mmio);
+    qemu_register_reset(etraxfs_timer_reset, t);
+    return 0;
+}
+
+static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = etraxfs_timer_init;
+}
+
+static const TypeInfo etraxfs_timer_info = {
+    .name          = "etraxfs,timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof (struct etrax_timer),
+    .class_init    = etraxfs_timer_class_init,
+};
+
+static void etraxfs_timer_register_types(void)
+{
+    type_register_static(&etraxfs_timer_info);
+}
+
+type_init(etraxfs_timer_register_types)
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
new file mode 100644 (file)
index 0000000..87ce75b
--- /dev/null
@@ -0,0 +1,1482 @@
+/*
+ * Samsung exynos4210 Multi Core timer
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Global Timer:
+ *
+ * Consists of two timers. First represents Free Running Counter and second
+ * is used to measure interval from FRC to nearest comparator.
+ *
+ *        0                                                           UINT64_MAX
+ *        |                              timer0                             |
+ *        | <-------------------------------------------------------------- |
+ *        | --------------------------------------------frc---------------> |
+ *        |______________________________________________|__________________|
+ *                CMP0          CMP1             CMP2    |           CMP3
+ *                                                     __|            |_
+ *                                                     |     timer1     |
+ *                                                     | -------------> |
+ *                                                    frc              CMPx
+ *
+ * Problem: when implementing global timer as is, overflow arises.
+ * next_time = cur_time + period * count;
+ * period and count are 64 bits width.
+ * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT
+ * register during each event.
+ *
+ * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because
+ * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--.
+ * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0
+ * generates IRQs suffers from too frequently events. Better to have one
+ * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT,
+ * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values,
+ * there is no way to avoid frequently events).
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/ptimer.h"
+
+#include "hw/arm/exynos4210.h"
+
+//#define DEBUG_MCT
+
+#ifdef DEBUG_MCT
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \
+                     ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define    MCT_CFG          0x000
+#define    G_CNT_L          0x100
+#define    G_CNT_U          0x104
+#define    G_CNT_WSTAT      0x110
+#define    G_COMP0_L        0x200
+#define    G_COMP0_U        0x204
+#define    G_COMP0_ADD_INCR 0x208
+#define    G_COMP1_L        0x210
+#define    G_COMP1_U        0x214
+#define    G_COMP1_ADD_INCR 0x218
+#define    G_COMP2_L        0x220
+#define    G_COMP2_U        0x224
+#define    G_COMP2_ADD_INCR 0x228
+#define    G_COMP3_L        0x230
+#define    G_COMP3_U        0x234
+#define    G_COMP3_ADD_INCR 0x238
+#define    G_TCON           0x240
+#define    G_INT_CSTAT      0x244
+#define    G_INT_ENB        0x248
+#define    G_WSTAT          0x24C
+#define    L0_TCNTB         0x300
+#define    L0_TCNTO         0x304
+#define    L0_ICNTB         0x308
+#define    L0_ICNTO         0x30C
+#define    L0_FRCNTB        0x310
+#define    L0_FRCNTO        0x314
+#define    L0_TCON          0x320
+#define    L0_INT_CSTAT     0x330
+#define    L0_INT_ENB       0x334
+#define    L0_WSTAT         0x340
+#define    L1_TCNTB         0x400
+#define    L1_TCNTO         0x404
+#define    L1_ICNTB         0x408
+#define    L1_ICNTO         0x40C
+#define    L1_FRCNTB        0x410
+#define    L1_FRCNTO        0x414
+#define    L1_TCON          0x420
+#define    L1_INT_CSTAT     0x430
+#define    L1_INT_ENB       0x434
+#define    L1_WSTAT         0x440
+
+#define MCT_CFG_GET_PRESCALER(x)    ((x) & 0xFF)
+#define MCT_CFG_GET_DIVIDER(x)      (1 << ((x) >> 8 & 7))
+
+#define GET_G_COMP_IDX(offset)          (((offset) - G_COMP0_L) / 0x10)
+#define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10)
+
+#define G_COMP_L(x) (G_COMP0_L + (x) * 0x10)
+#define G_COMP_U(x) (G_COMP0_U + (x) * 0x10)
+
+#define G_COMP_ADD_INCR(x)  (G_COMP0_ADD_INCR + (x) * 0x10)
+
+/* MCT bits */
+#define G_TCON_COMP_ENABLE(x)   (1 << 2 * (x))
+#define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1))
+#define G_TCON_TIMER_ENABLE     (1 << 8)
+
+#define G_INT_ENABLE(x)         (1 << (x))
+#define G_INT_CSTAT_COMP(x)     (1 << (x))
+
+#define G_CNT_WSTAT_L           1
+#define G_CNT_WSTAT_U           2
+
+#define G_WSTAT_COMP_L(x)       (1 << 4 * (x))
+#define G_WSTAT_COMP_U(x)       (1 << ((4 * (x)) + 1))
+#define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2))
+#define G_WSTAT_TCON_WRITE      (1 << 16)
+
+#define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100)
+#define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \
+        (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2)
+
+#define L_ICNTB_MANUAL_UPDATE   (1 << 31)
+
+#define L_TCON_TICK_START       (1)
+#define L_TCON_INT_START        (1 << 1)
+#define L_TCON_INTERVAL_MODE    (1 << 2)
+#define L_TCON_FRC_START        (1 << 3)
+
+#define L_INT_CSTAT_INTCNT      (1 << 0)
+#define L_INT_CSTAT_FRCCNT      (1 << 1)
+
+#define L_INT_INTENB_ICNTEIE    (1 << 0)
+#define L_INT_INTENB_FRCEIE     (1 << 1)
+
+#define L_WSTAT_TCNTB_WRITE     (1 << 0)
+#define L_WSTAT_ICNTB_WRITE     (1 << 1)
+#define L_WSTAT_FRCCNTB_WRITE   (1 << 2)
+#define L_WSTAT_TCON_WRITE      (1 << 3)
+
+enum LocalTimerRegCntIndexes {
+    L_REG_CNT_TCNTB,
+    L_REG_CNT_TCNTO,
+    L_REG_CNT_ICNTB,
+    L_REG_CNT_ICNTO,
+    L_REG_CNT_FRCCNTB,
+    L_REG_CNT_FRCCNTO,
+
+    L_REG_CNT_AMOUNT
+};
+
+#define MCT_NIRQ                6
+#define MCT_SFR_SIZE            0x444
+
+#define MCT_GT_CMP_NUM          4
+
+#define MCT_GT_MAX_VAL          UINT64_MAX
+
+#define MCT_GT_COUNTER_STEP     0x100000000ULL
+#define MCT_LT_COUNTER_STEP     0x100000000ULL
+#define MCT_LT_CNT_LOW_LIMIT    0x100
+
+/* global timer */
+typedef struct {
+    qemu_irq  irq[MCT_GT_CMP_NUM];
+
+    struct gregs {
+        uint64_t cnt;
+        uint32_t cnt_wstat;
+        uint32_t tcon;
+        uint32_t int_cstat;
+        uint32_t int_enb;
+        uint32_t wstat;
+        uint64_t comp[MCT_GT_CMP_NUM];
+        uint32_t comp_add_incr[MCT_GT_CMP_NUM];
+    } reg;
+
+    uint64_t count;            /* Value FRC was armed with */
+    int32_t curr_comp;             /* Current comparator FRC is running to */
+
+    ptimer_state *ptimer_frc;                   /* FRC timer */
+
+} Exynos4210MCTGT;
+
+/* local timer */
+typedef struct {
+    int         id;             /* timer id */
+    qemu_irq    irq;            /* local timer irq */
+
+    struct tick_timer {
+        uint32_t cnt_run;           /* cnt timer is running */
+        uint32_t int_run;           /* int timer is running */
+
+        uint32_t last_icnto;
+        uint32_t last_tcnto;
+        uint32_t tcntb;             /* initial value for TCNTB */
+        uint32_t icntb;             /* initial value for ICNTB */
+
+        /* for step mode */
+        uint64_t    distance;       /* distance to count to the next event */
+        uint64_t    progress;       /* progress when counting by steps */
+        uint64_t    count;          /* count to arm timer with */
+
+        ptimer_state *ptimer_tick;  /* timer for tick counter */
+    } tick_timer;
+
+    /* use ptimer.c to represent count down timer */
+
+    ptimer_state *ptimer_frc;   /* timer for free running counter */
+
+    /* registers */
+    struct lregs {
+        uint32_t    cnt[L_REG_CNT_AMOUNT];
+        uint32_t    tcon;
+        uint32_t    int_cstat;
+        uint32_t    int_enb;
+        uint32_t    wstat;
+    } reg;
+
+} Exynos4210MCTLT;
+
+typedef struct Exynos4210MCTState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    /* Registers */
+    uint32_t    reg_mct_cfg;
+
+    Exynos4210MCTLT l_timer[2];
+    Exynos4210MCTGT g_timer;
+
+    uint32_t    freq;                   /* all timers tick frequency, TCLK */
+} Exynos4210MCTState;
+
+/*** VMState ***/
+static const VMStateDescription vmstate_tick_timer = {
+    .name = "exynos4210.mct.tick_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cnt_run, struct tick_timer),
+        VMSTATE_UINT32(int_run, struct tick_timer),
+        VMSTATE_UINT32(last_icnto, struct tick_timer),
+        VMSTATE_UINT32(last_tcnto, struct tick_timer),
+        VMSTATE_UINT32(tcntb, struct tick_timer),
+        VMSTATE_UINT32(icntb, struct tick_timer),
+        VMSTATE_UINT64(distance, struct tick_timer),
+        VMSTATE_UINT64(progress, struct tick_timer),
+        VMSTATE_UINT64(count, struct tick_timer),
+        VMSTATE_PTIMER(ptimer_tick, struct tick_timer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_lregs = {
+    .name = "exynos4210.mct.lregs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT),
+        VMSTATE_UINT32(tcon, struct lregs),
+        VMSTATE_UINT32(int_cstat, struct lregs),
+        VMSTATE_UINT32(int_enb, struct lregs),
+        VMSTATE_UINT32(wstat, struct lregs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_mct_lt = {
+    .name = "exynos4210.mct.lt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(id, Exynos4210MCTLT),
+        VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0,
+                vmstate_tick_timer,
+                struct tick_timer),
+        VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT),
+        VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0,
+                vmstate_lregs,
+                struct lregs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_gregs = {
+    .name = "exynos4210.mct.lregs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(cnt, struct gregs),
+        VMSTATE_UINT32(cnt_wstat, struct gregs),
+        VMSTATE_UINT32(tcon, struct gregs),
+        VMSTATE_UINT32(int_cstat, struct gregs),
+        VMSTATE_UINT32(int_enb, struct gregs),
+        VMSTATE_UINT32(wstat, struct gregs),
+        VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM),
+        VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs,
+                MCT_GT_CMP_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_mct_gt = {
+    .name = "exynos4210.mct.lt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs,
+                struct gregs),
+        VMSTATE_UINT64(count, Exynos4210MCTGT),
+        VMSTATE_INT32(curr_comp, Exynos4210MCTGT),
+        VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_mct_state = {
+    .name = "exynos4210.mct",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState),
+        VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0,
+            vmstate_exynos4210_mct_lt, Exynos4210MCTLT),
+        VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0,
+            vmstate_exynos4210_mct_gt, Exynos4210MCTGT),
+        VMSTATE_UINT32(freq, Exynos4210MCTState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void exynos4210_mct_update_freq(Exynos4210MCTState *s);
+
+/*
+ * Set counter of FRC global timer.
+ */
+static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
+{
+    s->count = count;
+    DPRINTF("global timer frc set count 0x%llx\n", count);
+    ptimer_set_count(s->ptimer_frc, count);
+}
+
+/*
+ * Get counter of FRC global timer.
+ */
+static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
+{
+    uint64_t count = 0;
+    count = ptimer_get_count(s->ptimer_frc);
+    count = s->count - count;
+    return s->reg.cnt + count;
+}
+
+/*
+ * Stop global FRC timer
+ */
+static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
+{
+    DPRINTF("global timer frc stop\n");
+
+    ptimer_stop(s->ptimer_frc);
+}
+
+/*
+ * Start global FRC timer
+ */
+static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
+{
+    DPRINTF("global timer frc start\n");
+
+    ptimer_run(s->ptimer_frc, 1);
+}
+
+/*
+ * Find next nearest Comparator. If current Comparator value equals to other
+ * Comparator value, skip them both
+ */
+static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
+{
+    int res;
+    int i;
+    int enabled;
+    uint64_t min;
+    int min_comp_i;
+    uint64_t gfrc;
+    uint64_t distance;
+    uint64_t distance_min;
+    int comp_i;
+
+    /* get gfrc count */
+    gfrc = exynos4210_gfrc_get_count(&s->g_timer);
+
+    min = UINT64_MAX;
+    distance_min = UINT64_MAX;
+    comp_i = MCT_GT_CMP_NUM;
+    min_comp_i = MCT_GT_CMP_NUM;
+    enabled = 0;
+
+    /* lookup for nearest comparator */
+    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+
+        if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
+
+            enabled = 1;
+
+            if (s->g_timer.reg.comp[i] > gfrc) {
+                /* Comparator is upper then FRC */
+                distance = s->g_timer.reg.comp[i] - gfrc;
+
+                if (distance <= distance_min) {
+                    distance_min = distance;
+                    comp_i = i;
+                }
+            } else {
+                /* Comparator is below FRC, find the smallest */
+
+                if (s->g_timer.reg.comp[i] <= min) {
+                    min = s->g_timer.reg.comp[i];
+                    min_comp_i = i;
+                }
+            }
+        }
+    }
+
+    if (!enabled) {
+        /* All Comparators disabled */
+        res = -1;
+    } else if (comp_i < MCT_GT_CMP_NUM) {
+        /* Found upper Comparator */
+        res = comp_i;
+    } else {
+        /* All Comparators are below or equal to FRC  */
+        res = min_comp_i;
+    }
+
+    DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
+            res,
+            s->g_timer.reg.comp[res],
+            distance_min,
+            gfrc);
+
+    return res;
+}
+
+/*
+ * Get distance to nearest Comparator
+ */
+static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
+{
+    if (id == -1) {
+        /* no enabled Comparators, choose max distance */
+        return MCT_GT_COUNTER_STEP;
+    }
+    if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
+        return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
+    } else {
+        return MCT_GT_COUNTER_STEP;
+    }
+}
+
+/*
+ * Restart global FRC timer
+ */
+static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
+{
+    uint64_t distance;
+
+    exynos4210_gfrc_stop(&s->g_timer);
+
+    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
+
+    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
+
+    if (distance > MCT_GT_COUNTER_STEP || !distance) {
+        distance = MCT_GT_COUNTER_STEP;
+    }
+
+    exynos4210_gfrc_set_count(&s->g_timer, distance);
+    exynos4210_gfrc_start(&s->g_timer);
+}
+
+/*
+ * Raise global timer CMP IRQ
+ */
+static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
+{
+    Exynos4210MCTGT *s = opaque;
+
+    /* If CSTAT is pending and IRQ is enabled */
+    if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
+            (s->reg.int_enb & G_INT_ENABLE(id))) {
+        DPRINTF("gcmp timer[%d] IRQ\n", id);
+        qemu_irq_raise(s->irq[id]);
+    }
+}
+
+/*
+ * Lower global timer CMP IRQ
+ */
+static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
+{
+    Exynos4210MCTGT *s = opaque;
+    qemu_irq_lower(s->irq[id]);
+}
+
+/*
+ * Global timer FRC event handler.
+ * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
+ * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
+ */
+static void exynos4210_gfrc_event(void *opaque)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
+    int i;
+    uint64_t distance;
+
+    DPRINTF("\n");
+
+    s->g_timer.reg.cnt += s->g_timer.count;
+
+    /* Process all comparators */
+    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+
+        if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
+            /* reached nearest comparator */
+
+            s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
+
+            /* Auto increment */
+            if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
+                s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
+            }
+
+            /* IRQ */
+            exynos4210_gcomp_raise_irq(&s->g_timer, i);
+        }
+    }
+
+    /* Reload FRC to reach nearest comparator */
+    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
+    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
+    if (distance > MCT_GT_COUNTER_STEP || !distance) {
+        distance = MCT_GT_COUNTER_STEP;
+    }
+    exynos4210_gfrc_set_count(&s->g_timer, distance);
+
+    exynos4210_gfrc_start(&s->g_timer);
+}
+
+/*
+ * Get counter of FRC local timer.
+ */
+static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
+{
+    return ptimer_get_count(s->ptimer_frc);
+}
+
+/*
+ * Set counter of FRC local timer.
+ */
+static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
+{
+    if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) {
+        ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP);
+    } else {
+        ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]);
+    }
+}
+
+/*
+ * Start local FRC timer
+ */
+static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
+{
+    ptimer_run(s->ptimer_frc, 1);
+}
+
+/*
+ * Stop local FRC timer
+ */
+static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
+{
+    ptimer_stop(s->ptimer_frc);
+}
+
+/*
+ * Local timer free running counter tick handler
+ */
+static void exynos4210_lfrc_event(void *opaque)
+{
+    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
+
+    /* local frc expired */
+
+    DPRINTF("\n");
+
+    s->reg.int_cstat |= L_INT_CSTAT_FRCCNT;
+
+    /* update frc counter */
+    exynos4210_lfrc_update_count(s);
+
+    /* raise irq */
+    if (s->reg.int_enb & L_INT_INTENB_FRCEIE) {
+        qemu_irq_raise(s->irq);
+    }
+
+    /*  we reached here, this means that timer is enabled */
+    exynos4210_lfrc_start(s);
+}
+
+static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s);
+static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s);
+static void exynos4210_ltick_recalc_count(struct tick_timer *s);
+
+/*
+ * Action on enabling local tick int timer
+ */
+static void exynos4210_ltick_int_start(struct tick_timer *s)
+{
+    if (!s->int_run) {
+        s->int_run = 1;
+    }
+}
+
+/*
+ * Action on disabling local tick int timer
+ */
+static void exynos4210_ltick_int_stop(struct tick_timer *s)
+{
+    if (s->int_run) {
+        s->last_icnto = exynos4210_ltick_int_get_cnto(s);
+        s->int_run = 0;
+    }
+}
+
+/*
+ * Get count for INT timer
+ */
+static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
+{
+    uint32_t icnto;
+    uint64_t remain;
+    uint64_t count;
+    uint64_t counted;
+    uint64_t cur_progress;
+
+    count = ptimer_get_count(s->ptimer_tick);
+    if (count) {
+        /* timer is still counting, called not from event */
+        counted = s->count - ptimer_get_count(s->ptimer_tick);
+        cur_progress = s->progress + counted;
+    } else {
+        /* timer expired earlier */
+        cur_progress = s->progress;
+    }
+
+    remain = s->distance - cur_progress;
+
+    if (!s->int_run) {
+        /* INT is stopped. */
+        icnto = s->last_icnto;
+    } else {
+        /* Both are counting */
+        icnto = remain / s->tcntb;
+    }
+
+    return icnto;
+}
+
+/*
+ * Start local tick cnt timer.
+ */
+static void exynos4210_ltick_cnt_start(struct tick_timer *s)
+{
+    if (!s->cnt_run) {
+
+        exynos4210_ltick_recalc_count(s);
+        ptimer_set_count(s->ptimer_tick, s->count);
+        ptimer_run(s->ptimer_tick, 1);
+
+        s->cnt_run = 1;
+    }
+}
+
+/*
+ * Stop local tick cnt timer.
+ */
+static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
+{
+    if (s->cnt_run) {
+
+        s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s);
+
+        if (s->int_run) {
+            exynos4210_ltick_int_stop(s);
+        }
+
+        ptimer_stop(s->ptimer_tick);
+
+        s->cnt_run = 0;
+    }
+}
+
+/*
+ * Get counter for CNT timer
+ */
+static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
+{
+    uint32_t tcnto;
+    uint32_t icnto;
+    uint64_t remain;
+    uint64_t counted;
+    uint64_t count;
+    uint64_t cur_progress;
+
+    count = ptimer_get_count(s->ptimer_tick);
+    if (count) {
+        /* timer is still counting, called not from event */
+        counted = s->count - ptimer_get_count(s->ptimer_tick);
+        cur_progress = s->progress + counted;
+    } else {
+        /* timer expired earlier */
+        cur_progress = s->progress;
+    }
+
+    remain = s->distance - cur_progress;
+
+    if (!s->cnt_run) {
+        /* Both are stopped. */
+        tcnto = s->last_tcnto;
+    } else if (!s->int_run) {
+        /* INT counter is stopped, progress is by CNT timer */
+        tcnto = remain % s->tcntb;
+    } else {
+        /* Both are counting */
+        icnto = remain / s->tcntb;
+        if (icnto) {
+            tcnto = remain % (icnto * s->tcntb);
+        } else {
+            tcnto = remain % s->tcntb;
+        }
+    }
+
+    return tcnto;
+}
+
+/*
+ * Set new values of counters for CNT and INT timers
+ */
+static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
+        uint32_t new_int)
+{
+    uint32_t cnt_stopped = 0;
+    uint32_t int_stopped = 0;
+
+    if (s->cnt_run) {
+        exynos4210_ltick_cnt_stop(s);
+        cnt_stopped = 1;
+    }
+
+    if (s->int_run) {
+        exynos4210_ltick_int_stop(s);
+        int_stopped = 1;
+    }
+
+    s->tcntb = new_cnt + 1;
+    s->icntb = new_int + 1;
+
+    if (cnt_stopped) {
+        exynos4210_ltick_cnt_start(s);
+    }
+    if (int_stopped) {
+        exynos4210_ltick_int_start(s);
+    }
+
+}
+
+/*
+ * Calculate new counter value for tick timer
+ */
+static void exynos4210_ltick_recalc_count(struct tick_timer *s)
+{
+    uint64_t to_count;
+
+    if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) {
+        /*
+         * one or both timers run and not counted to the end;
+         * distance is not passed, recalculate with last_tcnto * last_icnto
+         */
+
+        if (s->last_tcnto) {
+            to_count = s->last_tcnto * s->last_icnto;
+        } else {
+            to_count = s->last_icnto;
+        }
+    } else {
+        /* distance is passed, recalculate with tcnto * icnto */
+        if (s->icntb) {
+            s->distance = s->tcntb * s->icntb;
+        } else {
+            s->distance = s->tcntb;
+        }
+
+        to_count = s->distance;
+        s->progress = 0;
+    }
+
+    if (to_count > MCT_LT_COUNTER_STEP) {
+        /* count by step */
+        s->count = MCT_LT_COUNTER_STEP;
+    } else {
+        s->count = to_count;
+    }
+}
+
+/*
+ * Initialize tick_timer
+ */
+static void exynos4210_ltick_timer_init(struct tick_timer *s)
+{
+    exynos4210_ltick_int_stop(s);
+    exynos4210_ltick_cnt_stop(s);
+
+    s->count = 0;
+    s->distance = 0;
+    s->progress = 0;
+    s->icntb = 0;
+    s->tcntb = 0;
+}
+
+/*
+ * tick_timer event.
+ * Raises when abstract tick_timer expires.
+ */
+static void exynos4210_ltick_timer_event(struct tick_timer *s)
+{
+    s->progress += s->count;
+}
+
+/*
+ * Local timer tick counter handler.
+ * Don't use reloaded timers. If timer counter = zero
+ * then handler called but after handler finished no
+ * timer reload occurs.
+ */
+static void exynos4210_ltick_event(void *opaque)
+{
+    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
+    uint32_t tcnto;
+    uint32_t icnto;
+#ifdef DEBUG_MCT
+    static uint64_t time1[2] = {0};
+    static uint64_t time2[2] = {0};
+#endif
+
+    /* Call tick_timer event handler, it will update its tcntb and icntb. */
+    exynos4210_ltick_timer_event(&s->tick_timer);
+
+    /* get tick_timer cnt */
+    tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer);
+
+    /* get tick_timer int */
+    icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer);
+
+    /* raise IRQ if needed */
+    if (!icnto && s->reg.tcon & L_TCON_INT_START) {
+        /* INT counter enabled and expired */
+
+        s->reg.int_cstat |= L_INT_CSTAT_INTCNT;
+
+        /* raise interrupt if enabled */
+        if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) {
+#ifdef DEBUG_MCT
+            time2[s->id] = qemu_get_clock_ns(vm_clock);
+            DPRINTF("local timer[%d] IRQ: %llx\n", s->id,
+                    time2[s->id] - time1[s->id]);
+            time1[s->id] = time2[s->id];
+#endif
+            qemu_irq_raise(s->irq);
+        }
+
+        /* reload ICNTB */
+        if (s->reg.tcon & L_TCON_INTERVAL_MODE) {
+            exynos4210_ltick_set_cntb(&s->tick_timer,
+                    s->reg.cnt[L_REG_CNT_TCNTB],
+                    s->reg.cnt[L_REG_CNT_ICNTB]);
+        }
+    } else {
+        /* reload TCNTB */
+        if (!tcnto) {
+            exynos4210_ltick_set_cntb(&s->tick_timer,
+                    s->reg.cnt[L_REG_CNT_TCNTB],
+                    icnto);
+        }
+    }
+
+    /* start tick_timer cnt */
+    exynos4210_ltick_cnt_start(&s->tick_timer);
+
+    /* start tick_timer int */
+    exynos4210_ltick_int_start(&s->tick_timer);
+}
+
+/* update timer frequency */
+static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
+{
+    uint32_t freq = s->freq;
+    s->freq = 24000000 /
+            ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) *
+                    MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
+
+    if (freq != s->freq) {
+        DPRINTF("freq=%dHz\n", s->freq);
+
+        /* global timer */
+        ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
+
+        /* local timer */
+        ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
+        ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
+        ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
+        ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
+    }
+}
+
+/* set defaul_timer values for all fields */
+static void exynos4210_mct_reset(DeviceState *d)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)d;
+    uint32_t i;
+
+    s->reg_mct_cfg = 0;
+
+    /* global timer */
+    memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
+    exynos4210_gfrc_stop(&s->g_timer);
+
+    /* local timer */
+    memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
+    memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt));
+    for (i = 0; i < 2; i++) {
+        s->l_timer[i].reg.int_cstat = 0;
+        s->l_timer[i].reg.int_enb = 0;
+        s->l_timer[i].reg.tcon = 0;
+        s->l_timer[i].reg.wstat = 0;
+        s->l_timer[i].tick_timer.count = 0;
+        s->l_timer[i].tick_timer.distance = 0;
+        s->l_timer[i].tick_timer.progress = 0;
+        ptimer_stop(s->l_timer[i].ptimer_frc);
+
+        exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
+    }
+
+    exynos4210_mct_update_freq(s);
+
+}
+
+/* Multi Core Timer read */
+static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
+    int index;
+    int shift;
+    uint64_t count;
+    uint32_t value;
+    int lt_i;
+
+    switch (offset) {
+
+    case MCT_CFG:
+        value = s->reg_mct_cfg;
+        break;
+
+    case G_CNT_L: case G_CNT_U:
+        shift = 8 * (offset & 0x4);
+        count = exynos4210_gfrc_get_count(&s->g_timer);
+        value = UINT32_MAX & (count >> shift);
+        DPRINTF("read FRC=0x%llx\n", count);
+        break;
+
+    case G_CNT_WSTAT:
+        value = s->g_timer.reg.cnt_wstat;
+        break;
+
+    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
+    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
+    index = GET_G_COMP_IDX(offset);
+    shift = 8 * (offset & 0x4);
+    value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
+    break;
+
+    case G_TCON:
+        value = s->g_timer.reg.tcon;
+        break;
+
+    case G_INT_CSTAT:
+        value = s->g_timer.reg.int_cstat;
+        break;
+
+    case G_INT_ENB:
+        value = s->g_timer.reg.int_enb;
+        break;
+        break;
+    case G_WSTAT:
+        value = s->g_timer.reg.wstat;
+        break;
+
+    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
+    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
+        value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
+        break;
+
+        /* Local timers */
+    case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
+    case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+        value = s->l_timer[lt_i].reg.cnt[index];
+        break;
+
+    case L0_TCNTO: case L1_TCNTO:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
+        DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
+        break;
+
+    case L0_ICNTO: case L1_ICNTO:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
+        DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
+        break;
+
+    case L0_FRCNTO: case L1_FRCNTO:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
+
+        break;
+
+    case L0_TCON: case L1_TCON:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.tcon;
+        break;
+
+    case L0_INT_CSTAT: case L1_INT_CSTAT:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.int_cstat;
+        break;
+
+    case L0_INT_ENB: case L1_INT_ENB:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.int_enb;
+        break;
+
+    case L0_WSTAT: case L1_WSTAT:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.wstat;
+        break;
+
+    default:
+        hw_error("exynos4210.mct: bad read offset "
+                TARGET_FMT_plx "\n", offset);
+        break;
+    }
+    return value;
+}
+
+/* MCT write */
+static void exynos4210_mct_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
+    int index;  /* index in buffer which represents register set */
+    int shift;
+    int lt_i;
+    uint64_t new_frc;
+    uint32_t i;
+    uint32_t old_val;
+#ifdef DEBUG_MCT
+    static uint32_t icntb_max[2] = {0};
+    static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
+    static uint32_t tcntb_max[2] = {0};
+    static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
+#endif
+
+    new_frc = s->g_timer.reg.cnt;
+
+    switch (offset) {
+
+    case MCT_CFG:
+        s->reg_mct_cfg = value;
+        exynos4210_mct_update_freq(s);
+        break;
+
+    case G_CNT_L:
+    case G_CNT_U:
+        if (offset == G_CNT_L) {
+
+            DPRINTF("global timer write to reg.cntl %llx\n", value);
+
+            new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
+            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
+        }
+        if (offset == G_CNT_U) {
+
+            DPRINTF("global timer write to reg.cntu %llx\n", value);
+
+            new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
+                    ((uint64_t)value << 32);
+            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
+        }
+
+        s->g_timer.reg.cnt = new_frc;
+        exynos4210_gfrc_restart(s);
+        break;
+
+    case G_CNT_WSTAT:
+        s->g_timer.reg.cnt_wstat &= ~(value);
+        break;
+
+    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
+    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
+    index = GET_G_COMP_IDX(offset);
+    shift = 8 * (offset & 0x4);
+    s->g_timer.reg.comp[index] =
+            (s->g_timer.reg.comp[index] &
+            (((uint64_t)UINT32_MAX << 32) >> shift)) +
+            (value << shift);
+
+    DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
+
+    if (offset&0x4) {
+        s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
+    } else {
+        s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
+    }
+
+    exynos4210_gfrc_restart(s);
+    break;
+
+    case G_TCON:
+        old_val = s->g_timer.reg.tcon;
+        s->g_timer.reg.tcon = value;
+        s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
+
+        DPRINTF("global timer write to reg.g_tcon %llx\n", value);
+
+        /* Start FRC if transition from disabled to enabled */
+        if ((value & G_TCON_TIMER_ENABLE) > (old_val &
+                G_TCON_TIMER_ENABLE)) {
+            exynos4210_gfrc_start(&s->g_timer);
+        }
+        if ((value & G_TCON_TIMER_ENABLE) < (old_val &
+                G_TCON_TIMER_ENABLE)) {
+            exynos4210_gfrc_stop(&s->g_timer);
+        }
+
+        /* Start CMP if transition from disabled to enabled */
+        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+            if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
+                    G_TCON_COMP_ENABLE(i))) {
+                exynos4210_gfrc_restart(s);
+            }
+        }
+        break;
+
+    case G_INT_CSTAT:
+        s->g_timer.reg.int_cstat &= ~(value);
+        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+            if (value & G_INT_CSTAT_COMP(i)) {
+                exynos4210_gcomp_lower_irq(&s->g_timer, i);
+            }
+        }
+        break;
+
+    case G_INT_ENB:
+
+        /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
+        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+            if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
+                    G_INT_ENABLE(i))) {
+                if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
+                    exynos4210_gcomp_raise_irq(&s->g_timer, i);
+                }
+            }
+
+            if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
+                    G_INT_ENABLE(i))) {
+                exynos4210_gcomp_lower_irq(&s->g_timer, i);
+            }
+        }
+
+        DPRINTF("global timer INT enable %llx\n", value);
+        s->g_timer.reg.int_enb = value;
+        break;
+
+    case G_WSTAT:
+        s->g_timer.reg.wstat &= ~(value);
+        break;
+
+    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
+    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
+        index = GET_G_COMP_ADD_INCR_IDX(offset);
+        s->g_timer.reg.comp_add_incr[index] = value;
+        s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
+        break;
+
+        /* Local timers */
+    case L0_TCON: case L1_TCON:
+        lt_i = GET_L_TIMER_IDX(offset);
+        old_val = s->l_timer[lt_i].reg.tcon;
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
+        s->l_timer[lt_i].reg.tcon = value;
+
+        /* Stop local CNT */
+        if ((value & L_TCON_TICK_START) <
+                (old_val & L_TCON_TICK_START)) {
+            DPRINTF("local timer[%d] stop cnt\n", lt_i);
+            exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Stop local INT */
+        if ((value & L_TCON_INT_START) <
+                (old_val & L_TCON_INT_START)) {
+            DPRINTF("local timer[%d] stop int\n", lt_i);
+            exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Start local CNT */
+        if ((value & L_TCON_TICK_START) >
+        (old_val & L_TCON_TICK_START)) {
+            DPRINTF("local timer[%d] start cnt\n", lt_i);
+            exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Start local INT */
+        if ((value & L_TCON_INT_START) >
+        (old_val & L_TCON_INT_START)) {
+            DPRINTF("local timer[%d] start int\n", lt_i);
+            exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Start or Stop local FRC if TCON changed */
+        if ((value & L_TCON_FRC_START) >
+        (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
+            DPRINTF("local timer[%d] start frc\n", lt_i);
+            exynos4210_lfrc_start(&s->l_timer[lt_i]);
+        }
+        if ((value & L_TCON_FRC_START) <
+                (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
+            DPRINTF("local timer[%d] stop frc\n", lt_i);
+            exynos4210_lfrc_stop(&s->l_timer[lt_i]);
+        }
+        break;
+
+    case L0_TCNTB: case L1_TCNTB:
+
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+
+        /*
+         * TCNTB is updated to internal register only after CNT expired.
+         * Due to this we should reload timer to nearest moment when CNT is
+         * expired and then in event handler update tcntb to new TCNTB value.
+         */
+        exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
+                s->l_timer[lt_i].tick_timer.icntb);
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
+        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
+
+#ifdef DEBUG_MCT
+        if (tcntb_min[lt_i] > value) {
+            tcntb_min[lt_i] = value;
+        }
+        if (tcntb_max[lt_i] < value) {
+            tcntb_max[lt_i] = value;
+        }
+        DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
+                lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
+#endif
+        break;
+
+    case L0_ICNTB: case L1_ICNTB:
+
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
+        s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
+                ~L_ICNTB_MANUAL_UPDATE;
+
+        /*
+         * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
+         * could raise too fast disallowing QEMU to execute target code.
+         */
+        if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
+            s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
+            if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
+                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
+                        MCT_LT_CNT_LOW_LIMIT;
+            } else {
+                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
+                        MCT_LT_CNT_LOW_LIMIT /
+                        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
+            }
+        }
+
+        if (value & L_ICNTB_MANUAL_UPDATE) {
+            exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
+                    s->l_timer[lt_i].tick_timer.tcntb,
+                    s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
+        }
+
+#ifdef DEBUG_MCT
+        if (icntb_min[lt_i] > value) {
+            icntb_min[lt_i] = value;
+        }
+        if (icntb_max[lt_i] < value) {
+            icntb_max[lt_i] = value;
+        }
+DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
+        lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
+#endif
+break;
+
+    case L0_FRCNTB: case L1_FRCNTB:
+
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+
+        DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
+        s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
+
+        break;
+
+    case L0_TCNTO: case L1_TCNTO:
+    case L0_ICNTO: case L1_ICNTO:
+    case L0_FRCNTO: case L1_FRCNTO:
+        fprintf(stderr, "\n[exynos4210.mct: write to RO register "
+                TARGET_FMT_plx "]\n\n", offset);
+        break;
+
+    case L0_INT_CSTAT: case L1_INT_CSTAT:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
+
+        s->l_timer[lt_i].reg.int_cstat &= ~value;
+        if (!s->l_timer[lt_i].reg.int_cstat) {
+            qemu_irq_lower(s->l_timer[lt_i].irq);
+        }
+        break;
+
+    case L0_INT_ENB: case L1_INT_ENB:
+        lt_i = GET_L_TIMER_IDX(offset);
+        old_val = s->l_timer[lt_i].reg.int_enb;
+
+        /* Raise Local timer IRQ if cstat is pending */
+        if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
+            if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
+                qemu_irq_raise(s->l_timer[lt_i].irq);
+            }
+        }
+
+        s->l_timer[lt_i].reg.int_enb = value;
+
+        break;
+
+    case L0_WSTAT: case L1_WSTAT:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        s->l_timer[lt_i].reg.wstat &= ~value;
+        break;
+
+    default:
+        hw_error("exynos4210.mct: bad write offset "
+                TARGET_FMT_plx "\n", offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps exynos4210_mct_ops = {
+    .read = exynos4210_mct_read,
+    .write = exynos4210_mct_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* MCT init */
+static int exynos4210_mct_init(SysBusDevice *dev)
+{
+    int i;
+    Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev);
+    QEMUBH *bh[2];
+
+    /* Global timer */
+    bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
+    s->g_timer.ptimer_frc = ptimer_init(bh[0]);
+    memset(&s->g_timer.reg, 0, sizeof(struct gregs));
+
+    /* Local timers */
+    for (i = 0; i < 2; i++) {
+        bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
+        bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
+        s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]);
+        s->l_timer[i].ptimer_frc = ptimer_init(bh[1]);
+        s->l_timer[i].id = i;
+    }
+
+    /* IRQs */
+    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+        sysbus_init_irq(dev, &s->g_timer.irq[i]);
+    }
+    for (i = 0; i < 2; i++) {
+        sysbus_init_irq(dev, &s->l_timer[i].irq);
+    }
+
+    memory_region_init_io(&s->iomem, &exynos4210_mct_ops, s, "exynos4210-mct",
+            MCT_SFR_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_mct_init;
+    dc->reset = exynos4210_mct_reset;
+    dc->vmsd = &vmstate_exynos4210_mct_state;
+}
+
+static const TypeInfo exynos4210_mct_info = {
+    .name          = "exynos4210.mct",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210MCTState),
+    .class_init    = exynos4210_mct_class_init,
+};
+
+static void exynos4210_mct_register_types(void)
+{
+    type_register_static(&exynos4210_mct_info);
+}
+
+type_init(exynos4210_mct_register_types)
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
new file mode 100644 (file)
index 0000000..185ccb9
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Samsung exynos4210 Pulse Width Modulation Timer
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/ptimer.h"
+
+#include "hw/arm/exynos4210.h"
+
+//#define DEBUG_PWM
+
+#ifdef DEBUG_PWM
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "PWM: [%24s:%5d] " fmt, __func__, __LINE__, \
+                ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define     EXYNOS4210_PWM_TIMERS_NUM      5
+#define     EXYNOS4210_PWM_REG_MEM_SIZE    0x50
+
+#define     TCFG0        0x0000
+#define     TCFG1        0x0004
+#define     TCON         0x0008
+#define     TCNTB0       0x000C
+#define     TCMPB0       0x0010
+#define     TCNTO0       0x0014
+#define     TCNTB1       0x0018
+#define     TCMPB1       0x001C
+#define     TCNTO1       0x0020
+#define     TCNTB2       0x0024
+#define     TCMPB2       0x0028
+#define     TCNTO2       0x002C
+#define     TCNTB3       0x0030
+#define     TCMPB3       0x0034
+#define     TCNTO3       0x0038
+#define     TCNTB4       0x003C
+#define     TCNTO4       0x0040
+#define     TINT_CSTAT   0x0044
+
+#define     TCNTB(x)    (0xC * (x))
+#define     TCMPB(x)    (0xC * (x) + 1)
+#define     TCNTO(x)    (0xC * (x) + 2)
+
+#define GET_PRESCALER(reg, x) (((reg) & (0xFF << (8 * (x)))) >> 8 * (x))
+#define GET_DIVIDER(reg, x) (1 << (((reg) & (0xF << (4 * (x)))) >> (4 * (x))))
+
+/*
+ * Attention! Timer4 doesn't have OUTPUT_INVERTER,
+ * so Auto Reload bit is not accessible by macros!
+ */
+#define     TCON_TIMER_BASE(x)          (((x) ? 1 : 0) * 4 + 4 * (x))
+#define     TCON_TIMER_START(x)         (1 << (TCON_TIMER_BASE(x) + 0))
+#define     TCON_TIMER_MANUAL_UPD(x)    (1 << (TCON_TIMER_BASE(x) + 1))
+#define     TCON_TIMER_OUTPUT_INV(x)    (1 << (TCON_TIMER_BASE(x) + 2))
+#define     TCON_TIMER_AUTO_RELOAD(x)   (1 << (TCON_TIMER_BASE(x) + 3))
+#define     TCON_TIMER4_AUTO_RELOAD     (1 << 22)
+
+#define     TINT_CSTAT_STATUS(x)        (1 << (5 + (x)))
+#define     TINT_CSTAT_ENABLE(x)        (1 << (x))
+
+/* timer struct */
+typedef struct {
+    uint32_t    id;             /* timer id */
+    qemu_irq    irq;            /* local timer irq */
+    uint32_t    freq;           /* timer frequency */
+
+    /* use ptimer.c to represent count down timer */
+    ptimer_state *ptimer;       /* timer  */
+
+    /* registers */
+    uint32_t    reg_tcntb;      /* counter register buffer */
+    uint32_t    reg_tcmpb;      /* compare register buffer */
+
+    struct Exynos4210PWMState *parent;
+
+} Exynos4210PWM;
+
+
+typedef struct Exynos4210PWMState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t    reg_tcfg[2];
+    uint32_t    reg_tcon;
+    uint32_t    reg_tint_cstat;
+
+    Exynos4210PWM timer[EXYNOS4210_PWM_TIMERS_NUM];
+
+} Exynos4210PWMState;
+
+/*** VMState ***/
+static const VMStateDescription vmstate_exynos4210_pwm = {
+    .name = "exynos4210.pwm.pwm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(id, Exynos4210PWM),
+        VMSTATE_UINT32(freq, Exynos4210PWM),
+        VMSTATE_PTIMER(ptimer, Exynos4210PWM),
+        VMSTATE_UINT32(reg_tcntb, Exynos4210PWM),
+        VMSTATE_UINT32(reg_tcmpb, Exynos4210PWM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_pwm_state = {
+    .name = "exynos4210.pwm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2),
+        VMSTATE_UINT32(reg_tcon, Exynos4210PWMState),
+        VMSTATE_UINT32(reg_tint_cstat, Exynos4210PWMState),
+        VMSTATE_STRUCT_ARRAY(timer, Exynos4210PWMState,
+            EXYNOS4210_PWM_TIMERS_NUM, 0,
+        vmstate_exynos4210_pwm, Exynos4210PWM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * PWM update frequency
+ */
+static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id)
+{
+    uint32_t freq;
+    freq = s->timer[id].freq;
+    if (id > 1) {
+        s->timer[id].freq = 24000000 /
+        ((GET_PRESCALER(s->reg_tcfg[0], 1) + 1) *
+                (GET_DIVIDER(s->reg_tcfg[1], id)));
+    } else {
+        s->timer[id].freq = 24000000 /
+        ((GET_PRESCALER(s->reg_tcfg[0], 0) + 1) *
+                (GET_DIVIDER(s->reg_tcfg[1], id)));
+    }
+
+    if (freq != s->timer[id].freq) {
+        ptimer_set_freq(s->timer[id].ptimer, s->timer[id].freq);
+        DPRINTF("freq=%dHz\n", s->timer[id].freq);
+    }
+}
+
+/*
+ * Counter tick handler
+ */
+static void exynos4210_pwm_tick(void *opaque)
+{
+    Exynos4210PWM *s = (Exynos4210PWM *)opaque;
+    Exynos4210PWMState *p = (Exynos4210PWMState *)s->parent;
+    uint32_t id = s->id;
+    bool cmp;
+
+    DPRINTF("timer %d tick\n", id);
+
+    /* set irq status */
+    p->reg_tint_cstat |= TINT_CSTAT_STATUS(id);
+
+    /* raise IRQ */
+    if (p->reg_tint_cstat & TINT_CSTAT_ENABLE(id)) {
+        DPRINTF("timer %d IRQ\n", id);
+        qemu_irq_raise(p->timer[id].irq);
+    }
+
+    /* reload timer */
+    if (id != 4) {
+        cmp = p->reg_tcon & TCON_TIMER_AUTO_RELOAD(id);
+    } else {
+        cmp = p->reg_tcon & TCON_TIMER4_AUTO_RELOAD;
+    }
+
+    if (cmp) {
+        DPRINTF("auto reload timer %d count to %x\n", id,
+                p->timer[id].reg_tcntb);
+        ptimer_set_count(p->timer[id].ptimer, p->timer[id].reg_tcntb);
+        ptimer_run(p->timer[id].ptimer, 1);
+    } else {
+        /* stop timer, set status to STOP, see Basic Timer Operation */
+        p->reg_tcon &= ~TCON_TIMER_START(id);
+        ptimer_stop(p->timer[id].ptimer);
+    }
+}
+
+/*
+ * PWM Read
+ */
+static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
+    uint32_t value = 0;
+    int index;
+
+    switch (offset) {
+    case TCFG0: case TCFG1:
+        index = (offset - TCFG0) >> 2;
+        value = s->reg_tcfg[index];
+        break;
+
+    case TCON:
+        value = s->reg_tcon;
+        break;
+
+    case TCNTB0: case TCNTB1:
+    case TCNTB2: case TCNTB3: case TCNTB4:
+        index = (offset - TCNTB0) / 0xC;
+        value = s->timer[index].reg_tcntb;
+        break;
+
+    case TCMPB0: case TCMPB1:
+    case TCMPB2: case TCMPB3:
+        index = (offset - TCMPB0) / 0xC;
+        value = s->timer[index].reg_tcmpb;
+        break;
+
+    case TCNTO0: case TCNTO1:
+    case TCNTO2: case TCNTO3: case TCNTO4:
+        index = (offset == TCNTO4) ? 4 : (offset - TCNTO0) / 0xC;
+        value = ptimer_get_count(s->timer[index].ptimer);
+        break;
+
+    case TINT_CSTAT:
+        value = s->reg_tint_cstat;
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+    }
+    return value;
+}
+
+/*
+ * PWM Write
+ */
+static void exynos4210_pwm_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
+    int index;
+    uint32_t new_val;
+    int i;
+
+    switch (offset) {
+    case TCFG0: case TCFG1:
+        index = (offset - TCFG0) >> 2;
+        s->reg_tcfg[index] = value;
+
+        /* update timers frequencies */
+        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+            exynos4210_pwm_update_freq(s, s->timer[i].id);
+        }
+        break;
+
+    case TCON:
+        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+            if ((value & TCON_TIMER_MANUAL_UPD(i)) >
+            (s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) {
+                /*
+                 * TCNTB and TCMPB are loaded into TCNT and TCMP.
+                 * Update timers.
+                 */
+
+                /* this will start timer to run, this ok, because
+                 * during processing start bit timer will be stopped
+                 * if needed */
+                ptimer_set_count(s->timer[i].ptimer, s->timer[i].reg_tcntb);
+                DPRINTF("set timer %d count to %x\n", i,
+                        s->timer[i].reg_tcntb);
+            }
+
+            if ((value & TCON_TIMER_START(i)) >
+            (s->reg_tcon & TCON_TIMER_START(i))) {
+                /* changed to start */
+                ptimer_run(s->timer[i].ptimer, 1);
+                DPRINTF("run timer %d\n", i);
+            }
+
+            if ((value & TCON_TIMER_START(i)) <
+                    (s->reg_tcon & TCON_TIMER_START(i))) {
+                /* changed to stop */
+                ptimer_stop(s->timer[i].ptimer);
+                DPRINTF("stop timer %d\n", i);
+            }
+        }
+        s->reg_tcon = value;
+        break;
+
+    case TCNTB0: case TCNTB1:
+    case TCNTB2: case TCNTB3: case TCNTB4:
+        index = (offset - TCNTB0) / 0xC;
+        s->timer[index].reg_tcntb = value;
+        break;
+
+    case TCMPB0: case TCMPB1:
+    case TCMPB2: case TCMPB3:
+        index = (offset - TCMPB0) / 0xC;
+        s->timer[index].reg_tcmpb = value;
+        break;
+
+    case TINT_CSTAT:
+        new_val = (s->reg_tint_cstat & 0x3E0) + (0x1F & value);
+        new_val &= ~(0x3E0 & value);
+
+        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+            if ((new_val & TINT_CSTAT_STATUS(i)) <
+                    (s->reg_tint_cstat & TINT_CSTAT_STATUS(i))) {
+                qemu_irq_lower(s->timer[i].irq);
+            }
+        }
+
+        s->reg_tint_cstat = new_val;
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+
+    }
+}
+
+/*
+ * Set default values to timer fields and registers
+ */
+static void exynos4210_pwm_reset(DeviceState *d)
+{
+    Exynos4210PWMState *s = (Exynos4210PWMState *)d;
+    int i;
+    s->reg_tcfg[0] = 0x0101;
+    s->reg_tcfg[1] = 0x0;
+    s->reg_tcon = 0;
+    s->reg_tint_cstat = 0;
+    for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+        s->timer[i].reg_tcmpb = 0;
+        s->timer[i].reg_tcntb = 0;
+
+        exynos4210_pwm_update_freq(s, s->timer[i].id);
+        ptimer_stop(s->timer[i].ptimer);
+    }
+}
+
+static const MemoryRegionOps exynos4210_pwm_ops = {
+    .read = exynos4210_pwm_read,
+    .write = exynos4210_pwm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * PWM timer initialization
+ */
+static int exynos4210_pwm_init(SysBusDevice *dev)
+{
+    Exynos4210PWMState *s = FROM_SYSBUS(Exynos4210PWMState, dev);
+    int i;
+    QEMUBH *bh;
+
+    for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+        bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]);
+        sysbus_init_irq(dev, &s->timer[i].irq);
+        s->timer[i].ptimer = ptimer_init(bh);
+        s->timer[i].id = i;
+        s->timer[i].parent = s;
+    }
+
+    memory_region_init_io(&s->iomem, &exynos4210_pwm_ops, s, "exynos4210-pwm",
+            EXYNOS4210_PWM_REG_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_pwm_init;
+    dc->reset = exynos4210_pwm_reset;
+    dc->vmsd = &vmstate_exynos4210_pwm_state;
+}
+
+static const TypeInfo exynos4210_pwm_info = {
+    .name          = "exynos4210.pwm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210PWMState),
+    .class_init    = exynos4210_pwm_class_init,
+};
+
+static void exynos4210_pwm_register_types(void)
+{
+    type_register_static(&exynos4210_pwm_info);
+}
+
+type_init(exynos4210_pwm_register_types)
diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c
new file mode 100644 (file)
index 0000000..bceee44
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * Samsung exynos4210 Real Time Clock
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *  Ogurtsov Oleg <o.ogurtsov@samsung.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Description:
+ * Register RTCCON:
+ *  CLKSEL Bit[1] not used
+ *  CLKOUTEN Bit[9] not used
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/ptimer.h"
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#include "hw/arm/exynos4210.h"
+
+#define DEBUG_RTC 0
+
+#if DEBUG_RTC
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "RTC: [%24s:%5d] " fmt, __func__, __LINE__, \
+                ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define     EXYNOS4210_RTC_REG_MEM_SIZE     0x0100
+
+#define     INTP            0x0030
+#define     RTCCON          0x0040
+#define     TICCNT          0x0044
+#define     RTCALM          0x0050
+#define     ALMSEC          0x0054
+#define     ALMMIN          0x0058
+#define     ALMHOUR         0x005C
+#define     ALMDAY          0x0060
+#define     ALMMON          0x0064
+#define     ALMYEAR         0x0068
+#define     BCDSEC          0x0070
+#define     BCDMIN          0x0074
+#define     BCDHOUR         0x0078
+#define     BCDDAY          0x007C
+#define     BCDDAYWEEK      0x0080
+#define     BCDMON          0x0084
+#define     BCDYEAR         0x0088
+#define     CURTICNT        0x0090
+
+#define     TICK_TIMER_ENABLE   0x0100
+#define     TICNT_THRESHHOLD    2
+
+
+#define     RTC_ENABLE          0x0001
+
+#define     INTP_TICK_ENABLE    0x0001
+#define     INTP_ALM_ENABLE     0x0002
+
+#define     ALARM_INT_ENABLE    0x0040
+
+#define     RTC_BASE_FREQ       32768
+
+typedef struct Exynos4210RTCState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    /* registers */
+    uint32_t    reg_intp;
+    uint32_t    reg_rtccon;
+    uint32_t    reg_ticcnt;
+    uint32_t    reg_rtcalm;
+    uint32_t    reg_almsec;
+    uint32_t    reg_almmin;
+    uint32_t    reg_almhour;
+    uint32_t    reg_almday;
+    uint32_t    reg_almmon;
+    uint32_t    reg_almyear;
+    uint32_t    reg_curticcnt;
+
+    ptimer_state    *ptimer;        /* tick timer */
+    ptimer_state    *ptimer_1Hz;    /* clock timer */
+    uint32_t        freq;
+
+    qemu_irq        tick_irq;   /* Time Tick Generator irq */
+    qemu_irq        alm_irq;    /* alarm irq */
+
+    struct tm   current_tm;     /* current time */
+} Exynos4210RTCState;
+
+#define TICCKSEL(value) ((value & (0x0F << 4)) >> 4)
+
+/*** VMState ***/
+static const VMStateDescription vmstate_exynos4210_rtc_state = {
+    .name = "exynos4210.rtc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(reg_intp, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_ticcnt, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_rtcalm, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almsec, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almmin, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almhour, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almday, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almmon, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almyear, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_curticcnt, Exynos4210RTCState),
+        VMSTATE_PTIMER(ptimer, Exynos4210RTCState),
+        VMSTATE_PTIMER(ptimer_1Hz, Exynos4210RTCState),
+        VMSTATE_UINT32(freq, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_sec, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_min, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_hour, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_wday, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_mday, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_mon, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_year, Exynos4210RTCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define BCD3DIGITS(x) \
+    ((uint32_t)to_bcd((uint8_t)(x % 100)) + \
+    ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8))
+
+static void check_alarm_raise(Exynos4210RTCState *s)
+{
+    unsigned int alarm_raise = 0;
+    struct tm stm = s->current_tm;
+
+    if ((s->reg_rtcalm & 0x01) &&
+        (to_bcd((uint8_t)stm.tm_sec) == (uint8_t)s->reg_almsec)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x02) &&
+        (to_bcd((uint8_t)stm.tm_min) == (uint8_t)s->reg_almmin)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x04) &&
+        (to_bcd((uint8_t)stm.tm_hour) == (uint8_t)s->reg_almhour)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x08) &&
+        (to_bcd((uint8_t)stm.tm_mday) == (uint8_t)s->reg_almday)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x10) &&
+         (to_bcd((uint8_t)stm.tm_mon) == (uint8_t)s->reg_almmon)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x20) &&
+        (BCD3DIGITS(stm.tm_year) == s->reg_almyear)) {
+        alarm_raise = 1;
+    }
+
+    if (alarm_raise) {
+        DPRINTF("ALARM IRQ\n");
+        /* set irq status */
+        s->reg_intp |= INTP_ALM_ENABLE;
+        qemu_irq_raise(s->alm_irq);
+    }
+}
+
+/*
+ * RTC update frequency
+ * Parameters:
+ *     reg_value - current RTCCON register or his new value
+ */
+static void exynos4210_rtc_update_freq(Exynos4210RTCState *s,
+                                       uint32_t reg_value)
+{
+    uint32_t freq;
+
+    freq = s->freq;
+    /* set frequncy for time generator */
+    s->freq = RTC_BASE_FREQ / (1 << TICCKSEL(reg_value));
+
+    if (freq != s->freq) {
+        ptimer_set_freq(s->ptimer, s->freq);
+        DPRINTF("freq=%dHz\n", s->freq);
+    }
+}
+
+/* month is between 0 and 11. */
+static int get_days_in_month(int month, int year)
+{
+    static const int days_tab[12] = {
+        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    int d;
+    if ((unsigned)month >= 12) {
+        return 31;
+    }
+    d = days_tab[month];
+    if (month == 1) {
+        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
+            d++;
+        }
+    }
+    return d;
+}
+
+/* update 'tm' to the next second */
+static void rtc_next_second(struct tm *tm)
+{
+    int days_in_month;
+
+    tm->tm_sec++;
+    if ((unsigned)tm->tm_sec >= 60) {
+        tm->tm_sec = 0;
+        tm->tm_min++;
+        if ((unsigned)tm->tm_min >= 60) {
+            tm->tm_min = 0;
+            tm->tm_hour++;
+            if ((unsigned)tm->tm_hour >= 24) {
+                tm->tm_hour = 0;
+                /* next day */
+                tm->tm_wday++;
+                if ((unsigned)tm->tm_wday >= 7) {
+                    tm->tm_wday = 0;
+                }
+                days_in_month = get_days_in_month(tm->tm_mon,
+                                                  tm->tm_year + 1900);
+                tm->tm_mday++;
+                if (tm->tm_mday < 1) {
+                    tm->tm_mday = 1;
+                } else if (tm->tm_mday > days_in_month) {
+                    tm->tm_mday = 1;
+                    tm->tm_mon++;
+                    if (tm->tm_mon >= 12) {
+                        tm->tm_mon = 0;
+                        tm->tm_year++;
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*
+ * tick handler
+ */
+static void exynos4210_rtc_tick(void *opaque)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    DPRINTF("TICK IRQ\n");
+    /* set irq status */
+    s->reg_intp |= INTP_TICK_ENABLE;
+    /* raise IRQ */
+    qemu_irq_raise(s->tick_irq);
+
+    /* restart timer */
+    ptimer_set_count(s->ptimer, s->reg_ticcnt);
+    ptimer_run(s->ptimer, 1);
+}
+
+/*
+ * 1Hz clock handler
+ */
+static void exynos4210_rtc_1Hz_tick(void *opaque)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    rtc_next_second(&s->current_tm);
+    /* DPRINTF("1Hz tick\n"); */
+
+    /* raise IRQ */
+    if (s->reg_rtcalm & ALARM_INT_ENABLE) {
+        check_alarm_raise(s);
+    }
+
+    ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
+    ptimer_run(s->ptimer_1Hz, 1);
+}
+
+/*
+ * RTC Read
+ */
+static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    uint32_t value = 0;
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    switch (offset) {
+    case INTP:
+        value = s->reg_intp;
+        break;
+    case RTCCON:
+        value = s->reg_rtccon;
+        break;
+    case TICCNT:
+        value = s->reg_ticcnt;
+        break;
+    case RTCALM:
+        value = s->reg_rtcalm;
+        break;
+    case ALMSEC:
+        value = s->reg_almsec;
+        break;
+    case ALMMIN:
+        value = s->reg_almmin;
+        break;
+    case ALMHOUR:
+        value = s->reg_almhour;
+        break;
+    case ALMDAY:
+        value = s->reg_almday;
+        break;
+    case ALMMON:
+        value = s->reg_almmon;
+        break;
+    case ALMYEAR:
+        value = s->reg_almyear;
+        break;
+
+    case BCDSEC:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_sec);
+        break;
+    case BCDMIN:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_min);
+        break;
+    case BCDHOUR:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_hour);
+        break;
+    case BCDDAYWEEK:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_wday);
+        break;
+    case BCDDAY:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mday);
+        break;
+    case BCDMON:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mon + 1);
+        break;
+    case BCDYEAR:
+        value = BCD3DIGITS(s->current_tm.tm_year);
+        break;
+
+    case CURTICNT:
+        s->reg_curticcnt = ptimer_get_count(s->ptimer);
+        value = s->reg_curticcnt;
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+    }
+    return value;
+}
+
+/*
+ * RTC Write
+ */
+static void exynos4210_rtc_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    switch (offset) {
+    case INTP:
+        if (value & INTP_ALM_ENABLE) {
+            qemu_irq_lower(s->alm_irq);
+            s->reg_intp &= (~INTP_ALM_ENABLE);
+        }
+        if (value & INTP_TICK_ENABLE) {
+            qemu_irq_lower(s->tick_irq);
+            s->reg_intp &= (~INTP_TICK_ENABLE);
+        }
+        break;
+    case RTCCON:
+        if (value & RTC_ENABLE) {
+            exynos4210_rtc_update_freq(s, value);
+        }
+        if ((value & RTC_ENABLE) > (s->reg_rtccon & RTC_ENABLE)) {
+            /* clock timer */
+            ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
+            ptimer_run(s->ptimer_1Hz, 1);
+            DPRINTF("run clock timer\n");
+        }
+        if ((value & RTC_ENABLE) < (s->reg_rtccon & RTC_ENABLE)) {
+            /* tick timer */
+            ptimer_stop(s->ptimer);
+            /* clock timer */
+            ptimer_stop(s->ptimer_1Hz);
+            DPRINTF("stop all timers\n");
+        }
+        if (value & RTC_ENABLE) {
+            if ((value & TICK_TIMER_ENABLE) >
+                (s->reg_rtccon & TICK_TIMER_ENABLE) &&
+                (s->reg_ticcnt)) {
+                ptimer_set_count(s->ptimer, s->reg_ticcnt);
+                ptimer_run(s->ptimer, 1);
+                DPRINTF("run tick timer\n");
+            }
+            if ((value & TICK_TIMER_ENABLE) <
+                (s->reg_rtccon & TICK_TIMER_ENABLE)) {
+                ptimer_stop(s->ptimer);
+            }
+        }
+        s->reg_rtccon = value;
+        break;
+    case TICCNT:
+        if (value > TICNT_THRESHHOLD) {
+            s->reg_ticcnt = value;
+        } else {
+            fprintf(stderr,
+                    "[exynos4210.rtc: bad TICNT value %u ]\n",
+                    (uint32_t)value);
+        }
+        break;
+
+    case RTCALM:
+        s->reg_rtcalm = value;
+        break;
+    case ALMSEC:
+        s->reg_almsec = (value & 0x7f);
+        break;
+    case ALMMIN:
+        s->reg_almmin = (value & 0x7f);
+        break;
+    case ALMHOUR:
+        s->reg_almhour = (value & 0x3f);
+        break;
+    case ALMDAY:
+        s->reg_almday = (value & 0x3f);
+        break;
+    case ALMMON:
+        s->reg_almmon = (value & 0x1f);
+        break;
+    case ALMYEAR:
+        s->reg_almyear = (value & 0x0fff);
+        break;
+
+    case BCDSEC:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_sec = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDMIN:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_min = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDHOUR:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_hour = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDDAYWEEK:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_wday = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDDAY:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_mday = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDMON:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_mon = (int)from_bcd((uint8_t)value) - 1;
+        }
+        break;
+    case BCDYEAR:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            /* 3 digits */
+            s->current_tm.tm_year = (int)from_bcd((uint8_t)value) +
+                    (int)from_bcd((uint8_t)((value >> 8) & 0x0f)) * 100;
+        }
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+
+    }
+}
+
+/*
+ * Set default values to timer fields and registers
+ */
+static void exynos4210_rtc_reset(DeviceState *d)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)d;
+
+    qemu_get_timedate(&s->current_tm, 0);
+
+    DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n",
+            s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday,
+            s->current_tm.tm_hour, s->current_tm.tm_min, s->current_tm.tm_sec);
+
+    s->reg_intp = 0;
+    s->reg_rtccon = 0;
+    s->reg_ticcnt = 0;
+    s->reg_rtcalm = 0;
+    s->reg_almsec = 0;
+    s->reg_almmin = 0;
+    s->reg_almhour = 0;
+    s->reg_almday = 0;
+    s->reg_almmon = 0;
+    s->reg_almyear = 0;
+
+    s->reg_curticcnt = 0;
+
+    exynos4210_rtc_update_freq(s, s->reg_rtccon);
+    ptimer_stop(s->ptimer);
+    ptimer_stop(s->ptimer_1Hz);
+}
+
+static const MemoryRegionOps exynos4210_rtc_ops = {
+    .read = exynos4210_rtc_read,
+    .write = exynos4210_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * RTC timer initialization
+ */
+static int exynos4210_rtc_init(SysBusDevice *dev)
+{
+    Exynos4210RTCState *s = FROM_SYSBUS(Exynos4210RTCState, dev);
+    QEMUBH *bh;
+
+    bh = qemu_bh_new(exynos4210_rtc_tick, s);
+    s->ptimer = ptimer_init(bh);
+    ptimer_set_freq(s->ptimer, RTC_BASE_FREQ);
+    exynos4210_rtc_update_freq(s, 0);
+
+    bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
+    s->ptimer_1Hz = ptimer_init(bh);
+    ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
+
+    sysbus_init_irq(dev, &s->alm_irq);
+    sysbus_init_irq(dev, &s->tick_irq);
+
+    memory_region_init_io(&s->iomem, &exynos4210_rtc_ops, s, "exynos4210-rtc",
+            EXYNOS4210_RTC_REG_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_rtc_init;
+    dc->reset = exynos4210_rtc_reset;
+    dc->vmsd = &vmstate_exynos4210_rtc_state;
+}
+
+static const TypeInfo exynos4210_rtc_info = {
+    .name          = "exynos4210.rtc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210RTCState),
+    .class_init    = exynos4210_rtc_class_init,
+};
+
+static void exynos4210_rtc_register_types(void)
+{
+    type_register_static(&exynos4210_rtc_info);
+}
+
+type_init(exynos4210_rtc_register_types)
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
new file mode 100644 (file)
index 0000000..7043a34
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * QEMU GRLIB GPTimer Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+
+#include "trace.h"
+
+#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
+#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
+
+#define GPTIMER_MAX_TIMERS 8
+
+/* GPTimer Config register fields */
+#define GPTIMER_ENABLE      (1 << 0)
+#define GPTIMER_RESTART     (1 << 1)
+#define GPTIMER_LOAD        (1 << 2)
+#define GPTIMER_INT_ENABLE  (1 << 3)
+#define GPTIMER_INT_PENDING (1 << 4)
+#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
+#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
+
+/* Memory mapped register offsets */
+#define SCALER_OFFSET         0x00
+#define SCALER_RELOAD_OFFSET  0x04
+#define CONFIG_OFFSET         0x08
+#define COUNTER_OFFSET        0x00
+#define COUNTER_RELOAD_OFFSET 0x04
+#define TIMER_BASE            0x10
+
+typedef struct GPTimer     GPTimer;
+typedef struct GPTimerUnit GPTimerUnit;
+
+struct GPTimer {
+    QEMUBH *bh;
+    struct ptimer_state *ptimer;
+
+    qemu_irq     irq;
+    int          id;
+    GPTimerUnit *unit;
+
+    /* registers */
+    uint32_t counter;
+    uint32_t reload;
+    uint32_t config;
+};
+
+struct GPTimerUnit {
+    SysBusDevice  busdev;
+    MemoryRegion iomem;
+
+    uint32_t nr_timers;         /* Number of timers available */
+    uint32_t freq_hz;           /* System frequency */
+    uint32_t irq_line;          /* Base irq line */
+
+    GPTimer *timers;
+
+    /* registers */
+    uint32_t scaler;
+    uint32_t reload;
+    uint32_t config;
+};
+
+static void grlib_gptimer_enable(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+
+    ptimer_stop(timer->ptimer);
+
+    if (!(timer->config & GPTIMER_ENABLE)) {
+        /* Timer disabled */
+        trace_grlib_gptimer_disabled(timer->id, timer->config);
+        return;
+    }
+
+    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
+       underflow. Set count + 1 to simulate the GPTimer behavior. */
+
+    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
+
+    ptimer_set_count(timer->ptimer, timer->counter + 1);
+    ptimer_run(timer->ptimer, 1);
+}
+
+static void grlib_gptimer_restart(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+    trace_grlib_gptimer_restart(timer->id, timer->reload);
+
+    timer->counter = timer->reload;
+    grlib_gptimer_enable(timer);
+}
+
+static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
+{
+    int i = 0;
+    uint32_t value = 0;
+
+    assert(unit != NULL);
+
+    if (scaler > 0) {
+        value = unit->freq_hz / (scaler + 1);
+    } else {
+        value = unit->freq_hz;
+    }
+
+    trace_grlib_gptimer_set_scaler(scaler, value);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        ptimer_set_freq(unit->timers[i].ptimer, value);
+    }
+}
+
+static void grlib_gptimer_hit(void *opaque)
+{
+    GPTimer *timer = opaque;
+    assert(timer != NULL);
+
+    trace_grlib_gptimer_hit(timer->id);
+
+    /* Timer expired */
+
+    if (timer->config & GPTIMER_INT_ENABLE) {
+        /* Set the pending bit (only unset by write in the config register) */
+        timer->config |= GPTIMER_INT_PENDING;
+        qemu_irq_pulse(timer->irq);
+    }
+
+    if (timer->config & GPTIMER_RESTART) {
+        grlib_gptimer_restart(timer);
+    }
+}
+
+static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    GPTimerUnit        *unit  = opaque;
+    hwaddr  timer_addr;
+    int                 id;
+    uint32_t            value = 0;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case SCALER_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
+        return unit->scaler;
+
+    case SCALER_RELOAD_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->reload);
+        return unit->reload;
+
+    case CONFIG_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->config);
+        return unit->config;
+
+    default:
+        break;
+    }
+
+    timer_addr = (addr % TIMER_BASE);
+    id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr) {
+        case COUNTER_OFFSET:
+            value = ptimer_get_count(unit->timers[id].ptimer);
+            trace_grlib_gptimer_readl(id, addr, value);
+            return value;
+
+        case COUNTER_RELOAD_OFFSET:
+            value = unit->timers[id].reload;
+            trace_grlib_gptimer_readl(id, addr, value);
+            return value;
+
+        case CONFIG_OFFSET:
+            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
+            return unit->timers[id].config;
+
+        default:
+            break;
+        }
+
+    }
+
+    trace_grlib_gptimer_readl(-1, addr, 0);
+    return 0;
+}
+
+static void grlib_gptimer_write(void *opaque, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    GPTimerUnit        *unit = opaque;
+    hwaddr  timer_addr;
+    int                 id;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case SCALER_OFFSET:
+        value &= 0xFFFF; /* clean up the value */
+        unit->scaler = value;
+        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
+        return;
+
+    case SCALER_RELOAD_OFFSET:
+        value &= 0xFFFF; /* clean up the value */
+        unit->reload = value;
+        trace_grlib_gptimer_writel(-1, addr, unit->reload);
+        grlib_gptimer_set_scaler(unit, value);
+        return;
+
+    case CONFIG_OFFSET:
+        /* Read Only (disable timer freeze not supported) */
+        trace_grlib_gptimer_writel(-1, addr, 0);
+        return;
+
+    default:
+        break;
+    }
+
+    timer_addr = (addr % TIMER_BASE);
+    id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr) {
+        case COUNTER_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+            unit->timers[id].counter = value;
+            grlib_gptimer_enable(&unit->timers[id]);
+            return;
+
+        case COUNTER_RELOAD_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+            unit->timers[id].reload = value;
+            return;
+
+        case CONFIG_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+
+            if (value & GPTIMER_INT_PENDING) {
+                /* clear pending bit */
+                value &= ~GPTIMER_INT_PENDING;
+            } else {
+                /* keep pending bit */
+                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
+            }
+
+            unit->timers[id].config = value;
+
+            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
+               bits are present, we just have to call restart. */
+
+            if (value & GPTIMER_LOAD) {
+                grlib_gptimer_restart(&unit->timers[id]);
+            } else if (value & GPTIMER_ENABLE) {
+                grlib_gptimer_enable(&unit->timers[id]);
+            }
+
+            /* These fields must always be read as 0 */
+            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
+
+            unit->timers[id].config = value;
+            return;
+
+        default:
+            break;
+        }
+
+    }
+
+    trace_grlib_gptimer_writel(-1, addr, value);
+}
+
+static const MemoryRegionOps grlib_gptimer_ops = {
+    .read = grlib_gptimer_read,
+    .write = grlib_gptimer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void grlib_gptimer_reset(DeviceState *d)
+{
+    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
+    int          i    = 0;
+
+    assert(unit != NULL);
+
+    unit->scaler = 0;
+    unit->reload = 0;
+    unit->config = 0;
+
+    unit->config  = unit->nr_timers;
+    unit->config |= unit->irq_line << 3;
+    unit->config |= 1 << 8;     /* separate interrupt */
+    unit->config |= 1 << 9;     /* Disable timer freeze */
+
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->counter = 0;
+        timer->reload = 0;
+        timer->config = 0;
+        ptimer_stop(timer->ptimer);
+        ptimer_set_count(timer->ptimer, 0);
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+}
+
+static int grlib_gptimer_init(SysBusDevice *dev)
+{
+    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
+    unsigned int  i;
+
+    assert(unit->nr_timers > 0);
+    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
+
+    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->unit   = unit;
+        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
+        timer->ptimer = ptimer_init(timer->bh);
+        timer->id     = i;
+
+        /* One IRQ line for each timer */
+        sysbus_init_irq(dev, &timer->irq);
+
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+
+    memory_region_init_io(&unit->iomem, &grlib_gptimer_ops, unit, "gptimer",
+                          UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
+
+    sysbus_init_mmio(dev, &unit->iomem);
+    return 0;
+}
+
+static Property grlib_gptimer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
+    DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
+    DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_gptimer_init;
+    dc->reset = grlib_gptimer_reset;
+    dc->props = grlib_gptimer_properties;
+}
+
+static const TypeInfo grlib_gptimer_info = {
+    .name          = "grlib,gptimer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GPTimerUnit),
+    .class_init    = grlib_gptimer_class_init,
+};
+
+static void grlib_gptimer_register_types(void)
+{
+    type_register_static(&grlib_gptimer_info);
+}
+
+type_init(grlib_gptimer_register_types)
diff --git a/hw/timer/imx_timer.c b/hw/timer/imx_timer.c
new file mode 100644 (file)
index 0000000..03197e3
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * IMX31 Timer
+ *
+ * Copyright (c) 2008 OK Labs
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally written by Hans Jiang
+ * Updated by Peter Chubb
+ *
+ * This code is licensed under GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "hw/sysbus.h"
+#include "hw/arm/imx.h"
+
+//#define DEBUG_TIMER 1
+#ifdef DEBUG_TIMER
+#  define DPRINTF(fmt, args...) \
+      do { printf("imx_timer: " fmt , ##args); } while (0)
+#else
+#  define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+#  define IPRINTF(fmt, args...)                                         \
+    do  { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+#else
+#  define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * GPT : General purpose timer
+ *
+ * This timer counts up continuously while it is enabled, resetting itself
+ * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
+ * reaches the value of ocr1 (in periodic mode).  WE simulate this using a
+ * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
+ * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
+ * waiting_rov is set when counting from TIMER_MAX.
+ *
+ * In the real hardware, there are three comparison registers that can
+ * trigger interrupts, and compare channel 1 can be used to
+ * force-reset the timer. However, this is a `bare-bones'
+ * implementation: only what Linux 3.x uses has been implemented
+ * (free-running timer from 0 to OCR1 or TIMER_MAX) .
+ */
+
+
+#define TIMER_MAX  0XFFFFFFFFUL
+
+/* Control register.  Not all of these bits have any effect (yet) */
+#define GPT_CR_EN     (1 << 0)  /* GPT Enable */
+#define GPT_CR_ENMOD  (1 << 1)  /* GPT Enable Mode */
+#define GPT_CR_DBGEN  (1 << 2)  /* GPT Debug mode enable */
+#define GPT_CR_WAITEN (1 << 3)  /* GPT Wait Mode Enable  */
+#define GPT_CR_DOZEN  (1 << 4)  /* GPT Doze mode enable */
+#define GPT_CR_STOPEN (1 << 5)  /* GPT Stop Mode Enable */
+#define GPT_CR_CLKSRC_SHIFT (6)
+#define GPT_CR_CLKSRC_MASK  (0x7)
+
+#define GPT_CR_FRR    (1 << 9)  /* Freerun or Restart */
+#define GPT_CR_SWR    (1 << 15) /* Software Reset */
+#define GPT_CR_IM1    (3 << 16) /* Input capture channel 1 mode (2 bits) */
+#define GPT_CR_IM2    (3 << 18) /* Input capture channel 2 mode (2 bits) */
+#define GPT_CR_OM1    (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
+#define GPT_CR_OM2    (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
+#define GPT_CR_OM3    (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
+#define GPT_CR_FO1    (1 << 29) /* Force Output Compare Channel 1 */
+#define GPT_CR_FO2    (1 << 30) /* Force Output Compare Channel 2 */
+#define GPT_CR_FO3    (1 << 31) /* Force Output Compare Channel 3 */
+
+#define GPT_SR_OF1  (1 << 0)
+#define GPT_SR_ROV  (1 << 5)
+
+#define GPT_IR_OF1IE  (1 << 0)
+#define GPT_IR_ROVIE  (1 << 5)
+
+typedef struct {
+    SysBusDevice busdev;
+    ptimer_state *timer;
+    MemoryRegion iomem;
+    DeviceState *ccm;
+
+    uint32_t cr;
+    uint32_t pr;
+    uint32_t sr;
+    uint32_t ir;
+    uint32_t ocr1;
+    uint32_t cnt;
+
+    uint32_t waiting_rov;
+    qemu_irq irq;
+} IMXTimerGState;
+
+static const VMStateDescription vmstate_imx_timerg = {
+    .name = "imx-timerg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr, IMXTimerGState),
+        VMSTATE_UINT32(pr, IMXTimerGState),
+        VMSTATE_UINT32(sr, IMXTimerGState),
+        VMSTATE_UINT32(ir, IMXTimerGState),
+        VMSTATE_UINT32(ocr1, IMXTimerGState),
+        VMSTATE_UINT32(cnt, IMXTimerGState),
+        VMSTATE_UINT32(waiting_rov, IMXTimerGState),
+        VMSTATE_PTIMER(timer, IMXTimerGState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const IMXClk imx_timerg_clocks[] = {
+    NOCLK,    /* 000 No clock source */
+    IPG,      /* 001 ipg_clk, 532MHz*/
+    IPG,      /* 010 ipg_clk_highfreq */
+    NOCLK,    /* 011 not defined */
+    CLK_32k,  /* 100 ipg_clk_32k */
+    NOCLK,    /* 101 not defined */
+    NOCLK,    /* 110 not defined */
+    NOCLK,    /* 111 not defined */
+};
+
+
+static void imx_timerg_set_freq(IMXTimerGState *s)
+{
+    int clksrc;
+    uint32_t freq;
+
+    clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
+    freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
+
+    DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
+    if (freq) {
+        ptimer_set_freq(s->timer, freq);
+    }
+}
+
+static void imx_timerg_update(IMXTimerGState *s)
+{
+    uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
+
+    DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
+            s->sr & GPT_SR_OF1 ? "OF1" : "",
+            s->sr & GPT_SR_ROV ? "ROV" : "",
+            s->ir & GPT_SR_OF1 ? "OF1" : "",
+            s->ir & GPT_SR_ROV ? "ROV" : "",
+            s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
+
+
+    qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
+}
+
+static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
+{
+    uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
+    uint64_t cnt = ptimer_get_count(s->timer);
+    s->cnt = target - cnt;
+    return s->cnt;
+}
+
+static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
+{
+    uint64_t diff_cnt;
+
+    if (!(s->cr & GPT_CR_FRR)) {
+        IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
+        return;
+    }
+
+    /*
+     * For small timeouts, qemu sometimes runs too slow.
+     * Better deliver a late interrupt than none.
+     *
+     * In Reset mode (FRR bit clear)
+     * the ptimer reloads itself from OCR1;
+     * in free-running mode we need to fake
+     * running from 0 to ocr1 to TIMER_MAX
+     */
+    if (timeout > s->cnt) {
+        diff_cnt = timeout - s->cnt;
+    } else {
+        diff_cnt = 0;
+    }
+    ptimer_set_count(s->timer, diff_cnt);
+}
+
+static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMXTimerGState *s = (IMXTimerGState *)opaque;
+
+    DPRINTF("g-read(offset=%x)", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* Control Register */
+        DPRINTF(" cr = %x\n", s->cr);
+        return s->cr;
+
+    case 1: /* prescaler */
+        DPRINTF(" pr = %x\n", s->pr);
+        return s->pr;
+
+    case 2: /* Status Register */
+        DPRINTF(" sr = %x\n", s->sr);
+        return s->sr;
+
+    case 3: /* Interrupt Register */
+        DPRINTF(" ir = %x\n", s->ir);
+        return s->ir;
+
+    case 4: /* Output Compare Register 1 */
+        DPRINTF(" ocr1 = %x\n", s->ocr1);
+        return s->ocr1;
+
+
+    case 9: /* cnt */
+        imx_timerg_update_counts(s);
+        DPRINTF(" cnt = %x\n", s->cnt);
+        return s->cnt;
+    }
+
+    IPRINTF("imx_timerg_read: Bad offset %x\n",
+            (int)offset >> 2);
+    return 0;
+}
+
+static void imx_timerg_reset(DeviceState *dev)
+{
+    IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
+
+    /*
+     * Soft reset doesn't touch some bits; hard reset clears them
+     */
+    s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
+    s->sr = 0;
+    s->pr = 0;
+    s->ir = 0;
+    s->cnt = 0;
+    s->ocr1 = TIMER_MAX;
+    ptimer_stop(s->timer);
+    ptimer_set_limit(s->timer, TIMER_MAX, 1);
+    imx_timerg_set_freq(s);
+}
+
+static void imx_timerg_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    IMXTimerGState *s = (IMXTimerGState *)opaque;
+    DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
+            (unsigned int)value);
+
+    switch (offset >> 2) {
+    case 0: {
+        uint32_t oldcr = s->cr;
+        /* CR */
+        if (value & GPT_CR_SWR) { /* force reset */
+            value &= ~GPT_CR_SWR;
+            imx_timerg_reset(&s->busdev.qdev);
+            imx_timerg_update(s);
+        }
+
+        s->cr = value & ~0x7c00;
+        imx_timerg_set_freq(s);
+        if ((oldcr ^ value) & GPT_CR_EN) {
+            if (value & GPT_CR_EN) {
+                if (value & GPT_CR_ENMOD) {
+                    ptimer_set_count(s->timer, s->ocr1);
+                    s->cnt = 0;
+                }
+                ptimer_run(s->timer,
+                           (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
+            } else {
+                ptimer_stop(s->timer);
+            };
+        }
+        return;
+    }
+
+    case 1: /* Prescaler */
+        s->pr = value & 0xfff;
+        imx_timerg_set_freq(s);
+        return;
+
+    case 2: /* SR */
+        /*
+         * No point in implementing the status register bits to do with
+         * external interrupt sources.
+         */
+        value &= GPT_SR_OF1 | GPT_SR_ROV;
+        s->sr &= ~value;
+        imx_timerg_update(s);
+        return;
+
+    case 3: /* IR -- interrupt register */
+        s->ir = value & 0x3f;
+        imx_timerg_update(s);
+        return;
+
+    case 4: /* OCR1 -- output compare register */
+        /* In non-freerun mode, reset count when this register is written */
+        if (!(s->cr & GPT_CR_FRR)) {
+            s->waiting_rov = 0;
+            ptimer_set_limit(s->timer, value, 1);
+        } else {
+            imx_timerg_update_counts(s);
+            if (value > s->cnt) {
+                s->waiting_rov = 0;
+                imx_timerg_reload(s, value);
+            } else {
+                s->waiting_rov = 1;
+                imx_timerg_reload(s, TIMER_MAX - s->cnt);
+            }
+        }
+        s->ocr1 = value;
+        return;
+
+    default:
+        IPRINTF("imx_timerg_write: Bad offset %x\n",
+                (int)offset >> 2);
+    }
+}
+
+static void imx_timerg_timeout(void *opaque)
+{
+    IMXTimerGState *s = (IMXTimerGState *)opaque;
+
+    DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
+    if (s->cr & GPT_CR_FRR) {
+        /*
+         * Free running timer from 0 -> TIMERMAX
+         * Generates interrupt at TIMER_MAX and at cnt==ocr1
+         * If ocr1 == TIMER_MAX, then no need to reload timer.
+         */
+        if (s->ocr1 == TIMER_MAX) {
+            DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
+            s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
+            imx_timerg_update(s);
+            return;
+        }
+
+        if (s->waiting_rov) {
+            /*
+             * We were waiting for cnt==TIMER_MAX
+             */
+            s->sr |= GPT_SR_ROV;
+            s->waiting_rov = 0;
+            s->cnt = 0;
+            imx_timerg_reload(s, s->ocr1);
+        } else {
+            /* Must have got a cnt==ocr1 timeout. */
+            s->sr |= GPT_SR_OF1;
+            s->cnt = s->ocr1;
+            s->waiting_rov = 1;
+            imx_timerg_reload(s, TIMER_MAX);
+        }
+        imx_timerg_update(s);
+        return;
+    }
+
+    s->sr |= GPT_SR_OF1;
+    imx_timerg_update(s);
+}
+
+static const MemoryRegionOps imx_timerg_ops = {
+    .read = imx_timerg_read,
+    .write = imx_timerg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static int imx_timerg_init(SysBusDevice *dev)
+{
+    IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev);
+    QEMUBH *bh;
+
+    sysbus_init_irq(dev, &s->irq);
+    memory_region_init_io(&s->iomem, &imx_timerg_ops,
+                          s, "imxg-timer",
+                          0x00001000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    bh = qemu_bh_new(imx_timerg_timeout, s);
+    s->timer = ptimer_init(bh);
+
+    /* Hard reset resets extra bits in CR */
+    s->cr = 0;
+    return 0;
+}
+
+
+
+/*
+ * EPIT: Enhanced periodic interrupt timer
+ */
+
+#define CR_EN       (1 << 0)
+#define CR_ENMOD    (1 << 1)
+#define CR_OCIEN    (1 << 2)
+#define CR_RLD      (1 << 3)
+#define CR_PRESCALE_SHIFT (4)
+#define CR_PRESCALE_MASK  (0xfff)
+#define CR_SWR      (1 << 16)
+#define CR_IOVW     (1 << 17)
+#define CR_DBGEN    (1 << 18)
+#define CR_EPIT     (1 << 19)
+#define CR_DOZEN    (1 << 20)
+#define CR_STOPEN   (1 << 21)
+#define CR_CLKSRC_SHIFT (24)
+#define CR_CLKSRC_MASK  (0x3 << CR_CLKSRC_SHIFT)
+
+
+/*
+ * Exact clock frequencies vary from board to board.
+ * These are typical.
+ */
+static const IMXClk imx_timerp_clocks[] =  {
+    0,        /* disabled */
+    IPG, /* ipg_clk, ~532MHz */
+    IPG, /* ipg_clk_highfreq */
+    CLK_32k,    /* ipg_clk_32k -- ~32kHz */
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    ptimer_state *timer;
+    MemoryRegion iomem;
+    DeviceState *ccm;
+
+    uint32_t cr;
+    uint32_t lr;
+    uint32_t cmp;
+
+    uint32_t freq;
+    int int_level;
+    qemu_irq irq;
+} IMXTimerPState;
+
+/*
+ * Update interrupt status
+ */
+static void imx_timerp_update(IMXTimerPState *s)
+{
+    if (s->int_level && (s->cr & CR_OCIEN)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void imx_timerp_reset(DeviceState *dev)
+{
+    IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
+
+    s->cr = 0;
+    s->lr = TIMER_MAX;
+    s->int_level = 0;
+    s->cmp = 0;
+    ptimer_stop(s->timer);
+    ptimer_set_count(s->timer, TIMER_MAX);
+}
+
+static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+    DPRINTF("p-read(offset=%x)", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* Control Register */
+        DPRINTF("cr %x\n", s->cr);
+        return s->cr;
+
+    case 1: /* Status Register */
+        DPRINTF("int_level %x\n", s->int_level);
+        return s->int_level;
+
+    case 2: /* LR - ticks*/
+        DPRINTF("lr %x\n", s->lr);
+        return s->lr;
+
+    case 3: /* CMP */
+        DPRINTF("cmp %x\n", s->cmp);
+        return s->cmp;
+
+    case 4: /* CNT */
+        return ptimer_get_count(s->timer);
+    }
+    IPRINTF("imx_timerp_read: Bad offset %x\n",
+            (int)offset >> 2);
+    return 0;
+}
+
+static void set_timerp_freq(IMXTimerPState *s)
+{
+    int clksrc;
+    unsigned prescaler;
+    uint32_t freq;
+
+    clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
+    prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
+    freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
+
+    s->freq = freq;
+    DPRINTF("Setting ptimer frequency to %u\n", freq);
+
+    if (freq) {
+        ptimer_set_freq(s->timer, freq);
+    }
+}
+
+static void imx_timerp_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+    DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
+            (unsigned int)value);
+
+    switch (offset >> 2) {
+    case 0: /* CR */
+        if (value & CR_SWR) {
+            imx_timerp_reset(&s->busdev.qdev);
+            value &= ~CR_SWR;
+        }
+        s->cr = value & 0x03ffffff;
+        set_timerp_freq(s);
+
+        if (s->freq && (s->cr & CR_EN)) {
+            if (!(s->cr & CR_ENMOD)) {
+                ptimer_set_count(s->timer, s->lr);
+            }
+            ptimer_run(s->timer, 0);
+        } else {
+            ptimer_stop(s->timer);
+        }
+        break;
+
+    case 1: /* SR - ACK*/
+        s->int_level = 0;
+        imx_timerp_update(s);
+        break;
+
+    case 2: /* LR - set ticks */
+        s->lr = value;
+        ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW));
+        break;
+
+    case 3: /* CMP */
+        s->cmp = value;
+        if (value) {
+            IPRINTF(
+                "Values for EPIT comparison other than zero not supported\n"
+            );
+        }
+        break;
+
+    default:
+        IPRINTF("imx_timerp_write: Bad offset %x\n",
+                   (int)offset >> 2);
+    }
+}
+
+static void imx_timerp_tick(void *opaque)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+   DPRINTF("imxp tick\n");
+    if (!(s->cr & CR_RLD)) {
+        ptimer_set_count(s->timer, TIMER_MAX);
+    }
+    s->int_level = 1;
+    imx_timerp_update(s);
+}
+
+void imx_timerp_create(const hwaddr addr,
+                              qemu_irq irq,
+                              DeviceState *ccm)
+{
+    IMXTimerPState *pp;
+    DeviceState *dev;
+
+    dev = sysbus_create_simple("imx_timerp", addr, irq);
+    pp = container_of(dev, IMXTimerPState, busdev.qdev);
+    pp->ccm = ccm;
+}
+
+static const MemoryRegionOps imx_timerp_ops = {
+  .read = imx_timerp_read,
+  .write = imx_timerp_write,
+  .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_imx_timerp = {
+    .name = "imx-timerp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr, IMXTimerPState),
+        VMSTATE_UINT32(lr, IMXTimerPState),
+        VMSTATE_UINT32(cmp, IMXTimerPState),
+        VMSTATE_UINT32(freq, IMXTimerPState),
+        VMSTATE_INT32(int_level, IMXTimerPState),
+        VMSTATE_PTIMER(timer, IMXTimerPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int imx_timerp_init(SysBusDevice *dev)
+{
+    IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
+    QEMUBH *bh;
+
+    DPRINTF("imx_timerp_init\n");
+
+    sysbus_init_irq(dev, &s->irq);
+    memory_region_init_io(&s->iomem, &imx_timerp_ops,
+                          s, "imxp-timer",
+                          0x00001000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    bh = qemu_bh_new(imx_timerp_tick, s);
+    s->timer = ptimer_init(bh);
+
+    return 0;
+}
+
+
+void imx_timerg_create(const hwaddr addr,
+                              qemu_irq irq,
+                              DeviceState *ccm)
+{
+    IMXTimerGState *pp;
+    DeviceState *dev;
+
+    dev = sysbus_create_simple("imx_timerg", addr, irq);
+    pp = container_of(dev, IMXTimerGState, busdev.qdev);
+    pp->ccm = ccm;
+}
+
+static void imx_timerg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc  = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = imx_timerg_init;
+    dc->vmsd = &vmstate_imx_timerg;
+    dc->reset = imx_timerg_reset;
+    dc->desc = "i.MX general timer";
+}
+
+static void imx_timerp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc  = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = imx_timerp_init;
+    dc->vmsd = &vmstate_imx_timerp;
+    dc->reset = imx_timerp_reset;
+    dc->desc = "i.MX periodic timer";
+}
+
+static const TypeInfo imx_timerp_info = {
+    .name = "imx_timerp",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXTimerPState),
+    .class_init = imx_timerp_class_init,
+};
+
+static const TypeInfo imx_timerg_info = {
+    .name = "imx_timerg",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXTimerGState),
+    .class_init = imx_timerg_class_init,
+};
+
+static void imx_timer_register_types(void)
+{
+    type_register_static(&imx_timerp_info);
+    type_register_static(&imx_timerg_info);
+}
+
+type_init(imx_timer_register_types)
diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c
new file mode 100644 (file)
index 0000000..e06fac7
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  QEMU model of the LatticeMico32 timer block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32timer.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "qemu/error-report.h"
+
+#define DEFAULT_FREQUENCY (50*1000000)
+
+enum {
+    R_SR = 0,
+    R_CR,
+    R_PERIOD,
+    R_SNAPSHOT,
+    R_MAX
+};
+
+enum {
+    SR_TO    = (1 << 0),
+    SR_RUN   = (1 << 1),
+};
+
+enum {
+    CR_ITO   = (1 << 0),
+    CR_CONT  = (1 << 1),
+    CR_START = (1 << 2),
+    CR_STOP  = (1 << 3),
+};
+
+struct LM32TimerState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+
+    qemu_irq irq;
+    uint32_t freq_hz;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32TimerState LM32TimerState;
+
+static void timer_update_irq(LM32TimerState *s)
+{
+    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
+
+    trace_lm32_timer_irq_state(state);
+    qemu_set_irq(s->irq, state);
+}
+
+static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
+{
+    LM32TimerState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+    case R_CR:
+    case R_PERIOD:
+        r = s->regs[addr];
+        break;
+    case R_SNAPSHOT:
+        r = (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+    default:
+        error_report("lm32_timer: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_timer_memory_read(addr << 2, r);
+    return r;
+}
+
+static void timer_write(void *opaque, hwaddr addr,
+                        uint64_t value, unsigned size)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+        s->regs[R_SR] &= ~SR_TO;
+        break;
+    case R_CR:
+        s->regs[R_CR] = value;
+        if (s->regs[R_CR] & CR_START) {
+            ptimer_run(s->ptimer, 1);
+        }
+        if (s->regs[R_CR] & CR_STOP) {
+            ptimer_stop(s->ptimer);
+        }
+        break;
+    case R_PERIOD:
+        s->regs[R_PERIOD] = value;
+        ptimer_set_count(s->ptimer, value);
+        break;
+    case R_SNAPSHOT:
+        error_report("lm32_timer: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_timer: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    timer_update_irq(s);
+}
+
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void timer_hit(void *opaque)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_hit();
+
+    s->regs[R_SR] |= SR_TO;
+
+    if (s->regs[R_CR] & CR_CONT) {
+        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
+        ptimer_run(s->ptimer, 1);
+    }
+    timer_update_irq(s);
+}
+
+static void timer_reset(DeviceState *d)
+{
+    LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    ptimer_stop(s->ptimer);
+}
+
+static int lm32_timer_init(SysBusDevice *dev)
+{
+    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(timer_hit, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, s->freq_hz);
+
+    memory_region_init_io(&s->iomem, &timer_ops, s, "timer", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_timer = {
+    .name = "lm32-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, LM32TimerState),
+        VMSTATE_UINT32(freq_hz, LM32TimerState),
+        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property lm32_timer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_timer_init;
+    dc->reset = timer_reset;
+    dc->vmsd = &vmstate_lm32_timer;
+    dc->props = lm32_timer_properties;
+}
+
+static const TypeInfo lm32_timer_info = {
+    .name          = "lm32-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32TimerState),
+    .class_init    = lm32_timer_class_init,
+};
+
+static void lm32_timer_register_types(void)
+{
+    type_register_static(&lm32_timer_info);
+}
+
+type_init(lm32_timer_register_types)
diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c
new file mode 100644 (file)
index 0000000..e083a28
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/sysctl.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "qemu/error-report.h"
+
+enum {
+    CTRL_ENABLE      = (1<<0),
+    CTRL_AUTORESTART = (1<<1),
+};
+
+enum {
+    ICAP_READY       = (1<<0),
+};
+
+enum {
+    R_GPIO_IN         = 0,
+    R_GPIO_OUT,
+    R_GPIO_INTEN,
+    R_TIMER0_CONTROL  = 4,
+    R_TIMER0_COMPARE,
+    R_TIMER0_COUNTER,
+    R_TIMER1_CONTROL  = 8,
+    R_TIMER1_COMPARE,
+    R_TIMER1_COUNTER,
+    R_ICAP = 16,
+    R_DBG_SCRATCHPAD  = 20,
+    R_DBG_WRITE_LOCK,
+    R_CLK_FREQUENCY   = 29,
+    R_CAPABILITIES,
+    R_SYSTEM_ID,
+    R_MAX
+};
+
+struct MilkymistSysctlState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+
+    QEMUBH *bh0;
+    QEMUBH *bh1;
+    ptimer_state *ptimer0;
+    ptimer_state *ptimer1;
+
+    uint32_t freq_hz;
+    uint32_t capabilities;
+    uint32_t systemid;
+    uint32_t strappings;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq gpio_irq;
+    qemu_irq timer0_irq;
+    qemu_irq timer1_irq;
+};
+typedef struct MilkymistSysctlState MilkymistSysctlState;
+
+static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
+{
+    trace_milkymist_sysctl_icap_write(value);
+    switch (value & 0xffff) {
+    case 0x000e:
+        qemu_system_shutdown_request();
+        break;
+    }
+}
+
+static uint64_t sysctl_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    MilkymistSysctlState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_TIMER0_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer0);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER0_COMPARE] - r;
+        break;
+    case R_TIMER1_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer1);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER1_COMPARE] - r;
+        break;
+    case R_GPIO_IN:
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_CONTROL:
+    case R_TIMER0_COMPARE:
+    case R_TIMER1_CONTROL:
+    case R_TIMER1_COMPARE:
+    case R_ICAP:
+    case R_DBG_SCRATCHPAD:
+    case R_DBG_WRITE_LOCK:
+    case R_CLK_FREQUENCY:
+    case R_CAPABILITIES:
+    case R_SYSTEM_ID:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_sysctl: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_sysctl_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
+                         unsigned size)
+{
+    MilkymistSysctlState *s = opaque;
+
+    trace_milkymist_sysctl_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_COUNTER:
+    case R_TIMER1_COUNTER:
+    case R_DBG_SCRATCHPAD:
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_COMPARE:
+        ptimer_set_limit(s->ptimer0, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER1_COMPARE:
+        ptimer_set_limit(s->ptimer1, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer0();
+            ptimer_set_count(s->ptimer0,
+                    s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
+            ptimer_run(s->ptimer0, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer0();
+            ptimer_stop(s->ptimer0);
+        }
+        break;
+    case R_TIMER1_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer1();
+            ptimer_set_count(s->ptimer1,
+                    s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
+            ptimer_run(s->ptimer1, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer1();
+            ptimer_stop(s->ptimer1);
+        }
+        break;
+    case R_ICAP:
+        sysctl_icap_write(s, value);
+        break;
+    case R_DBG_WRITE_LOCK:
+        s->regs[addr] = 1;
+        break;
+    case R_SYSTEM_ID:
+        qemu_system_reset_request();
+        break;
+
+    case R_GPIO_IN:
+    case R_CLK_FREQUENCY:
+    case R_CAPABILITIES:
+        error_report("milkymist_sysctl: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_sysctl: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps sysctl_mmio_ops = {
+    .read = sysctl_read,
+    .write = sysctl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timer0_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer0();
+        ptimer_stop(s->ptimer0);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer0();
+    qemu_irq_pulse(s->timer0_irq);
+}
+
+static void timer1_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer1();
+        ptimer_stop(s->ptimer1);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer1();
+    qemu_irq_pulse(s->timer1_irq);
+}
+
+static void milkymist_sysctl_reset(DeviceState *d)
+{
+    MilkymistSysctlState *s =
+            container_of(d, MilkymistSysctlState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    ptimer_stop(s->ptimer0);
+    ptimer_stop(s->ptimer1);
+
+    /* defaults */
+    s->regs[R_ICAP] = ICAP_READY;
+    s->regs[R_SYSTEM_ID] = s->systemid;
+    s->regs[R_CLK_FREQUENCY] = s->freq_hz;
+    s->regs[R_CAPABILITIES] = s->capabilities;
+    s->regs[R_GPIO_IN] = s->strappings;
+}
+
+static int milkymist_sysctl_init(SysBusDevice *dev)
+{
+    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->gpio_irq);
+    sysbus_init_irq(dev, &s->timer0_irq);
+    sysbus_init_irq(dev, &s->timer1_irq);
+
+    s->bh0 = qemu_bh_new(timer0_hit, s);
+    s->bh1 = qemu_bh_new(timer1_hit, s);
+    s->ptimer0 = ptimer_init(s->bh0);
+    s->ptimer1 = ptimer_init(s->bh1);
+    ptimer_set_freq(s->ptimer0, s->freq_hz);
+    ptimer_set_freq(s->ptimer1, s->freq_hz);
+
+    memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
+            "milkymist-sysctl", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_sysctl = {
+    .name = "milkymist-sysctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
+        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
+        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_sysctl_properties[] = {
+    DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+    freq_hz, 80000000),
+    DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+    capabilities, 0x00000000),
+    DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+    systemid, 0x10014d31),
+    DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+    strappings, 0x00000001),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_sysctl_init;
+    dc->reset = milkymist_sysctl_reset;
+    dc->vmsd = &vmstate_milkymist_sysctl;
+    dc->props = milkymist_sysctl_properties;
+}
+
+static const TypeInfo milkymist_sysctl_info = {
+    .name          = "milkymist-sysctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistSysctlState),
+    .class_init    = milkymist_sysctl_class_init,
+};
+
+static void milkymist_sysctl_register_types(void)
+{
+    type_register_static(&milkymist_sysctl_info);
+}
+
+type_init(milkymist_sysctl_register_types)
diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c
new file mode 100644 (file)
index 0000000..9b0e9dd
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * TI OMAP2 general purpose timers emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/arm/omap.h"
+
+/* GP timers */
+struct omap_gp_timer_s {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq wkup;
+    qemu_irq in;
+    qemu_irq out;
+    omap_clk clk;
+    QEMUTimer *timer;
+    QEMUTimer *match;
+    struct omap_target_agent_s *ta;
+
+    int in_val;
+    int out_val;
+    int64_t time;
+    int64_t rate;
+    int64_t ticks_per_sec;
+
+    int16_t config;
+    int status;
+    int it_ena;
+    int wu_ena;
+    int enable;
+    int inout;
+    int capt2;
+    int pt;
+    enum {
+        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
+    } trigger;
+    enum {
+        gpt_capture_none, gpt_capture_rising,
+        gpt_capture_falling, gpt_capture_both
+    } capture;
+    int scpwm;
+    int ce;
+    int pre;
+    int ptv;
+    int ar;
+    int st;
+    int posted;
+    uint32_t val;
+    uint32_t load_val;
+    uint32_t capture_val[2];
+    uint32_t match_val;
+    int capt_num;
+
+    uint16_t writeh;   /* LSB */
+    uint16_t readh;    /* MSB */
+};
+
+#define GPT_TCAR_IT    (1 << 2)
+#define GPT_OVF_IT     (1 << 1)
+#define GPT_MAT_IT     (1 << 0)
+
+static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
+{
+    if (timer->it_ena & it) {
+        if (!timer->status)
+            qemu_irq_raise(timer->irq);
+
+        timer->status |= it;
+        /* Or are the status bits set even when masked?
+         * i.e. is masking applied before or after the status register?  */
+    }
+
+    if (timer->wu_ena & it)
+        qemu_irq_pulse(timer->wkup);
+}
+
+static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
+{
+    if (!timer->inout && timer->out_val != level) {
+        timer->out_val = level;
+        qemu_set_irq(timer->out, level);
+    }
+}
+
+static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
+{
+    uint64_t distance;
+
+    if (timer->st && timer->rate) {
+        distance = qemu_get_clock_ns(vm_clock) - timer->time;
+        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
+
+        if (distance >= 0xffffffff - timer->val)
+            return 0xffffffff;
+        else
+            return timer->val + distance;
+    } else
+        return timer->val;
+}
+
+static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
+{
+    if (timer->st) {
+        timer->val = omap_gp_timer_read(timer);
+        timer->time = qemu_get_clock_ns(vm_clock);
+    }
+}
+
+static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
+{
+    int64_t expires, matches;
+
+    if (timer->st && timer->rate) {
+        expires = muldiv64(0x100000000ll - timer->val,
+                        timer->ticks_per_sec, timer->rate);
+        qemu_mod_timer(timer->timer, timer->time + expires);
+
+        if (timer->ce && timer->match_val >= timer->val) {
+            matches = muldiv64(timer->match_val - timer->val,
+                            timer->ticks_per_sec, timer->rate);
+            qemu_mod_timer(timer->match, timer->time + matches);
+        } else
+            qemu_del_timer(timer->match);
+    } else {
+        qemu_del_timer(timer->timer);
+        qemu_del_timer(timer->match);
+        omap_gp_timer_out(timer, timer->scpwm);
+    }
+}
+
+static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
+{
+    if (timer->pt)
+        /* TODO in overflow-and-match mode if the first event to
+         * occur is the match, don't toggle.  */
+        omap_gp_timer_out(timer, !timer->out_val);
+    else
+        /* TODO inverted pulse on timer->out_val == 1?  */
+        qemu_irq_pulse(timer->out);
+}
+
+static void omap_gp_timer_tick(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (!timer->ar) {
+        timer->st = 0;
+        timer->val = 0;
+    } else {
+        timer->val = timer->load_val;
+        timer->time = qemu_get_clock_ns(vm_clock);
+    }
+
+    if (timer->trigger == gpt_trigger_overflow ||
+                    timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_OVF_IT);
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_match(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_MAT_IT);
+}
+
+static void omap_gp_timer_input(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    int trigger;
+
+    switch (s->capture) {
+    default:
+    case gpt_capture_none:
+        trigger = 0;
+        break;
+    case gpt_capture_rising:
+        trigger = !s->in_val && on;
+        break;
+    case gpt_capture_falling:
+        trigger = s->in_val && !on;
+        break;
+    case gpt_capture_both:
+        trigger = (s->in_val == !on);
+        break;
+    }
+    s->in_val = on;
+
+    if (s->inout && trigger && s->capt_num < 2) {
+        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
+
+        if (s->capt2 == s->capt_num ++)
+            omap_gp_timer_intr(s, GPT_TCAR_IT);
+    }
+}
+
+static void omap_gp_timer_clk_update(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    omap_gp_timer_sync(timer);
+    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
+{
+    omap_clk_adduser(timer->clk,
+                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
+void omap_gp_timer_reset(struct omap_gp_timer_s *s)
+{
+    s->config = 0x000;
+    s->status = 0;
+    s->it_ena = 0;
+    s->wu_ena = 0;
+    s->inout = 0;
+    s->capt2 = 0;
+    s->capt_num = 0;
+    s->pt = 0;
+    s->trigger = gpt_trigger_none;
+    s->capture = gpt_capture_none;
+    s->scpwm = 0;
+    s->ce = 0;
+    s->pre = 0;
+    s->ptv = 0;
+    s->ar = 0;
+    s->st = 0;
+    s->posted = 1;
+    s->val = 0x00000000;
+    s->load_val = 0x00000000;
+    s->capture_val[0] = 0x00000000;
+    s->capture_val[1] = 0x00000000;
+    s->match_val = 0x00000000;
+    omap_gp_timer_update(s);
+}
+
+static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* TIDR */
+        return 0x21;
+
+    case 0x10: /* TIOCP_CFG */
+        return s->config;
+
+    case 0x14: /* TISTAT */
+        /* ??? When's this bit reset? */
+        return 1;                                              /* RESETDONE */
+
+    case 0x18: /* TISR */
+        return s->status;
+
+    case 0x1c: /* TIER */
+        return s->it_ena;
+
+    case 0x20: /* TWER */
+        return s->wu_ena;
+
+    case 0x24: /* TCLR */
+        return (s->inout << 14) |
+                (s->capt2 << 13) |
+                (s->pt << 12) |
+                (s->trigger << 10) |
+                (s->capture << 8) |
+                (s->scpwm << 7) |
+                (s->ce << 6) |
+                (s->pre << 5) |
+                (s->ptv << 2) |
+                (s->ar << 1) |
+                (s->st << 0);
+
+    case 0x28: /* TCRR */
+        return omap_gp_timer_read(s);
+
+    case 0x2c: /* TLDR */
+        return s->load_val;
+
+    case 0x30: /* TTGR */
+        return 0xffffffff;
+
+    case 0x34: /* TWPS */
+        return 0x00000000;     /* No posted writes pending.  */
+
+    case 0x38: /* TMAR */
+        return s->match_val;
+
+    case 0x3c: /* TCAR1 */
+        return s->capture_val[0];
+
+    case 0x40: /* TSICR */
+        return s->posted << 2;
+
+    case 0x44: /* TCAR2 */
+        return s->capture_val[1];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_gp_timer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static void omap_gp_timer_write(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* TIDR */
+    case 0x14: /* TISTAT */
+    case 0x34: /* TWPS */
+    case 0x3c: /* TCAR1 */
+    case 0x44: /* TCAR2 */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* TIOCP_CFG */
+        s->config = value & 0x33d;
+        if (((value >> 3) & 3) == 3)                           /* IDLEMODE */
+            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
+                            __FUNCTION__);
+        if (value & 2)                                         /* SOFTRESET */
+            omap_gp_timer_reset(s);
+        break;
+
+    case 0x18: /* TISR */
+        if (value & GPT_TCAR_IT)
+            s->capt_num = 0;
+        if (s->status && !(s->status &= ~value))
+            qemu_irq_lower(s->irq);
+        break;
+
+    case 0x1c: /* TIER */
+        s->it_ena = value & 7;
+        break;
+
+    case 0x20: /* TWER */
+        s->wu_ena = value & 7;
+        break;
+
+    case 0x24: /* TCLR */
+        omap_gp_timer_sync(s);
+        s->inout = (value >> 14) & 1;
+        s->capt2 = (value >> 13) & 1;
+        s->pt = (value >> 12) & 1;
+        s->trigger = (value >> 10) & 3;
+        if (s->capture == gpt_capture_none &&
+                        ((value >> 8) & 3) != gpt_capture_none)
+            s->capt_num = 0;
+        s->capture = (value >> 8) & 3;
+        s->scpwm = (value >> 7) & 1;
+        s->ce = (value >> 6) & 1;
+        s->pre = (value >> 5) & 1;
+        s->ptv = (value >> 2) & 7;
+        s->ar = (value >> 1) & 1;
+        s->st = (value >> 0) & 1;
+        if (s->inout && s->trigger != gpt_trigger_none)
+            fprintf(stderr, "%s: GP timer pin must be an output "
+                            "for this trigger mode\n", __FUNCTION__);
+        if (!s->inout && s->capture != gpt_capture_none)
+            fprintf(stderr, "%s: GP timer pin must be an input "
+                            "for this capture mode\n", __FUNCTION__);
+        if (s->trigger == gpt_trigger_none)
+            omap_gp_timer_out(s, s->scpwm);
+        /* TODO: make sure this doesn't overflow 32-bits */
+        s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x28: /* TCRR */
+        s->time = qemu_get_clock_ns(vm_clock);
+        s->val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x2c: /* TLDR */
+        s->load_val = value;
+        break;
+
+    case 0x30: /* TTGR */
+        s->time = qemu_get_clock_ns(vm_clock);
+        s->val = s->load_val;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x38: /* TMAR */
+        omap_gp_timer_sync(s);
+        s->match_val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x40: /* TSICR */
+        s->posted = (value >> 2) & 1;
+        if (value & 2) /* How much exactly are we supposed to reset? */
+            omap_gp_timer_reset(s);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    if (addr & 2)
+        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
+    else
+        s->writeh = (uint16_t) value;
+}
+
+static const MemoryRegionOps omap_gp_timer_ops = {
+    .old_mmio = {
+        .read = {
+            omap_badwidth_read32,
+            omap_gp_timer_readh,
+            omap_gp_timer_readw,
+        },
+        .write = {
+            omap_badwidth_write32,
+            omap_gp_timer_writeh,
+            omap_gp_timer_write,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
+            g_malloc0(sizeof(struct omap_gp_timer_s));
+
+    s->ta = ta;
+    s->irq = irq;
+    s->clk = fclk;
+    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
+    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
+    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
+    omap_gp_timer_reset(s);
+    omap_gp_timer_clk_setup(s);
+
+    memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    return s;
+}
diff --git a/hw/timer/omap_synctimer.c b/hw/timer/omap_synctimer.c
new file mode 100644 (file)
index 0000000..a24f35c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * TI OMAP2 32kHz sync timer emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/arm/omap.h"
+struct omap_synctimer_s {
+    MemoryRegion iomem;
+    uint32_t val;
+    uint16_t readh;
+};
+
+/* 32-kHz Sync Timer of the OMAP2 */
+static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
+    return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec());
+}
+
+void omap_synctimer_reset(struct omap_synctimer_s *s)
+{
+    s->val = omap_synctimer_read(s);
+}
+
+static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* 32KSYNCNT_REV */
+        return 0x21;
+
+    case 0x10: /* CR */
+        return omap_synctimer_read(s) - s->val;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_synctimer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static void omap_synctimer_write(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap_synctimer_ops = {
+    .old_mmio = {
+        .read = {
+            omap_badwidth_read32,
+            omap_synctimer_readh,
+            omap_synctimer_readw,
+        },
+        .write = {
+            omap_badwidth_write32,
+            omap_synctimer_write,
+            omap_synctimer_write,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
+
+    omap_synctimer_reset(s);
+    memory_region_init_io(&s->iomem, &omap_synctimer_ops, s, "omap.synctimer",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    return s;
+}
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
new file mode 100644 (file)
index 0000000..8ea2416
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * Intel XScale PXA255/270 OS Timers.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/arm/pxa.h"
+#include "hw/sysbus.h"
+
+#define OSMR0  0x00
+#define OSMR1  0x04
+#define OSMR2  0x08
+#define OSMR3  0x0c
+#define OSMR4  0x80
+#define OSMR5  0x84
+#define OSMR6  0x88
+#define OSMR7  0x8c
+#define OSMR8  0x90
+#define OSMR9  0x94
+#define OSMR10 0x98
+#define OSMR11 0x9c
+#define OSCR   0x10    /* OS Timer Count */
+#define OSCR4  0x40
+#define OSCR5  0x44
+#define OSCR6  0x48
+#define OSCR7  0x4c
+#define OSCR8  0x50
+#define OSCR9  0x54
+#define OSCR10 0x58
+#define OSCR11 0x5c
+#define OSSR   0x14    /* Timer status register */
+#define OWER   0x18
+#define OIER   0x1c    /* Interrupt enable register  3-0 to E3-E0 */
+#define OMCR4  0xc0    /* OS Match Control registers */
+#define OMCR5  0xc4
+#define OMCR6  0xc8
+#define OMCR7  0xcc
+#define OMCR8  0xd0
+#define OMCR9  0xd4
+#define OMCR10 0xd8
+#define OMCR11 0xdc
+#define OSNR   0x20
+
+#define PXA25X_FREQ    3686400 /* 3.6864 MHz */
+#define PXA27X_FREQ    3250000 /* 3.25 MHz */
+
+static int pxa2xx_timer4_freq[8] = {
+    [0] = 0,
+    [1] = 32768,
+    [2] = 1000,
+    [3] = 1,
+    [4] = 1000000,
+    /* [5] is the "Externally supplied clock".  Assign if necessary.  */
+    [5 ... 7] = 0,
+};
+
+typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
+
+typedef struct {
+    uint32_t value;
+    qemu_irq irq;
+    QEMUTimer *qtimer;
+    int num;
+    PXA2xxTimerInfo *info;
+} PXA2xxTimer0;
+
+typedef struct {
+    PXA2xxTimer0 tm;
+    int32_t oldclock;
+    int32_t clock;
+    uint64_t lastload;
+    uint32_t freq;
+    uint32_t control;
+} PXA2xxTimer4;
+
+struct PXA2xxTimerInfo {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t flags;
+
+    int32_t clock;
+    int32_t oldclock;
+    uint64_t lastload;
+    uint32_t freq;
+    PXA2xxTimer0 timer[4];
+    uint32_t events;
+    uint32_t irq_enabled;
+    uint32_t reset3;
+    uint32_t snapshot;
+
+    qemu_irq irq4;
+    PXA2xxTimer4 tm4[8];
+};
+
+#define PXA2XX_TIMER_HAVE_TM4  0
+
+static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
+{
+    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
+}
+
+static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int i;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+
+    now_vm = s->clock +
+            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
+
+    for (i = 0; i < 4; i ++) {
+        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
+                        get_ticks_per_sec(), s->freq);
+        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
+    }
+}
+
+static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+    static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
+    int counter;
+
+    if (s->tm4[n].control & (1 << 7))
+        counter = n;
+    else
+        counter = counters[n];
+
+    if (!s->tm4[counter].freq) {
+        qemu_del_timer(s->tm4[n].tm.qtimer);
+        return;
+    }
+
+    now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
+                    s->tm4[counter].lastload,
+                    s->tm4[counter].freq, get_ticks_per_sec());
+
+    new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
+                    get_ticks_per_sec(), s->tm4[counter].freq);
+    qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
+}
+
+static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
+                                  unsigned size)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int tm = 0;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+        /* fall through */
+    case OSMR2:  tm ++;
+        /* fall through */
+    case OSMR1:  tm ++;
+        /* fall through */
+    case OSMR0:
+        return s->timer[tm].value;
+    case OSMR11: tm ++;
+        /* fall through */
+    case OSMR10: tm ++;
+        /* fall through */
+    case OSMR9:  tm ++;
+        /* fall through */
+    case OSMR8:  tm ++;
+        /* fall through */
+    case OSMR7:  tm ++;
+        /* fall through */
+    case OSMR6:  tm ++;
+        /* fall through */
+    case OSMR5:  tm ++;
+        /* fall through */
+    case OSMR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        return s->tm4[tm].tm.value;
+    case OSCR:
+        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->lastload, s->freq, get_ticks_per_sec());
+    case OSCR11: tm ++;
+        /* fall through */
+    case OSCR10: tm ++;
+        /* fall through */
+    case OSCR9:  tm ++;
+        /* fall through */
+    case OSCR8:  tm ++;
+        /* fall through */
+    case OSCR7:  tm ++;
+        /* fall through */
+    case OSCR6:  tm ++;
+        /* fall through */
+    case OSCR5:  tm ++;
+        /* fall through */
+    case OSCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+
+        if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
+            if (s->tm4[tm - 1].freq)
+                s->snapshot = s->tm4[tm - 1].clock + muldiv64(
+                                qemu_get_clock_ns(vm_clock) -
+                                s->tm4[tm - 1].lastload,
+                                s->tm4[tm - 1].freq, get_ticks_per_sec());
+            else
+                s->snapshot = s->tm4[tm - 1].clock;
+        }
+
+        if (!s->tm4[tm].freq)
+            return s->tm4[tm].clock;
+        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
+    case OIER:
+        return s->irq_enabled;
+    case OSSR: /* Status register */
+        return s->events;
+    case OWER:
+        return s->reset3;
+    case OMCR11: tm ++;
+        /* fall through */
+    case OMCR10: tm ++;
+        /* fall through */
+    case OMCR9:  tm ++;
+        /* fall through */
+    case OMCR8:  tm ++;
+        /* fall through */
+    case OMCR7:  tm ++;
+        /* fall through */
+    case OMCR6:  tm ++;
+        /* fall through */
+    case OMCR5:  tm ++;
+        /* fall through */
+    case OMCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        return s->tm4[tm].control;
+    case OSNR:
+        return s->snapshot;
+    default:
+    badreg:
+        hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_timer_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    int i, tm = 0;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+        /* fall through */
+    case OSMR2:  tm ++;
+        /* fall through */
+    case OSMR1:  tm ++;
+        /* fall through */
+    case OSMR0:
+        s->timer[tm].value = value;
+        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
+        break;
+    case OSMR11: tm ++;
+        /* fall through */
+    case OSMR10: tm ++;
+        /* fall through */
+    case OSMR9:  tm ++;
+        /* fall through */
+    case OSMR8:  tm ++;
+        /* fall through */
+    case OSMR7:  tm ++;
+        /* fall through */
+    case OSMR6:  tm ++;
+        /* fall through */
+    case OSMR5:  tm ++;
+        /* fall through */
+    case OSMR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].tm.value = value;
+        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        break;
+    case OSCR:
+        s->oldclock = s->clock;
+        s->lastload = qemu_get_clock_ns(vm_clock);
+        s->clock = value;
+        pxa2xx_timer_update(s, s->lastload);
+        break;
+    case OSCR11: tm ++;
+        /* fall through */
+    case OSCR10: tm ++;
+        /* fall through */
+    case OSCR9:  tm ++;
+        /* fall through */
+    case OSCR8:  tm ++;
+        /* fall through */
+    case OSCR7:  tm ++;
+        /* fall through */
+    case OSCR6:  tm ++;
+        /* fall through */
+    case OSCR5:  tm ++;
+        /* fall through */
+    case OSCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].oldclock = s->tm4[tm].clock;
+        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
+        s->tm4[tm].clock = value;
+        pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
+        break;
+    case OIER:
+        s->irq_enabled = value & 0xfff;
+        break;
+    case OSSR: /* Status register */
+        value &= s->events;
+        s->events &= ~value;
+        for (i = 0; i < 4; i ++, value >>= 1)
+            if (value & 1)
+                qemu_irq_lower(s->timer[i].irq);
+        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
+            qemu_irq_lower(s->irq4);
+        break;
+    case OWER: /* XXX: Reset on OSMR3 match? */
+        s->reset3 = value;
+        break;
+    case OMCR7:  tm ++;
+        /* fall through */
+    case OMCR6:  tm ++;
+        /* fall through */
+    case OMCR5:  tm ++;
+        /* fall through */
+    case OMCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].control = value & 0x0ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || tm == 0)
+            s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        }
+        break;
+    case OMCR11: tm ++;
+        /* fall through */
+    case OMCR10: tm ++;
+        /* fall through */
+    case OMCR9:  tm ++;
+        /* fall through */
+    case OMCR8:  tm += 4;
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].control = value & 0x3ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || !(tm & 1))
+            s->tm4[tm].freq =
+                    pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        }
+        break;
+    default:
+    badreg:
+        hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_timer_ops = {
+    .read = pxa2xx_timer_read,
+    .write = pxa2xx_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pxa2xx_timer_tick(void *opaque)
+{
+    PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
+    PXA2xxTimerInfo *i = t->info;
+
+    if (i->irq_enabled & (1 << t->num)) {
+        i->events |= 1 << t->num;
+        qemu_irq_raise(t->irq);
+    }
+
+    if (t->num == 3)
+        if (i->reset3 & 1) {
+            i->reset3 = 0;
+            qemu_system_reset_request();
+        }
+}
+
+static void pxa2xx_timer_tick4(void *opaque)
+{
+    PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
+    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
+
+    pxa2xx_timer_tick(&t->tm);
+    if (t->control & (1 << 3))
+        t->clock = 0;
+    if (t->control & (1 << 6))
+        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
+    if (i->events & 0xff0)
+        qemu_irq_raise(i->irq4);
+}
+
+static int pxa25x_timer_post_load(void *opaque, int version_id)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int64_t now;
+    int i;
+
+    now = qemu_get_clock_ns(vm_clock);
+    pxa2xx_timer_update(s, now);
+
+    if (pxa2xx_timer_has_tm4(s))
+        for (i = 0; i < 8; i ++)
+            pxa2xx_timer_update4(s, now, i);
+
+    return 0;
+}
+
+static int pxa2xx_timer_init(SysBusDevice *dev)
+{
+    int i;
+    PXA2xxTimerInfo *s;
+
+    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
+    s->irq_enabled = 0;
+    s->oldclock = 0;
+    s->clock = 0;
+    s->lastload = qemu_get_clock_ns(vm_clock);
+    s->reset3 = 0;
+
+    for (i = 0; i < 4; i ++) {
+        s->timer[i].value = 0;
+        sysbus_init_irq(dev, &s->timer[i].irq);
+        s->timer[i].info = s;
+        s->timer[i].num = i;
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick, &s->timer[i]);
+    }
+    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
+        sysbus_init_irq(dev, &s->irq4);
+
+        for (i = 0; i < 8; i ++) {
+            s->tm4[i].tm.value = 0;
+            s->tm4[i].tm.info = s;
+            s->tm4[i].tm.num = i + 4;
+            s->tm4[i].freq = 0;
+            s->tm4[i].control = 0x0;
+            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick4, &s->tm4[i]);
+        }
+    }
+
+    memory_region_init_io(&s->iomem, &pxa2xx_timer_ops, s,
+                          "pxa2xx-timer", 0x00001000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
+    .name = "pxa2xx_timer0",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(value, PXA2xxTimer0),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
+    .name = "pxa2xx_timer4",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_INT32(oldclock, PXA2xxTimer4),
+        VMSTATE_INT32(clock, PXA2xxTimer4),
+        VMSTATE_UINT64(lastload, PXA2xxTimer4),
+        VMSTATE_UINT32(freq, PXA2xxTimer4),
+        VMSTATE_UINT32(control, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
+{
+    return pxa2xx_timer_has_tm4(opaque);
+}
+
+static const VMStateDescription vmstate_pxa2xx_timer_regs = {
+    .name = "pxa2xx_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pxa25x_timer_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(clock, PXA2xxTimerInfo),
+        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
+        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_UINT32(events, PXA2xxTimerInfo),
+        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
+        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
+        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
+                        pxa2xx_timer_has_tm4_test, 0,
+                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static Property pxa25x_timer_dev_properties[] = {
+    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+    PXA2XX_TIMER_HAVE_TM4, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+    dc->desc = "PXA25x timer";
+    dc->vmsd = &vmstate_pxa2xx_timer_regs;
+    dc->props = pxa25x_timer_dev_properties;
+}
+
+static const TypeInfo pxa25x_timer_dev_info = {
+    .name          = "pxa25x-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxTimerInfo),
+    .class_init    = pxa25x_timer_dev_class_init,
+};
+
+static Property pxa27x_timer_dev_properties[] = {
+    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+    PXA2XX_TIMER_HAVE_TM4, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+    dc->desc = "PXA27x timer";
+    dc->vmsd = &vmstate_pxa2xx_timer_regs;
+    dc->props = pxa27x_timer_dev_properties;
+}
+
+static const TypeInfo pxa27x_timer_dev_info = {
+    .name          = "pxa27x-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxTimerInfo),
+    .class_init    = pxa27x_timer_dev_class_init,
+};
+
+static void pxa2xx_timer_register_types(void)
+{
+    type_register_static(&pxa25x_timer_dev_info);
+    type_register_static(&pxa27x_timer_dev_info);
+}
+
+type_init(pxa2xx_timer_register_types)
diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c
new file mode 100644 (file)
index 0000000..f92ff4f
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * SuperH Timer modules.
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/hw.h"
+#include "hw/sh4/sh.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+#include "hw/ptimer.h"
+
+//#define DEBUG_TIMER
+
+#define TIMER_TCR_TPSC          (7 << 0)
+#define TIMER_TCR_CKEG          (3 << 3)
+#define TIMER_TCR_UNIE          (1 << 5)
+#define TIMER_TCR_ICPE          (3 << 6)
+#define TIMER_TCR_UNF           (1 << 8)
+#define TIMER_TCR_ICPF          (1 << 9)
+#define TIMER_TCR_RESERVED      (0x3f << 10)
+
+#define TIMER_FEAT_CAPT   (1 << 0)
+#define TIMER_FEAT_EXTCLK (1 << 1)
+
+#define OFFSET_TCOR   0
+#define OFFSET_TCNT   1
+#define OFFSET_TCR    2
+#define OFFSET_TCPR   3
+
+typedef struct {
+    ptimer_state *timer;
+    uint32_t tcnt;
+    uint32_t tcor;
+    uint32_t tcr;
+    uint32_t tcpr;
+    int freq;
+    int int_level;
+    int old_level;
+    int feat;
+    int enabled;
+    qemu_irq irq;
+} sh_timer_state;
+
+/* Check all active timers, and schedule the next timer interrupt. */
+
+static void sh_timer_update(sh_timer_state *s)
+{
+    int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
+
+    if (new_level != s->old_level)
+      qemu_set_irq (s->irq, new_level);
+
+    s->old_level = s->int_level;
+    s->int_level = new_level;
+}
+
+static uint32_t sh_timer_read(void *opaque, hwaddr offset)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+    switch (offset >> 2) {
+    case OFFSET_TCOR:
+        return s->tcor;
+    case OFFSET_TCNT:
+        return ptimer_get_count(s->timer);
+    case OFFSET_TCR:
+        return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
+    case OFFSET_TCPR:
+        if (s->feat & TIMER_FEAT_CAPT)
+            return s->tcpr;
+    default:
+        hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void sh_timer_write(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    int freq;
+
+    switch (offset >> 2) {
+    case OFFSET_TCOR:
+        s->tcor = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        break;
+    case OFFSET_TCNT:
+        s->tcnt = value;
+        ptimer_set_count(s->timer, s->tcnt);
+        break;
+    case OFFSET_TCR:
+        if (s->enabled) {
+            /* Pause the timer if it is running.  This may cause some
+               inaccuracy dure to rounding, but avoids a whole lot of other
+               messyness.  */
+            ptimer_stop(s->timer);
+        }
+        freq = s->freq;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch (value & TIMER_TCR_TPSC) {
+        case 0: freq >>= 2; break;
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 6; break;
+        case 3: freq >>= 8; break;
+        case 4: freq >>= 10; break;
+       case 6:
+       case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
+       default: hw_error("sh_timer_write: Reserved TPSC value\n"); break;
+        }
+        switch ((value & TIMER_TCR_CKEG) >> 3) {
+       case 0: break;
+        case 1:
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
+       default: hw_error("sh_timer_write: Reserved CKEG value\n"); break;
+        }
+        switch ((value & TIMER_TCR_ICPE) >> 6) {
+       case 0: break;
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_CAPT) break;
+       default: hw_error("sh_timer_write: Reserved ICPE value\n"); break;
+        }
+       if ((value & TIMER_TCR_UNF) == 0)
+            s->int_level = 0;
+
+       value &= ~TIMER_TCR_UNF;
+
+       if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
+            hw_error("sh_timer_write: Reserved ICPF value\n");
+
+       value &= ~TIMER_TCR_ICPF; /* capture not supported */
+
+       if (value & TIMER_TCR_RESERVED)
+            hw_error("sh_timer_write: Reserved TCR bits set\n");
+        s->tcr = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        ptimer_set_freq(s->timer, freq);
+        if (s->enabled) {
+            /* Restart the timer if still enabled.  */
+            ptimer_run(s->timer, 0);
+        }
+        break;
+    case OFFSET_TCPR:
+        if (s->feat & TIMER_FEAT_CAPT) {
+            s->tcpr = value;
+           break;
+       }
+    default:
+        hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
+    }
+    sh_timer_update(s);
+}
+
+static void sh_timer_start_stop(void *opaque, int enable)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
+#endif
+
+    if (s->enabled && !enable) {
+        ptimer_stop(s->timer);
+    }
+    if (!s->enabled && enable) {
+        ptimer_run(s->timer, 0);
+    }
+    s->enabled = !!enable;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop done %d\n", s->enabled);
+#endif
+}
+
+static void sh_timer_tick(void *opaque)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    s->int_level = s->enabled;
+    sh_timer_update(s);
+}
+
+static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
+{
+    sh_timer_state *s;
+    QEMUBH *bh;
+
+    s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
+    s->freq = freq;
+    s->feat = feat;
+    s->tcor = 0xffffffff;
+    s->tcnt = 0xffffffff;
+    s->tcpr = 0xdeadbeef;
+    s->tcr = 0;
+    s->enabled = 0;
+    s->irq = irq;
+
+    bh = qemu_bh_new(sh_timer_tick, s);
+    s->timer = ptimer_init(bh);
+
+    sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
+    sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
+    sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr);
+    sh_timer_write(s, OFFSET_TCR  >> 2, s->tcpr);
+    /* ??? Save/restore.  */
+    return s;
+}
+
+typedef struct {
+    MemoryRegion iomem;
+    MemoryRegion iomem_p4;
+    MemoryRegion iomem_a7;
+    void *timer[3];
+    int level[3];
+    uint32_t tocr;
+    uint32_t tstr;
+    int feat;
+} tmu012_state;
+
+static uint64_t tmu012_read(void *opaque, hwaddr offset,
+                            unsigned size)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_read 0x%lx\n", (unsigned long) offset);
+#endif
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
+        return sh_timer_read(s->timer[2], offset - 0x20);
+    }
+
+    if (offset >= 0x14)
+        return sh_timer_read(s->timer[1], offset - 0x14);
+
+    if (offset >= 0x08)
+        return sh_timer_read(s->timer[0], offset - 0x08);
+
+    if (offset == 4)
+        return s->tstr;
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
+        return s->tocr;
+
+    hw_error("tmu012_write: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static void tmu012_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
+        sh_timer_write(s->timer[2], offset - 0x20, value);
+       return;
+    }
+
+    if (offset >= 0x14) {
+        sh_timer_write(s->timer[1], offset - 0x14, value);
+       return;
+    }
+
+    if (offset >= 0x08) {
+        sh_timer_write(s->timer[0], offset - 0x08, value);
+       return;
+    }
+
+    if (offset == 4) {
+        sh_timer_start_stop(s->timer[0], value & (1 << 0));
+        sh_timer_start_stop(s->timer[1], value & (1 << 1));
+        if (s->feat & TMU012_FEAT_3CHAN)
+            sh_timer_start_stop(s->timer[2], value & (1 << 2));
+       else
+            if (value & (1 << 2))
+                hw_error("tmu012_write: Bad channel\n");
+
+       s->tstr = value;
+       return;
+    }
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
+        s->tocr = value & (1 << 0);
+    }
+}
+
+static const MemoryRegionOps tmu012_ops = {
+    .read = tmu012_read,
+    .write = tmu012_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void tmu012_init(MemoryRegion *sysmem, hwaddr base,
+                 int feat, uint32_t freq,
+                qemu_irq ch0_irq, qemu_irq ch1_irq,
+                qemu_irq ch2_irq0, qemu_irq ch2_irq1)
+{
+    tmu012_state *s;
+    int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
+
+    s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
+    s->feat = feat;
+    s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
+    s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
+    if (feat & TMU012_FEAT_3CHAN)
+        s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
+                                   ch2_irq0); /* ch2_irq1 not supported */
+
+    memory_region_init_io(&s->iomem, &tmu012_ops, s,
+                          "timer", 0x100000000ULL);
+
+    memory_region_init_alias(&s->iomem_p4, "timer-p4",
+                             &s->iomem, 0, 0x1000);
+    memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
+
+    memory_region_init_alias(&s->iomem_a7, "timer-a7",
+                             &s->iomem, 0, 0x1000);
+    memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
+    /* ??? Save/restore.  */
+}
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
new file mode 100644 (file)
index 0000000..1145a87
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * QEMU Sparc SLAVIO timer controller emulation
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sparc/sun4m.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+/*
+ * Registers of hardware timer in sun4m.
+ *
+ * This is the timer/counter part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
+ * are zero. Bit 31 is 1 when count has been reached.
+ *
+ * Per-CPU timers interrupt local CPU, system timer uses normal
+ * interrupt routing.
+ *
+ */
+
+#define MAX_CPUS 16
+
+typedef struct CPUTimerState {
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint32_t count, counthigh, reached;
+    /* processor only */
+    uint32_t running;
+    uint64_t limit;
+} CPUTimerState;
+
+typedef struct SLAVIO_TIMERState {
+    SysBusDevice busdev;
+    uint32_t num_cpus;
+    uint32_t cputimer_mode;
+    CPUTimerState cputimer[MAX_CPUS + 1];
+} SLAVIO_TIMERState;
+
+typedef struct TimerContext {
+    MemoryRegion iomem;
+    SLAVIO_TIMERState *s;
+    unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
+} TimerContext;
+
+#define SYS_TIMER_SIZE 0x14
+#define CPU_TIMER_SIZE 0x10
+
+#define TIMER_LIMIT         0
+#define TIMER_COUNTER       1
+#define TIMER_COUNTER_NORST 2
+#define TIMER_STATUS        3
+#define TIMER_MODE          4
+
+#define TIMER_COUNT_MASK32 0xfffffe00
+#define TIMER_LIMIT_MASK32 0x7fffffff
+#define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
+#define TIMER_MAX_COUNT32  0x7ffffe00ULL
+#define TIMER_REACHED      0x80000000
+#define TIMER_PERIOD       500ULL // 500ns
+#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
+#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
+
+static int slavio_timer_is_user(TimerContext *tc)
+{
+    SLAVIO_TIMERState *s = tc->s;
+    unsigned int timer_index = tc->timer_index;
+
+    return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
+}
+
+// Update count, set irq, update expire_time
+// Convert from ptimer countdown units
+static void slavio_timer_get_out(CPUTimerState *t)
+{
+    uint64_t count, limit;
+
+    if (t->limit == 0) { /* free-run system or processor counter */
+        limit = TIMER_MAX_COUNT32;
+    } else {
+        limit = t->limit;
+    }
+    count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
+
+    trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
+    t->count = count & TIMER_COUNT_MASK32;
+    t->counthigh = count >> 32;
+}
+
+// timer callback
+static void slavio_timer_irq(void *opaque)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    CPUTimerState *t = &s->cputimer[tc->timer_index];
+
+    slavio_timer_get_out(t);
+    trace_slavio_timer_irq(t->counthigh, t->count);
+    /* if limit is 0 (free-run), there will be no match */
+    if (t->limit != 0) {
+        t->reached = TIMER_REACHED;
+    }
+    /* there is no interrupt if user timer or free-run */
+    if (!slavio_timer_is_user(tc) && t->limit != 0) {
+        qemu_irq_raise(t->irq);
+    }
+}
+
+static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
+                                       unsigned size)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    uint32_t saddr, ret;
+    unsigned int timer_index = tc->timer_index;
+    CPUTimerState *t = &s->cputimer[timer_index];
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        // read limit (system counter mode) or read most signifying
+        // part of counter (user mode)
+        if (slavio_timer_is_user(tc)) {
+            // read user timer MSW
+            slavio_timer_get_out(t);
+            ret = t->counthigh | t->reached;
+        } else {
+            // read limit
+            // clear irq
+            qemu_irq_lower(t->irq);
+            t->reached = 0;
+            ret = t->limit & TIMER_LIMIT_MASK32;
+        }
+        break;
+    case TIMER_COUNTER:
+        // read counter and reached bit (system mode) or read lsbits
+        // of counter (user mode)
+        slavio_timer_get_out(t);
+        if (slavio_timer_is_user(tc)) { // read user timer LSW
+            ret = t->count & TIMER_MAX_COUNT64;
+        } else { // read limit
+            ret = (t->count & TIMER_MAX_COUNT32) |
+                t->reached;
+        }
+        break;
+    case TIMER_STATUS:
+        // only available in processor counter/timer
+        // read start/stop status
+        if (timer_index > 0) {
+            ret = t->running;
+        } else {
+            ret = 0;
+        }
+        break;
+    case TIMER_MODE:
+        // only available in system counter
+        // read user/system mode
+        ret = s->cputimer_mode;
+        break;
+    default:
+        trace_slavio_timer_mem_readl_invalid(addr);
+        ret = 0;
+        break;
+    }
+    trace_slavio_timer_mem_readl(addr, ret);
+    return ret;
+}
+
+static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
+                                    uint64_t val, unsigned size)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    uint32_t saddr;
+    unsigned int timer_index = tc->timer_index;
+    CPUTimerState *t = &s->cputimer[timer_index];
+
+    trace_slavio_timer_mem_writel(addr, val);
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        if (slavio_timer_is_user(tc)) {
+            uint64_t count;
+
+            // set user counter MSW, reset counter
+            t->limit = TIMER_MAX_COUNT64;
+            t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
+            t->reached = 0;
+            count = ((uint64_t)t->counthigh << 32) | t->count;
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
+            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+        } else {
+            // set limit, reset counter
+            qemu_irq_lower(t->irq);
+            t->limit = val & TIMER_MAX_COUNT32;
+            if (t->timer) {
+                if (t->limit == 0) { /* free-run */
+                    ptimer_set_limit(t->timer,
+                                     LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+                } else {
+                    ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
+                }
+            }
+        }
+        break;
+    case TIMER_COUNTER:
+        if (slavio_timer_is_user(tc)) {
+            uint64_t count;
+
+            // set user counter LSW, reset counter
+            t->limit = TIMER_MAX_COUNT64;
+            t->count = val & TIMER_MAX_COUNT64;
+            t->reached = 0;
+            count = ((uint64_t)t->counthigh) << 32 | t->count;
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
+            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+        } else {
+            trace_slavio_timer_mem_writel_counter_invalid();
+        }
+        break;
+    case TIMER_COUNTER_NORST:
+        // set limit without resetting counter
+        t->limit = val & TIMER_MAX_COUNT32;
+        if (t->limit == 0) { /* free-run */
+            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
+        } else {
+            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
+        }
+        break;
+    case TIMER_STATUS:
+        if (slavio_timer_is_user(tc)) {
+            // start/stop user counter
+            if ((val & 1) && !t->running) {
+                trace_slavio_timer_mem_writel_status_start(timer_index);
+                ptimer_run(t->timer, 0);
+                t->running = 1;
+            } else if (!(val & 1) && t->running) {
+                trace_slavio_timer_mem_writel_status_stop(timer_index);
+                ptimer_stop(t->timer);
+                t->running = 0;
+            }
+        }
+        break;
+    case TIMER_MODE:
+        if (timer_index == 0) {
+            unsigned int i;
+
+            for (i = 0; i < s->num_cpus; i++) {
+                unsigned int processor = 1 << i;
+                CPUTimerState *curr_timer = &s->cputimer[i + 1];
+
+                // check for a change in timer mode for this processor
+                if ((val & processor) != (s->cputimer_mode & processor)) {
+                    if (val & processor) { // counter -> user timer
+                        qemu_irq_lower(curr_timer->irq);
+                        // counters are always running
+                        ptimer_stop(curr_timer->timer);
+                        curr_timer->running = 0;
+                        // user timer limit is always the same
+                        curr_timer->limit = TIMER_MAX_COUNT64;
+                        ptimer_set_limit(curr_timer->timer,
+                                         LIMIT_TO_PERIODS(curr_timer->limit),
+                                         1);
+                        // set this processors user timer bit in config
+                        // register
+                        s->cputimer_mode |= processor;
+                        trace_slavio_timer_mem_writel_mode_user(timer_index);
+                    } else { // user timer -> counter
+                        // stop the user timer if it is running
+                        if (curr_timer->running) {
+                            ptimer_stop(curr_timer->timer);
+                        }
+                        // start the counter
+                        ptimer_run(curr_timer->timer, 0);
+                        curr_timer->running = 1;
+                        // clear this processors user timer bit in config
+                        // register
+                        s->cputimer_mode &= ~processor;
+                        trace_slavio_timer_mem_writel_mode_counter(timer_index);
+                    }
+                }
+            }
+        } else {
+            trace_slavio_timer_mem_writel_mode_invalid();
+        }
+        break;
+    default:
+        trace_slavio_timer_mem_writel_invalid(addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_timer_mem_ops = {
+    .read = slavio_timer_mem_readl,
+    .write = slavio_timer_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const VMStateDescription vmstate_timer = {
+    .name ="timer",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(limit, CPUTimerState),
+        VMSTATE_UINT32(count, CPUTimerState),
+        VMSTATE_UINT32(counthigh, CPUTimerState),
+        VMSTATE_UINT32(reached, CPUTimerState),
+        VMSTATE_UINT32(running, CPUTimerState),
+        VMSTATE_PTIMER(timer, CPUTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slavio_timer = {
+    .name ="slavio_timer",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
+                             vmstate_timer, CPUTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void slavio_timer_reset(DeviceState *d)
+{
+    SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
+    unsigned int i;
+    CPUTimerState *curr_timer;
+
+    for (i = 0; i <= MAX_CPUS; i++) {
+        curr_timer = &s->cputimer[i];
+        curr_timer->limit = 0;
+        curr_timer->count = 0;
+        curr_timer->reached = 0;
+        if (i <= s->num_cpus) {
+            ptimer_set_limit(curr_timer->timer,
+                             LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+            ptimer_run(curr_timer->timer, 0);
+            curr_timer->running = 1;
+        }
+    }
+    s->cputimer_mode = 0;
+}
+
+static int slavio_timer_init1(SysBusDevice *dev)
+{
+    SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
+    QEMUBH *bh;
+    unsigned int i;
+    TimerContext *tc;
+
+    for (i = 0; i <= MAX_CPUS; i++) {
+        uint64_t size;
+        char timer_name[20];
+
+        tc = g_malloc0(sizeof(TimerContext));
+        tc->s = s;
+        tc->timer_index = i;
+
+        bh = qemu_bh_new(slavio_timer_irq, tc);
+        s->cputimer[i].timer = ptimer_init(bh);
+        ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
+
+        size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
+        snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
+        memory_region_init_io(&tc->iomem, &slavio_timer_mem_ops, tc,
+                              timer_name, size);
+        sysbus_init_mmio(dev, &tc->iomem);
+
+        sysbus_init_irq(dev, &s->cputimer[i].irq);
+    }
+
+    return 0;
+}
+
+static Property slavio_timer_properties[] = {
+    DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void slavio_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_timer_init1;
+    dc->reset = slavio_timer_reset;
+    dc->vmsd = &vmstate_slavio_timer;
+    dc->props = slavio_timer_properties;
+}
+
+static const TypeInfo slavio_timer_info = {
+    .name          = "slavio_timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SLAVIO_TIMERState),
+    .class_init    = slavio_timer_class_init,
+};
+
+static void slavio_timer_register_types(void)
+{
+    type_register_static(&slavio_timer_info);
+}
+
+type_init(slavio_timer_register_types)
diff --git a/hw/timer/tusb6010.c b/hw/timer/tusb6010.c
new file mode 100644 (file)
index 0000000..533938a
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Texas Instruments TUSB6010 emulation.
+ * Based on reverse-engineering of a linux driver.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "hw/usb.h"
+#include "hw/arm/omap.h"
+#include "hw/irq.h"
+#include "hw/arm/devices.h"
+#include "hw/sysbus.h"
+
+typedef struct TUSBState {
+    SysBusDevice busdev;
+    MemoryRegion iomem[2];
+    qemu_irq irq;
+    MUSBState *musb;
+    QEMUTimer *otg_timer;
+    QEMUTimer *pwr_timer;
+
+    int power;
+    uint32_t scratch;
+    uint16_t test_reset;
+    uint32_t prcm_config;
+    uint32_t prcm_mngmt;
+    uint16_t otg_status;
+    uint32_t dev_config;
+    int host_mode;
+    uint32_t intr;
+    uint32_t intr_ok;
+    uint32_t mask;
+    uint32_t usbip_intr;
+    uint32_t usbip_mask;
+    uint32_t gpio_intr;
+    uint32_t gpio_mask;
+    uint32_t gpio_config;
+    uint32_t dma_intr;
+    uint32_t dma_mask;
+    uint32_t dma_map;
+    uint32_t dma_config;
+    uint32_t ep0_config;
+    uint32_t rx_config[15];
+    uint32_t tx_config[15];
+    uint32_t wkup_mask;
+    uint32_t pullup[2];
+    uint32_t control_config;
+    uint32_t otg_timer_val;
+} TUSBState;
+
+#define TUSB_DEVCLOCK                  60000000        /* 60 MHz */
+
+#define TUSB_VLYNQ_CTRL                        0x004
+
+/* Mentor Graphics OTG core registers.  */
+#define TUSB_BASE_OFFSET               0x400
+
+/* FIFO registers, 32-bit.  */
+#define TUSB_FIFO_BASE                 0x600
+
+/* Device System & Control registers, 32-bit.  */
+#define TUSB_SYS_REG_BASE              0x800
+
+#define TUSB_DEV_CONF                  (TUSB_SYS_REG_BASE + 0x000)
+#define        TUSB_DEV_CONF_USB_HOST_MODE     (1 << 16)
+#define        TUSB_DEV_CONF_PROD_TEST_MODE    (1 << 15)
+#define        TUSB_DEV_CONF_SOFT_ID           (1 << 1)
+#define        TUSB_DEV_CONF_ID_SEL            (1 << 0)
+
+#define TUSB_PHY_OTG_CTRL_ENABLE       (TUSB_SYS_REG_BASE + 0x004)
+#define TUSB_PHY_OTG_CTRL              (TUSB_SYS_REG_BASE + 0x008)
+#define        TUSB_PHY_OTG_CTRL_WRPROTECT     (0xa5 << 24)
+#define        TUSB_PHY_OTG_CTRL_O_ID_PULLUP   (1 << 23)
+#define        TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
+#define        TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
+#define        TUSB_PHY_OTG_CTRL_TESTM2        (1 << 17)
+#define        TUSB_PHY_OTG_CTRL_TESTM1        (1 << 16)
+#define        TUSB_PHY_OTG_CTRL_TESTM0        (1 << 15)
+#define        TUSB_PHY_OTG_CTRL_TX_DATA2      (1 << 14)
+#define        TUSB_PHY_OTG_CTRL_TX_GZ2        (1 << 13)
+#define        TUSB_PHY_OTG_CTRL_TX_ENABLE2    (1 << 12)
+#define        TUSB_PHY_OTG_CTRL_DM_PULLDOWN   (1 << 11)
+#define        TUSB_PHY_OTG_CTRL_DP_PULLDOWN   (1 << 10)
+#define        TUSB_PHY_OTG_CTRL_OSC_EN        (1 << 9)
+#define        TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
+#define        TUSB_PHY_OTG_CTRL_PD            (1 << 6)
+#define        TUSB_PHY_OTG_CTRL_PLL_ON        (1 << 5)
+#define        TUSB_PHY_OTG_CTRL_EXT_RPU       (1 << 4)
+#define        TUSB_PHY_OTG_CTRL_PWR_GOOD      (1 << 3)
+#define        TUSB_PHY_OTG_CTRL_RESET         (1 << 2)
+#define        TUSB_PHY_OTG_CTRL_SUSPENDM      (1 << 1)
+#define        TUSB_PHY_OTG_CTRL_CLK_MODE      (1 << 0)
+
+/* OTG status register */
+#define TUSB_DEV_OTG_STAT              (TUSB_SYS_REG_BASE + 0x00c)
+#define        TUSB_DEV_OTG_STAT_PWR_CLK_GOOD  (1 << 8)
+#define        TUSB_DEV_OTG_STAT_SESS_END      (1 << 7)
+#define        TUSB_DEV_OTG_STAT_SESS_VALID    (1 << 6)
+#define        TUSB_DEV_OTG_STAT_VBUS_VALID    (1 << 5)
+#define        TUSB_DEV_OTG_STAT_VBUS_SENSE    (1 << 4)
+#define        TUSB_DEV_OTG_STAT_ID_STATUS     (1 << 3)
+#define        TUSB_DEV_OTG_STAT_HOST_DISCON   (1 << 2)
+#define        TUSB_DEV_OTG_STAT_LINE_STATE    (3 << 0)
+#define        TUSB_DEV_OTG_STAT_DP_ENABLE     (1 << 1)
+#define        TUSB_DEV_OTG_STAT_DM_ENABLE     (1 << 0)
+
+#define TUSB_DEV_OTG_TIMER             (TUSB_SYS_REG_BASE + 0x010)
+#define TUSB_DEV_OTG_TIMER_ENABLE      (1 << 31)
+#define TUSB_DEV_OTG_TIMER_VAL(v)      ((v) & 0x07ffffff)
+#define TUSB_PRCM_REV                  (TUSB_SYS_REG_BASE + 0x014)
+
+/* PRCM configuration register */
+#define TUSB_PRCM_CONF                 (TUSB_SYS_REG_BASE + 0x018)
+#define        TUSB_PRCM_CONF_SFW_CPEN         (1 << 24)
+#define        TUSB_PRCM_CONF_SYS_CLKSEL(v)    (((v) & 3) << 16)
+
+/* PRCM management register */
+#define TUSB_PRCM_MNGMT                        (TUSB_SYS_REG_BASE + 0x01c)
+#define        TUSB_PRCM_MNGMT_SRP_FIX_TMR(v)  (((v) & 0xf) << 25)
+#define        TUSB_PRCM_MNGMT_SRP_FIX_EN      (1 << 24)
+#define        TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
+#define        TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
+#define        TUSB_PRCM_MNGMT_DFT_CLK_DIS     (1 << 18)
+#define        TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS   (1 << 17)
+#define        TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
+#define        TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
+#define        TUSB_PRCM_MNGMT_OTG_ID_PULLUP   (1 << 8)
+#define        TUSB_PRCM_MNGMT_15_SW_EN        (1 << 4)
+#define        TUSB_PRCM_MNGMT_33_SW_EN        (1 << 3)
+#define        TUSB_PRCM_MNGMT_5V_CPEN         (1 << 2)
+#define        TUSB_PRCM_MNGMT_PM_IDLE         (1 << 1)
+#define        TUSB_PRCM_MNGMT_DEV_IDLE        (1 << 0)
+
+/* Wake-up source clear and mask registers */
+#define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
+#define TUSB_PRCM_WAKEUP_CLEAR         (TUSB_SYS_REG_BASE + 0x028)
+#define TUSB_PRCM_WAKEUP_MASK          (TUSB_SYS_REG_BASE + 0x02c)
+#define        TUSB_PRCM_WAKEUP_RESERVED_BITS  (0xffffe << 13)
+#define        TUSB_PRCM_WGPIO_7               (1 << 12)
+#define        TUSB_PRCM_WGPIO_6               (1 << 11)
+#define        TUSB_PRCM_WGPIO_5               (1 << 10)
+#define        TUSB_PRCM_WGPIO_4               (1 << 9)
+#define        TUSB_PRCM_WGPIO_3               (1 << 8)
+#define        TUSB_PRCM_WGPIO_2               (1 << 7)
+#define        TUSB_PRCM_WGPIO_1               (1 << 6)
+#define        TUSB_PRCM_WGPIO_0               (1 << 5)
+#define        TUSB_PRCM_WHOSTDISCON           (1 << 4)        /* Host disconnect */
+#define        TUSB_PRCM_WBUS                  (1 << 3)        /* USB bus resume */
+#define        TUSB_PRCM_WNORCS                (1 << 2)        /* NOR chip select */
+#define        TUSB_PRCM_WVBUS                 (1 << 1)        /* OTG PHY VBUS */
+#define        TUSB_PRCM_WID                   (1 << 0)        /* OTG PHY ID detect */
+
+#define TUSB_PULLUP_1_CTRL             (TUSB_SYS_REG_BASE + 0x030)
+#define TUSB_PULLUP_2_CTRL             (TUSB_SYS_REG_BASE + 0x034)
+#define TUSB_INT_CTRL_REV              (TUSB_SYS_REG_BASE + 0x038)
+#define TUSB_INT_CTRL_CONF             (TUSB_SYS_REG_BASE + 0x03c)
+#define TUSB_USBIP_INT_SRC             (TUSB_SYS_REG_BASE + 0x040)
+#define TUSB_USBIP_INT_SET             (TUSB_SYS_REG_BASE + 0x044)
+#define TUSB_USBIP_INT_CLEAR           (TUSB_SYS_REG_BASE + 0x048)
+#define TUSB_USBIP_INT_MASK            (TUSB_SYS_REG_BASE + 0x04c)
+#define TUSB_DMA_INT_SRC               (TUSB_SYS_REG_BASE + 0x050)
+#define TUSB_DMA_INT_SET               (TUSB_SYS_REG_BASE + 0x054)
+#define TUSB_DMA_INT_CLEAR             (TUSB_SYS_REG_BASE + 0x058)
+#define TUSB_DMA_INT_MASK              (TUSB_SYS_REG_BASE + 0x05c)
+#define TUSB_GPIO_INT_SRC              (TUSB_SYS_REG_BASE + 0x060)
+#define TUSB_GPIO_INT_SET              (TUSB_SYS_REG_BASE + 0x064)
+#define TUSB_GPIO_INT_CLEAR            (TUSB_SYS_REG_BASE + 0x068)
+#define TUSB_GPIO_INT_MASK             (TUSB_SYS_REG_BASE + 0x06c)
+
+/* NOR flash interrupt source registers */
+#define TUSB_INT_SRC                   (TUSB_SYS_REG_BASE + 0x070)
+#define TUSB_INT_SRC_SET               (TUSB_SYS_REG_BASE + 0x074)
+#define TUSB_INT_SRC_CLEAR             (TUSB_SYS_REG_BASE + 0x078)
+#define TUSB_INT_MASK                  (TUSB_SYS_REG_BASE + 0x07c)
+#define        TUSB_INT_SRC_TXRX_DMA_DONE      (1 << 24)
+#define        TUSB_INT_SRC_USB_IP_CORE        (1 << 17)
+#define        TUSB_INT_SRC_OTG_TIMEOUT        (1 << 16)
+#define        TUSB_INT_SRC_VBUS_SENSE_CHNG    (1 << 15)
+#define        TUSB_INT_SRC_ID_STATUS_CHNG     (1 << 14)
+#define        TUSB_INT_SRC_DEV_WAKEUP         (1 << 13)
+#define        TUSB_INT_SRC_DEV_READY          (1 << 12)
+#define        TUSB_INT_SRC_USB_IP_TX          (1 << 9)
+#define        TUSB_INT_SRC_USB_IP_RX          (1 << 8)
+#define        TUSB_INT_SRC_USB_IP_VBUS_ERR    (1 << 7)
+#define        TUSB_INT_SRC_USB_IP_VBUS_REQ    (1 << 6)
+#define        TUSB_INT_SRC_USB_IP_DISCON      (1 << 5)
+#define        TUSB_INT_SRC_USB_IP_CONN        (1 << 4)
+#define        TUSB_INT_SRC_USB_IP_SOF         (1 << 3)
+#define        TUSB_INT_SRC_USB_IP_RST_BABBLE  (1 << 2)
+#define        TUSB_INT_SRC_USB_IP_RESUME      (1 << 1)
+#define        TUSB_INT_SRC_USB_IP_SUSPEND     (1 << 0)
+
+#define TUSB_GPIO_REV                  (TUSB_SYS_REG_BASE + 0x080)
+#define TUSB_GPIO_CONF                 (TUSB_SYS_REG_BASE + 0x084)
+#define TUSB_DMA_CTRL_REV              (TUSB_SYS_REG_BASE + 0x100)
+#define TUSB_DMA_REQ_CONF              (TUSB_SYS_REG_BASE + 0x104)
+#define TUSB_EP0_CONF                  (TUSB_SYS_REG_BASE + 0x108)
+#define TUSB_EP_IN_SIZE                        (TUSB_SYS_REG_BASE + 0x10c)
+#define TUSB_DMA_EP_MAP                        (TUSB_SYS_REG_BASE + 0x148)
+#define TUSB_EP_OUT_SIZE               (TUSB_SYS_REG_BASE + 0x14c)
+#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
+#define TUSB_SCRATCH_PAD               (TUSB_SYS_REG_BASE + 0x1c4)
+#define TUSB_WAIT_COUNT                        (TUSB_SYS_REG_BASE + 0x1c8)
+#define TUSB_PROD_TEST_RESET           (TUSB_SYS_REG_BASE + 0x1d8)
+
+#define TUSB_DIDR1_LO                  (TUSB_SYS_REG_BASE + 0x1f8)
+#define TUSB_DIDR1_HI                  (TUSB_SYS_REG_BASE + 0x1fc)
+
+/* Device System & Control register bitfields */
+#define TUSB_INT_CTRL_CONF_INT_RLCYC(v)        (((v) & 0x7) << 18)
+#define TUSB_INT_CTRL_CONF_INT_POLARITY        (1 << 17)
+#define TUSB_INT_CTRL_CONF_INT_MODE    (1 << 16)
+#define TUSB_GPIO_CONF_DMAREQ(v)       (((v) & 0x3f) << 24)
+#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)        (((v) & 3) << 26)
+#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
+#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v)        (((v) & 0xf) << 16)
+#define TUSB_EP0_CONFIG_SW_EN          (1 << 8)
+#define TUSB_EP0_CONFIG_DIR_TX         (1 << 7)
+#define TUSB_EP0_CONFIG_XFR_SIZE(v)    ((v) & 0x7f)
+#define TUSB_EP_CONFIG_SW_EN           (1 << 31)
+#define TUSB_EP_CONFIG_XFR_SIZE(v)     ((v) & 0x7fffffff)
+#define TUSB_PROD_TEST_RESET_VAL       0xa596
+
+static void tusb_intr_update(TUSBState *s)
+{
+    if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
+        qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
+    else
+        qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
+}
+
+static void tusb_usbip_intr_update(TUSBState *s)
+{
+    /* TX interrupt in the MUSB */
+    if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
+        s->intr |= TUSB_INT_SRC_USB_IP_TX;
+    else
+        s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
+
+    /* RX interrupt in the MUSB */
+    if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
+        s->intr |= TUSB_INT_SRC_USB_IP_RX;
+    else
+        s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
+
+    /* XXX: What about TUSB_INT_SRC_USB_IP_CORE?  */
+
+    tusb_intr_update(s);
+}
+
+static void tusb_dma_intr_update(TUSBState *s)
+{
+    if (s->dma_intr & ~s->dma_mask)
+        s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
+    else
+        s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
+
+    tusb_intr_update(s);
+}
+
+static void tusb_gpio_intr_update(TUSBState *s)
+{
+    /* TODO: How is this signalled?  */
+}
+
+extern CPUReadMemoryFunc * const musb_read[];
+extern CPUWriteMemoryFunc * const musb_write[];
+
+static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[0](s->musb, addr & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+    }
+
+    printf("%s: unknown register at %03x\n",
+                    __FUNCTION__, (int) (addr & 0xfff));
+    return 0;
+}
+
+static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[1](s->musb, addr & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+    }
+
+    printf("%s: unknown register at %03x\n",
+                    __FUNCTION__, (int) (addr & 0xfff));
+    return 0;
+}
+
+static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    int offset = addr & 0xfff;
+    int epnum;
+    uint32_t ret;
+
+    switch (offset) {
+    case TUSB_DEV_CONF:
+        return s->dev_config;
+
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[2](s->musb, offset & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+
+    case TUSB_PHY_OTG_CTRL_ENABLE:
+    case TUSB_PHY_OTG_CTRL:
+        return 0x00;   /* TODO */
+
+    case TUSB_DEV_OTG_STAT:
+        ret = s->otg_status;
+#if 0
+        if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
+            ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
+#endif
+        return ret;
+    case TUSB_DEV_OTG_TIMER:
+        return s->otg_timer_val;
+
+    case TUSB_PRCM_REV:
+        return 0x20;
+    case TUSB_PRCM_CONF:
+        return s->prcm_config;
+    case TUSB_PRCM_MNGMT:
+        return s->prcm_mngmt;
+    case TUSB_PRCM_WAKEUP_SOURCE:
+    case TUSB_PRCM_WAKEUP_CLEAR:       /* TODO: What does this one return?  */
+        return 0x00000000;
+    case TUSB_PRCM_WAKEUP_MASK:
+        return s->wkup_mask;
+
+    case TUSB_PULLUP_1_CTRL:
+        return s->pullup[0];
+    case TUSB_PULLUP_2_CTRL:
+        return s->pullup[1];
+
+    case TUSB_INT_CTRL_REV:
+        return 0x20;
+    case TUSB_INT_CTRL_CONF:
+        return s->control_config;
+
+    case TUSB_USBIP_INT_SRC:
+    case TUSB_USBIP_INT_SET:   /* TODO: What do these two return?  */
+    case TUSB_USBIP_INT_CLEAR:
+        return s->usbip_intr;
+    case TUSB_USBIP_INT_MASK:
+        return s->usbip_mask;
+
+    case TUSB_DMA_INT_SRC:
+    case TUSB_DMA_INT_SET:     /* TODO: What do these two return?  */
+    case TUSB_DMA_INT_CLEAR:
+        return s->dma_intr;
+    case TUSB_DMA_INT_MASK:
+        return s->dma_mask;
+
+    case TUSB_GPIO_INT_SRC:    /* TODO: What do these two return?  */
+    case TUSB_GPIO_INT_SET:
+    case TUSB_GPIO_INT_CLEAR:
+        return s->gpio_intr;
+    case TUSB_GPIO_INT_MASK:
+        return s->gpio_mask;
+
+    case TUSB_INT_SRC:
+    case TUSB_INT_SRC_SET:     /* TODO: What do these two return?  */
+    case TUSB_INT_SRC_CLEAR:
+        return s->intr;
+    case TUSB_INT_MASK:
+        return s->mask;
+
+    case TUSB_GPIO_REV:
+        return 0x30;
+    case TUSB_GPIO_CONF:
+        return s->gpio_config;
+
+    case TUSB_DMA_CTRL_REV:
+        return 0x30;
+    case TUSB_DMA_REQ_CONF:
+        return s->dma_config;
+    case TUSB_EP0_CONF:
+        return s->ep0_config;
+    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
+        return s->tx_config[epnum];
+    case TUSB_DMA_EP_MAP:
+        return s->dma_map;
+    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
+        return s->rx_config[epnum];
+    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
+            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
+        return 0x00000000;     /* TODO */
+    case TUSB_WAIT_COUNT:
+        return 0x00;           /* TODO */
+
+    case TUSB_SCRATCH_PAD:
+        return s->scratch;
+
+    case TUSB_PROD_TEST_RESET:
+        return s->test_reset;
+
+    /* DIE IDs */
+    case TUSB_DIDR1_LO:
+        return 0xa9453c59;
+    case TUSB_DIDR1_HI:
+        return 0x54059adf;
+    }
+
+    printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
+    return 0;
+}
+
+static void tusb_async_writeb(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[0](s->musb, addr & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n",
+                        __FUNCTION__, (int) (addr & 0xfff));
+        return;
+    }
+}
+
+static void tusb_async_writeh(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[1](s->musb, addr & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n",
+                        __FUNCTION__, (int) (addr & 0xfff));
+        return;
+    }
+}
+
+static void tusb_async_writew(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    int offset = addr & 0xfff;
+    int epnum;
+
+    switch (offset) {
+    case TUSB_VLYNQ_CTRL:
+        break;
+
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[2](s->musb, offset & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    case TUSB_DEV_CONF:
+        s->dev_config = value;
+        s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
+        if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
+            hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
+        break;
+
+    case TUSB_PHY_OTG_CTRL_ENABLE:
+    case TUSB_PHY_OTG_CTRL:
+        return;                /* TODO */
+    case TUSB_DEV_OTG_TIMER:
+        s->otg_timer_val = value;
+        if (value & TUSB_DEV_OTG_TIMER_ENABLE)
+            qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
+                            muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
+                                     get_ticks_per_sec(), TUSB_DEVCLOCK));
+        else
+            qemu_del_timer(s->otg_timer);
+        break;
+
+    case TUSB_PRCM_CONF:
+        s->prcm_config = value;
+        break;
+    case TUSB_PRCM_MNGMT:
+        s->prcm_mngmt = value;
+        break;
+    case TUSB_PRCM_WAKEUP_CLEAR:
+        break;
+    case TUSB_PRCM_WAKEUP_MASK:
+        s->wkup_mask = value;
+        break;
+
+    case TUSB_PULLUP_1_CTRL:
+        s->pullup[0] = value;
+        break;
+    case TUSB_PULLUP_2_CTRL:
+        s->pullup[1] = value;
+        break;
+    case TUSB_INT_CTRL_CONF:
+        s->control_config = value;
+        tusb_intr_update(s);
+        break;
+
+    case TUSB_USBIP_INT_SET:
+        s->usbip_intr |= value;
+        tusb_usbip_intr_update(s);
+        break;
+    case TUSB_USBIP_INT_CLEAR:
+        s->usbip_intr &= ~value;
+        tusb_usbip_intr_update(s);
+        musb_core_intr_clear(s->musb, ~value);
+        break;
+    case TUSB_USBIP_INT_MASK:
+        s->usbip_mask = value;
+        tusb_usbip_intr_update(s);
+        break;
+
+    case TUSB_DMA_INT_SET:
+        s->dma_intr |= value;
+        tusb_dma_intr_update(s);
+        break;
+    case TUSB_DMA_INT_CLEAR:
+        s->dma_intr &= ~value;
+        tusb_dma_intr_update(s);
+        break;
+    case TUSB_DMA_INT_MASK:
+        s->dma_mask = value;
+        tusb_dma_intr_update(s);
+        break;
+
+    case TUSB_GPIO_INT_SET:
+        s->gpio_intr |= value;
+        tusb_gpio_intr_update(s);
+        break;
+    case TUSB_GPIO_INT_CLEAR:
+        s->gpio_intr &= ~value;
+        tusb_gpio_intr_update(s);
+        break;
+    case TUSB_GPIO_INT_MASK:
+        s->gpio_mask = value;
+        tusb_gpio_intr_update(s);
+        break;
+
+    case TUSB_INT_SRC_SET:
+        s->intr |= value;
+        tusb_intr_update(s);
+        break;
+    case TUSB_INT_SRC_CLEAR:
+        s->intr &= ~value;
+        tusb_intr_update(s);
+        break;
+    case TUSB_INT_MASK:
+        s->mask = value;
+        tusb_intr_update(s);
+        break;
+
+    case TUSB_GPIO_CONF:
+        s->gpio_config = value;
+        break;
+    case TUSB_DMA_REQ_CONF:
+        s->dma_config = value;
+        break;
+    case TUSB_EP0_CONF:
+        s->ep0_config = value & 0x1ff;
+        musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
+                        value & TUSB_EP0_CONFIG_DIR_TX);
+        break;
+    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
+        s->tx_config[epnum] = value;
+        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
+        break;
+    case TUSB_DMA_EP_MAP:
+        s->dma_map = value;
+        break;
+    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
+        s->rx_config[epnum] = value;
+        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
+        break;
+    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
+            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
+        return;                /* TODO */
+    case TUSB_WAIT_COUNT:
+        return;                /* TODO */
+
+    case TUSB_SCRATCH_PAD:
+        s->scratch = value;
+        break;
+
+    case TUSB_PROD_TEST_RESET:
+        s->test_reset = value;
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
+        return;
+    }
+}
+
+static const MemoryRegionOps tusb_async_ops = {
+    .old_mmio = {
+        .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
+        .write =  { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void tusb_otg_tick(void *opaque)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    s->otg_timer_val = 0;
+    s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
+    tusb_intr_update(s);
+}
+
+static void tusb_power_tick(void *opaque)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    if (s->power) {
+        s->intr_ok = ~0;
+        tusb_intr_update(s);
+    }
+}
+
+static void tusb_musb_core_intr(void *opaque, int source, int level)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    uint16_t otg_status = s->otg_status;
+
+    switch (source) {
+    case musb_set_vbus:
+        if (level)
+            otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
+        else
+            otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
+
+        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set?  */
+        /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set?  */
+        if (s->otg_status != otg_status) {
+            s->otg_status = otg_status;
+            s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
+            tusb_intr_update(s);
+        }
+        break;
+
+    case musb_set_session:
+        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set?  */
+        /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set?  */
+        if (level) {
+            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
+            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
+        } else {
+            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
+            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
+        }
+
+        /* XXX: some IRQ or anything?  */
+        break;
+
+    case musb_irq_tx:
+    case musb_irq_rx:
+        s->usbip_intr = musb_core_intr_get(s->musb);
+        /* Fall through.  */
+    default:
+        if (level)
+            s->intr |= 1 << source;
+        else
+            s->intr &= ~(1 << source);
+        tusb_intr_update(s);
+        break;
+    }
+}
+
+static void tusb6010_power(TUSBState *s, int on)
+{
+    if (!on) {
+        s->power = 0;
+    } else if (!s->power && on) {
+        s->power = 1;
+        /* Pull the interrupt down after TUSB6010 comes up.  */
+        s->intr_ok = 0;
+        tusb_intr_update(s);
+        qemu_mod_timer(s->pwr_timer,
+                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
+    }
+}
+
+static void tusb6010_irq(void *opaque, int source, int level)
+{
+    if (source) {
+        tusb_musb_core_intr(opaque, source - 1, level);
+    } else {
+        tusb6010_power(opaque, level);
+    }
+}
+
+static void tusb6010_reset(DeviceState *dev)
+{
+    TUSBState *s = FROM_SYSBUS(TUSBState, SYS_BUS_DEVICE(dev));
+    int i;
+
+    s->test_reset = TUSB_PROD_TEST_RESET_VAL;
+    s->host_mode = 0;
+    s->dev_config = 0;
+    s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
+    s->power = 0;
+    s->mask = 0xffffffff;
+    s->intr = 0x00000000;
+    s->otg_timer_val = 0;
+    s->scratch = 0;
+    s->prcm_config = 0;
+    s->prcm_mngmt = 0;
+    s->intr_ok = 0;
+    s->usbip_intr = 0;
+    s->usbip_mask = 0;
+    s->gpio_intr = 0;
+    s->gpio_mask = 0;
+    s->gpio_config = 0;
+    s->dma_intr = 0;
+    s->dma_mask = 0;
+    s->dma_map = 0;
+    s->dma_config = 0;
+    s->ep0_config = 0;
+    s->wkup_mask = 0;
+    s->pullup[0] = s->pullup[1] = 0;
+    s->control_config = 0;
+    for (i = 0; i < 15; i++) {
+        s->rx_config[i] = s->tx_config[i] = 0;
+    }
+    musb_reset(s->musb);
+}
+
+static int tusb6010_init(SysBusDevice *dev)
+{
+    TUSBState *s = FROM_SYSBUS(TUSBState, dev);
+    s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
+    s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
+    memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
+                          UINT32_MAX);
+    sysbus_init_mmio(dev, &s->iomem[0]);
+    sysbus_init_mmio(dev, &s->iomem[1]);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
+    s->musb = musb_init(&dev->qdev, 1);
+    return 0;
+}
+
+static void tusb6010_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tusb6010_init;
+    dc->reset = tusb6010_reset;
+}
+
+static const TypeInfo tusb6010_info = {
+    .name          = "tusb6010",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TUSBState),
+    .class_init    = tusb6010_class_init,
+};
+
+static void tusb6010_register_types(void)
+{
+    type_register_static(&tusb6010_info);
+}
+
+type_init(tusb6010_register_types)
diff --git a/hw/tsc210x.c b/hw/tsc210x.c
deleted file mode 100644 (file)
index e6c217c..0000000
+++ /dev/null
@@ -1,1293 +0,0 @@
-/*
- * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
- * TI TSC2301 (touchscreen/sensors/keypad).
- *
- * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"       /* For I2SCodec and uWireSlave */
-#include "hw/arm/devices.h"
-
-#define TSC_DATA_REGISTERS_PAGE                0x0
-#define TSC_CONTROL_REGISTERS_PAGE     0x1
-#define TSC_AUDIO_REGISTERS_PAGE       0x2
-
-#define TSC_VERBOSE
-
-#define TSC_CUT_RESOLUTION(value, p)   ((value) >> (16 - resolution[p]))
-
-typedef struct {
-    qemu_irq pint;
-    qemu_irq kbint;
-    qemu_irq davint;
-    QEMUTimer *timer;
-    QEMUSoundCard card;
-    uWireSlave chip;
-    I2SCodec codec;
-    uint8_t in_fifo[16384];
-    uint8_t out_fifo[16384];
-    uint16_t model;
-
-    int x, y;
-    int pressure;
-
-    int state, page, offset, irq;
-    uint16_t command, dav;
-
-    int busy;
-    int enabled;
-    int host_mode;
-    int function;
-    int nextfunction;
-    int precision;
-    int nextprecision;
-    int filter;
-    int pin_func;
-    int ref;
-    int timing;
-    int noise;
-
-    uint16_t audio_ctrl1;
-    uint16_t audio_ctrl2;
-    uint16_t audio_ctrl3;
-    uint16_t pll[3];
-    uint16_t volume;
-    int64_t volume_change;
-    int softstep;
-    uint16_t dac_power;
-    int64_t powerdown;
-    uint16_t filter_data[0x14];
-
-    const char *name;
-    SWVoiceIn *adc_voice[1];
-    SWVoiceOut *dac_voice[1];
-    int i2s_rx_rate;
-    int i2s_tx_rate;
-
-    int tr[8];
-
-    struct {
-        uint16_t down;
-        uint16_t mask;
-        int scan;
-        int debounce;
-        int mode;
-        int intr;
-    } kb;
-} TSC210xState;
-
-static const int resolution[4] = { 12, 8, 10, 12 };
-
-#define TSC_MODE_NO_SCAN       0x0
-#define TSC_MODE_XY_SCAN       0x1
-#define TSC_MODE_XYZ_SCAN      0x2
-#define TSC_MODE_X             0x3
-#define TSC_MODE_Y             0x4
-#define TSC_MODE_Z             0x5
-#define TSC_MODE_BAT1          0x6
-#define TSC_MODE_BAT2          0x7
-#define TSC_MODE_AUX           0x8
-#define TSC_MODE_AUX_SCAN      0x9
-#define TSC_MODE_TEMP1         0xa
-#define TSC_MODE_PORT_SCAN     0xb
-#define TSC_MODE_TEMP2         0xc
-#define TSC_MODE_XX_DRV                0xd
-#define TSC_MODE_YY_DRV                0xe
-#define TSC_MODE_YX_DRV                0xf
-
-static const uint16_t mode_regs[16] = {
-    0x0000,    /* No scan */
-    0x0600,    /* X, Y scan */
-    0x0780,    /* X, Y, Z scan */
-    0x0400,    /* X */
-    0x0200,    /* Y */
-    0x0180,    /* Z */
-    0x0040,    /* BAT1 */
-    0x0030,    /* BAT2 */
-    0x0010,    /* AUX */
-    0x0010,    /* AUX scan */
-    0x0004,    /* TEMP1 */
-    0x0070,    /* Port scan */
-    0x0002,    /* TEMP2 */
-    0x0000,    /* X+, X- drivers */
-    0x0000,    /* Y+, Y- drivers */
-    0x0000,    /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s)                 \
-    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s)                 \
-    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s)                        \
-    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s)                        \
-    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define BAT1_VAL                       0x8660
-#define BAT2_VAL                       0x0000
-#define AUX1_VAL                       0x35c0
-#define AUX2_VAL                       0xffff
-#define TEMP1_VAL                      0x8c70
-#define TEMP2_VAL                      0xa5b0
-
-#define TSC_POWEROFF_DELAY             50
-#define TSC_SOFTSTEP_DELAY             50
-
-static void tsc210x_reset(TSC210xState *s)
-{
-    s->state = 0;
-    s->pin_func = 2;
-    s->enabled = 0;
-    s->busy = 0;
-    s->nextfunction = 0;
-    s->ref = 0;
-    s->timing = 0;
-    s->irq = 0;
-    s->dav = 0;
-
-    s->audio_ctrl1 = 0x0000;
-    s->audio_ctrl2 = 0x4410;
-    s->audio_ctrl3 = 0x0000;
-    s->pll[0] = 0x1004;
-    s->pll[1] = 0x0000;
-    s->pll[2] = 0x1fff;
-    s->volume = 0xffff;
-    s->dac_power = 0x8540;
-    s->softstep = 1;
-    s->volume_change = 0;
-    s->powerdown = 0;
-    s->filter_data[0x00] = 0x6be3;
-    s->filter_data[0x01] = 0x9666;
-    s->filter_data[0x02] = 0x675d;
-    s->filter_data[0x03] = 0x6be3;
-    s->filter_data[0x04] = 0x9666;
-    s->filter_data[0x05] = 0x675d;
-    s->filter_data[0x06] = 0x7d83;
-    s->filter_data[0x07] = 0x84ee;
-    s->filter_data[0x08] = 0x7d83;
-    s->filter_data[0x09] = 0x84ee;
-    s->filter_data[0x0a] = 0x6be3;
-    s->filter_data[0x0b] = 0x9666;
-    s->filter_data[0x0c] = 0x675d;
-    s->filter_data[0x0d] = 0x6be3;
-    s->filter_data[0x0e] = 0x9666;
-    s->filter_data[0x0f] = 0x675d;
-    s->filter_data[0x10] = 0x7d83;
-    s->filter_data[0x11] = 0x84ee;
-    s->filter_data[0x12] = 0x7d83;
-    s->filter_data[0x13] = 0x84ee;
-
-    s->i2s_tx_rate = 0;
-    s->i2s_rx_rate = 0;
-
-    s->kb.scan = 1;
-    s->kb.debounce = 0;
-    s->kb.mask = 0x0000;
-    s->kb.mode = 3;
-    s->kb.intr = 0;
-
-    qemu_set_irq(s->pint, !s->irq);
-    qemu_set_irq(s->davint, !s->dav);
-    qemu_irq_raise(s->kbint);
-}
-
-typedef struct {
-    int rate;
-    int dsor;
-    int fsref;
-} TSC210xRateInfo;
-
-/*  { rate,  dsor,  fsref } */
-static const TSC210xRateInfo tsc2101_rates[] = {
-    /* Fsref / 6.0 */
-    { 7350,    7,      1 },
-    { 8000,    7,      0 },
-    /* Fsref / 5.5 */
-    { 8018,    6,      1 },
-    { 8727,    6,      0 },
-    /* Fsref / 5.0 */
-    { 8820,    5,      1 },
-    { 9600,    5,      0 },
-    /* Fsref / 4.0 */
-    { 11025,   4,      1 },
-    { 12000,   4,      0 },
-    /* Fsref / 3.0 */
-    { 14700,   3,      1 },
-    { 16000,   3,      0 },
-    /* Fsref / 2.0 */
-    { 22050,   2,      1 },
-    { 24000,   2,      0 },
-    /* Fsref / 1.5 */
-    { 29400,   1,      1 },
-    { 32000,   1,      0 },
-    /* Fsref */
-    { 44100,   0,      1 },
-    { 48000,   0,      0 },
-
-    { 0,       0,      0 },
-};
-
-/*  { rate,   dsor, fsref }    */
-static const TSC210xRateInfo tsc2102_rates[] = {
-    /* Fsref / 6.0 */
-    { 7350,    63,     1 },
-    { 8000,    63,     0 },
-    /* Fsref / 6.0 */
-    { 7350,    54,     1 },
-    { 8000,    54,     0 },
-    /* Fsref / 5.0 */
-    { 8820,    45,     1 },
-    { 9600,    45,     0 },
-    /* Fsref / 4.0 */
-    { 11025,   36,     1 },
-    { 12000,   36,     0 },
-    /* Fsref / 3.0 */
-    { 14700,   27,     1 },
-    { 16000,   27,     0 },
-    /* Fsref / 2.0 */
-    { 22050,   18,     1 },
-    { 24000,   18,     0 },
-    /* Fsref / 1.5 */
-    { 29400,   9,      1 },
-    { 32000,   9,      0 },
-    /* Fsref */
-    { 44100,   0,      1 },
-    { 48000,   0,      0 },
-
-    { 0,       0,      0 },
-};
-
-static inline void tsc210x_out_flush(TSC210xState *s, int len)
-{
-    uint8_t *data = s->codec.out.fifo + s->codec.out.start;
-    uint8_t *end = data + len;
-
-    while (data < end)
-        data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
-
-    s->codec.out.len -= len;
-    if (s->codec.out.len)
-        memmove(s->codec.out.fifo, end, s->codec.out.len);
-    s->codec.out.start = 0;
-}
-
-static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
-{
-    if (s->codec.out.len >= free_b) {
-        tsc210x_out_flush(s, free_b);
-        return;
-    }
-
-    s->codec.out.size = MIN(free_b, 16384);
-    qemu_irq_raise(s->codec.tx_start);
-}
-
-static void tsc2102_audio_rate_update(TSC210xState *s)
-{
-    const TSC210xRateInfo *rate;
-
-    s->codec.tx_rate = 0;
-    s->codec.rx_rate = 0;
-    if (s->dac_power & (1 << 15))                              /* PWDNC */
-        return;
-
-    for (rate = tsc2102_rates; rate->rate; rate ++)
-        if (rate->dsor == (s->audio_ctrl1 & 0x3f) &&           /* DACFS */
-                        rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
-            break;
-    if (!rate->rate) {
-        printf("%s: unknown sampling rate configured\n", __FUNCTION__);
-        return;
-    }
-
-    s->codec.tx_rate = rate->rate;
-}
-
-static void tsc2102_audio_output_update(TSC210xState *s)
-{
-    int enable;
-    struct audsettings fmt;
-
-    if (s->dac_voice[0]) {
-        tsc210x_out_flush(s, s->codec.out.len);
-        s->codec.out.size = 0;
-        AUD_set_active_out(s->dac_voice[0], 0);
-        AUD_close_out(&s->card, s->dac_voice[0]);
-        s->dac_voice[0] = NULL;
-    }
-    s->codec.cts = 0;
-
-    enable =
-            (~s->dac_power & (1 << 15)) &&                     /* PWDNC */
-            (~s->dac_power & (1 << 10));                       /* DAPWDN */
-    if (!enable || !s->codec.tx_rate)
-        return;
-
-    /* Force our own sampling rate even in slave DAC mode */
-    fmt.endianness = 0;
-    fmt.nchannels = 2;
-    fmt.freq = s->codec.tx_rate;
-    fmt.fmt = AUD_FMT_S16;
-
-    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
-                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
-    if (s->dac_voice[0]) {
-        s->codec.cts = 1;
-        AUD_set_active_out(s->dac_voice[0], 1);
-    }
-}
-
-static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
-{
-    switch (reg) {
-    case 0x00: /* X */
-        s->dav &= 0xfbff;
-        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
-                (s->noise & 3);
-
-    case 0x01: /* Y */
-        s->noise ++;
-        s->dav &= 0xfdff;
-        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
-                (s->noise & 3);
-
-    case 0x02: /* Z1 */
-        s->dav &= 0xfeff;
-        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
-                (s->noise & 3);
-
-    case 0x03: /* Z2 */
-        s->dav &= 0xff7f;
-        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
-                (s->noise & 3);
-
-    case 0x04: /* KPData */
-        if ((s->model & 0xff00) == 0x2300) {
-            if (s->kb.intr && (s->kb.mode & 2)) {
-                s->kb.intr = 0;
-                qemu_irq_raise(s->kbint);
-            }
-            return s->kb.down;
-        }
-
-        return 0xffff;
-
-    case 0x05: /* BAT1 */
-        s->dav &= 0xffbf;
-        return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
-                (s->noise & 6);
-
-    case 0x06: /* BAT2 */
-        s->dav &= 0xffdf;
-        return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
-
-    case 0x07: /* AUX1 */
-        s->dav &= 0xffef;
-        return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
-
-    case 0x08: /* AUX2 */
-        s->dav &= 0xfff7;
-        return 0xffff;
-
-    case 0x09: /* TEMP1 */
-        s->dav &= 0xfffb;
-        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
-                (s->noise & 5);
-
-    case 0x0a: /* TEMP2 */
-        s->dav &= 0xfffd;
-        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
-                (s->noise & 3);
-
-    case 0x0b: /* DAC */
-        s->dav &= 0xfffe;
-        return 0xffff;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_data_register_read: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-        return 0xffff;
-    }
-}
-
-static uint16_t tsc2102_control_register_read(
-                TSC210xState *s, int reg)
-{
-    switch (reg) {
-    case 0x00: /* TSC ADC */
-        return (s->pressure << 15) | ((!s->busy) << 14) |
-                (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; 
-
-    case 0x01: /* Status / Keypad Control */
-        if ((s->model & 0xff00) == 0x2100)
-            return (s->pin_func << 14) | ((!s->enabled) << 13) |
-                    (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
-        else
-            return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
-                    (s->kb.debounce << 11);
-
-    case 0x02: /* DAC Control */
-        if ((s->model & 0xff00) == 0x2300)
-            return s->dac_power & 0x8000;
-        else
-            goto bad_reg;
-
-    case 0x03: /* Reference */
-        return s->ref;
-
-    case 0x04: /* Reset */
-        return 0xffff;
-
-    case 0x05: /* Configuration */
-        return s->timing;
-
-    case 0x06: /* Secondary configuration */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
-
-    case 0x10: /* Keypad Mask */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        return s->kb.mask;
-
-    default:
-    bad_reg:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_control_register_read: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-        return 0xffff;
-    }
-}
-
-static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
-{
-    int l_ch, r_ch;
-    uint16_t val;
-
-    switch (reg) {
-    case 0x00: /* Audio Control 1 */
-        return s->audio_ctrl1;
-
-    case 0x01:
-        return 0xff00;
-
-    case 0x02: /* DAC Volume Control */
-        return s->volume;
-
-    case 0x03:
-        return 0x8b00;
-
-    case 0x04: /* Audio Control 2 */
-        l_ch = 1;
-        r_ch = 1;
-        if (s->softstep && !(s->dac_power & (1 << 10))) {
-            l_ch = (qemu_get_clock_ns(vm_clock) >
-                            s->volume_change + TSC_SOFTSTEP_DELAY);
-            r_ch = (qemu_get_clock_ns(vm_clock) >
-                            s->volume_change + TSC_SOFTSTEP_DELAY);
-        }
-
-        return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
-
-    case 0x05: /* Stereo DAC Power Control */
-        return 0x2aa0 | s->dac_power |
-                (((s->dac_power & (1 << 10)) &&
-                  (qemu_get_clock_ns(vm_clock) >
-                   s->powerdown + TSC_POWEROFF_DELAY)) << 6);
-
-    case 0x06: /* Audio Control 3 */
-        val = s->audio_ctrl3 | 0x0001;
-        s->audio_ctrl3 &= 0xff3f;
-        return val;
-
-    case 0x07: /* LCH_BASS_BOOST_N0 */
-    case 0x08: /* LCH_BASS_BOOST_N1 */
-    case 0x09: /* LCH_BASS_BOOST_N2 */
-    case 0x0a: /* LCH_BASS_BOOST_N3 */
-    case 0x0b: /* LCH_BASS_BOOST_N4 */
-    case 0x0c: /* LCH_BASS_BOOST_N5 */
-    case 0x0d: /* LCH_BASS_BOOST_D1 */
-    case 0x0e: /* LCH_BASS_BOOST_D2 */
-    case 0x0f: /* LCH_BASS_BOOST_D4 */
-    case 0x10: /* LCH_BASS_BOOST_D5 */
-    case 0x11: /* RCH_BASS_BOOST_N0 */
-    case 0x12: /* RCH_BASS_BOOST_N1 */
-    case 0x13: /* RCH_BASS_BOOST_N2 */
-    case 0x14: /* RCH_BASS_BOOST_N3 */
-    case 0x15: /* RCH_BASS_BOOST_N4 */
-    case 0x16: /* RCH_BASS_BOOST_N5 */
-    case 0x17: /* RCH_BASS_BOOST_D1 */
-    case 0x18: /* RCH_BASS_BOOST_D2 */
-    case 0x19: /* RCH_BASS_BOOST_D4 */
-    case 0x1a: /* RCH_BASS_BOOST_D5 */
-        return s->filter_data[reg - 0x07];
-
-    case 0x1b: /* PLL Programmability 1 */
-        return s->pll[0];
-
-    case 0x1c: /* PLL Programmability 2 */
-        return s->pll[1];
-
-    case 0x1d: /* Audio Control 4 */
-        return (!s->softstep) << 14;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_audio_register_read: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-        return 0xffff;
-    }
-}
-
-static void tsc2102_data_register_write(
-                TSC210xState *s, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* X */
-    case 0x01: /* Y */
-    case 0x02: /* Z1 */
-    case 0x03: /* Z2 */
-    case 0x05: /* BAT1 */
-    case 0x06: /* BAT2 */
-    case 0x07: /* AUX1 */
-    case 0x08: /* AUX2 */
-    case 0x09: /* TEMP1 */
-    case 0x0a: /* TEMP2 */
-        return;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_data_register_write: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-    }
-}
-
-static void tsc2102_control_register_write(
-                TSC210xState *s, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* TSC ADC */
-        s->host_mode = value >> 15;
-        s->enabled = !(value & 0x4000);
-        if (s->busy && !s->enabled)
-            qemu_del_timer(s->timer);
-        s->busy &= s->enabled;
-        s->nextfunction = (value >> 10) & 0xf;
-        s->nextprecision = (value >> 8) & 3;
-        s->filter = value & 0xff;
-        return;
-
-    case 0x01: /* Status / Keypad Control */
-        if ((s->model & 0xff00) == 0x2100)
-            s->pin_func = value >> 14;
-       else {
-            s->kb.scan = (value >> 14) & 1;
-            s->kb.debounce = (value >> 11) & 7;
-            if (s->kb.intr && s->kb.scan) {
-                s->kb.intr = 0;
-                qemu_irq_raise(s->kbint);
-            }
-        }
-        return;
-
-    case 0x02: /* DAC Control */
-        if ((s->model & 0xff00) == 0x2300) {
-            s->dac_power &= 0x7fff;
-            s->dac_power |= 0x8000 & value;
-        } else
-            goto bad_reg;
-        break;
-
-    case 0x03: /* Reference */
-        s->ref = value & 0x1f;
-        return;
-
-    case 0x04: /* Reset */
-        if (value == 0xbb00) {
-            if (s->busy)
-                qemu_del_timer(s->timer);
-            tsc210x_reset(s);
-#ifdef TSC_VERBOSE
-        } else {
-            fprintf(stderr, "tsc2102_control_register_write: "
-                            "wrong value written into RESET\n");
-#endif
-        }
-        return;
-
-    case 0x05: /* Configuration */
-        s->timing = value & 0x3f;
-#ifdef TSC_VERBOSE
-        if (value & ~0x3f)
-            fprintf(stderr, "tsc2102_control_register_write: "
-                            "wrong value written into CONFIG\n");
-#endif
-        return;
-
-    case 0x06: /* Secondary configuration */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        s->kb.mode = value >> 14;
-        s->pll[2] = value & 0x3ffff;
-        return;
-
-    case 0x10: /* Keypad Mask */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        s->kb.mask = value;
-        return;
-
-    default:
-    bad_reg:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_control_register_write: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-    }
-}
-
-static void tsc2102_audio_register_write(
-                TSC210xState *s, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* Audio Control 1 */
-        s->audio_ctrl1 = value & 0x0f3f;
-#ifdef TSC_VERBOSE
-        if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 1\n");
-#endif
-        tsc2102_audio_rate_update(s);
-        tsc2102_audio_output_update(s);
-        return;
-
-    case 0x01:
-#ifdef TSC_VERBOSE
-        if (value != 0xff00)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into reg 0x01\n");
-#endif
-        return;
-
-    case 0x02: /* DAC Volume Control */
-        s->volume = value;
-        s->volume_change = qemu_get_clock_ns(vm_clock);
-        return;
-
-    case 0x03:
-#ifdef TSC_VERBOSE
-        if (value != 0x8b00)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into reg 0x03\n");
-#endif
-        return;
-
-    case 0x04: /* Audio Control 2 */
-        s->audio_ctrl2 = value & 0xf7f2;
-#ifdef TSC_VERBOSE
-        if (value & ~0xf7fd)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 2\n");
-#endif
-        return;
-
-    case 0x05: /* Stereo DAC Power Control */
-        if ((value & ~s->dac_power) & (1 << 10))
-            s->powerdown = qemu_get_clock_ns(vm_clock);
-
-        s->dac_power = value & 0x9543;
-#ifdef TSC_VERBOSE
-        if ((value & ~0x9543) != 0x2aa0)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Power\n");
-#endif
-        tsc2102_audio_rate_update(s);
-        tsc2102_audio_output_update(s);
-        return;
-
-    case 0x06: /* Audio Control 3 */
-        s->audio_ctrl3 &= 0x00c0;
-        s->audio_ctrl3 |= value & 0xf800;
-#ifdef TSC_VERBOSE
-        if (value & ~0xf8c7)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 3\n");
-#endif
-        tsc2102_audio_output_update(s);
-        return;
-
-    case 0x07: /* LCH_BASS_BOOST_N0 */
-    case 0x08: /* LCH_BASS_BOOST_N1 */
-    case 0x09: /* LCH_BASS_BOOST_N2 */
-    case 0x0a: /* LCH_BASS_BOOST_N3 */
-    case 0x0b: /* LCH_BASS_BOOST_N4 */
-    case 0x0c: /* LCH_BASS_BOOST_N5 */
-    case 0x0d: /* LCH_BASS_BOOST_D1 */
-    case 0x0e: /* LCH_BASS_BOOST_D2 */
-    case 0x0f: /* LCH_BASS_BOOST_D4 */
-    case 0x10: /* LCH_BASS_BOOST_D5 */
-    case 0x11: /* RCH_BASS_BOOST_N0 */
-    case 0x12: /* RCH_BASS_BOOST_N1 */
-    case 0x13: /* RCH_BASS_BOOST_N2 */
-    case 0x14: /* RCH_BASS_BOOST_N3 */
-    case 0x15: /* RCH_BASS_BOOST_N4 */
-    case 0x16: /* RCH_BASS_BOOST_N5 */
-    case 0x17: /* RCH_BASS_BOOST_D1 */
-    case 0x18: /* RCH_BASS_BOOST_D2 */
-    case 0x19: /* RCH_BASS_BOOST_D4 */
-    case 0x1a: /* RCH_BASS_BOOST_D5 */
-        s->filter_data[reg - 0x07] = value;
-        return;
-
-    case 0x1b: /* PLL Programmability 1 */
-        s->pll[0] = value & 0xfffc;
-#ifdef TSC_VERBOSE
-        if (value & ~0xfffc)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into PLL 1\n");
-#endif
-        return;
-
-    case 0x1c: /* PLL Programmability 2 */
-        s->pll[1] = value & 0xfffc;
-#ifdef TSC_VERBOSE
-        if (value & ~0xfffc)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into PLL 2\n");
-#endif
-        return;
-
-    case 0x1d: /* Audio Control 4 */
-        s->softstep = !(value & 0x4000);
-#ifdef TSC_VERBOSE
-        if (value & ~0x4000)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 4\n");
-#endif
-        return;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_audio_register_write: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-    }
-}
-
-/* This handles most of the chip logic.  */
-static void tsc210x_pin_update(TSC210xState *s)
-{
-    int64_t expires;
-    int pin_state;
-
-    switch (s->pin_func) {
-    case 0:
-        pin_state = s->pressure;
-        break;
-    case 1:
-        pin_state = !!s->dav;
-        break;
-    case 2:
-    default:
-        pin_state = s->pressure && !s->dav;
-    }
-
-    if (!s->enabled)
-        pin_state = 0;
-
-    if (pin_state != s->irq) {
-        s->irq = pin_state;
-        qemu_set_irq(s->pint, !s->irq);
-    }
-
-    switch (s->nextfunction) {
-    case TSC_MODE_XY_SCAN:
-    case TSC_MODE_XYZ_SCAN:
-        if (!s->pressure)
-            return;
-        break;
-
-    case TSC_MODE_X:
-    case TSC_MODE_Y:
-    case TSC_MODE_Z:
-        if (!s->pressure)
-            return;
-        /* Fall through */
-    case TSC_MODE_BAT1:
-    case TSC_MODE_BAT2:
-    case TSC_MODE_AUX:
-    case TSC_MODE_TEMP1:
-    case TSC_MODE_TEMP2:
-        if (s->dav)
-            s->enabled = 0;
-        break;
-
-    case TSC_MODE_AUX_SCAN:
-    case TSC_MODE_PORT_SCAN:
-        break;
-
-    case TSC_MODE_NO_SCAN:
-    case TSC_MODE_XX_DRV:
-    case TSC_MODE_YY_DRV:
-    case TSC_MODE_YX_DRV:
-    default:
-        return;
-    }
-
-    if (!s->enabled || s->busy || s->dav)
-        return;
-
-    s->busy = 1;
-    s->precision = s->nextprecision;
-    s->function = s->nextfunction;
-    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10);
-    qemu_mod_timer(s->timer, expires);
-}
-
-static uint16_t tsc210x_read(TSC210xState *s)
-{
-    uint16_t ret = 0x0000;
-
-    if (!s->command)
-        fprintf(stderr, "tsc210x_read: SPI underrun!\n");
-
-    switch (s->page) {
-    case TSC_DATA_REGISTERS_PAGE:
-        ret = tsc2102_data_register_read(s, s->offset);
-        if (!s->dav)
-            qemu_irq_raise(s->davint);
-        break;
-    case TSC_CONTROL_REGISTERS_PAGE:
-        ret = tsc2102_control_register_read(s, s->offset);
-        break;
-    case TSC_AUDIO_REGISTERS_PAGE:
-        ret = tsc2102_audio_register_read(s, s->offset);
-        break;
-    default:
-        hw_error("tsc210x_read: wrong memory page\n");
-    }
-
-    tsc210x_pin_update(s);
-
-    /* Allow sequential reads.  */
-    s->offset ++;
-    s->state = 0;
-    return ret;
-}
-
-static void tsc210x_write(TSC210xState *s, uint16_t value)
-{
-    /*
-     * This is a two-state state machine for reading
-     * command and data every second time.
-     */
-    if (!s->state) {
-        s->command = value >> 15;
-        s->page = (value >> 11) & 0x0f;
-        s->offset = (value >> 5) & 0x3f;
-        s->state = 1;
-    } else {
-        if (s->command)
-            fprintf(stderr, "tsc210x_write: SPI overrun!\n");
-        else
-            switch (s->page) {
-            case TSC_DATA_REGISTERS_PAGE:
-                tsc2102_data_register_write(s, s->offset, value);
-                break;
-            case TSC_CONTROL_REGISTERS_PAGE:
-                tsc2102_control_register_write(s, s->offset, value);
-                break;
-            case TSC_AUDIO_REGISTERS_PAGE:
-                tsc2102_audio_register_write(s, s->offset, value);
-                break;
-            default:
-                hw_error("tsc210x_write: wrong memory page\n");
-            }
-
-        tsc210x_pin_update(s);
-        s->state = 0;
-    }
-}
-
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
-{
-    TSC210xState *s = opaque;
-    uint32_t ret = 0;
-
-    if (len != 16)
-        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
-
-    /* TODO: sequential reads etc - how do we make sure the host doesn't
-     * unintentionally read out a conversion result from a register while
-     * transmitting the command word of the next command?  */
-    if (!value || (s->state && s->command))
-        ret = tsc210x_read(s);
-    if (value || (s->state && !s->command))
-        tsc210x_write(s, value);
-
-    return ret;
-}
-
-static void tsc210x_timer_tick(void *opaque)
-{
-    TSC210xState *s = opaque;
-
-    /* Timer ticked -- a set of conversions has been finished.  */
-
-    if (!s->busy)
-        return;
-
-    s->busy = 0;
-    s->dav |= mode_regs[s->function];
-    tsc210x_pin_update(s);
-    qemu_irq_lower(s->davint);
-}
-
-static void tsc210x_touchscreen_event(void *opaque,
-                int x, int y, int z, int buttons_state)
-{
-    TSC210xState *s = opaque;
-    int p = s->pressure;
-
-    if (buttons_state) {
-        s->x = x;
-        s->y = y;
-    }
-    s->pressure = !!buttons_state;
-
-    /*
-     * Note: We would get better responsiveness in the guest by
-     * signaling TS events immediately, but for now we simulate
-     * the first conversion delay for sake of correctness.
-     */
-    if (p != s->pressure)
-        tsc210x_pin_update(s);
-}
-
-static void tsc210x_i2s_swallow(TSC210xState *s)
-{
-    if (s->dac_voice[0])
-        tsc210x_out_flush(s, s->codec.out.len);
-    else
-        s->codec.out.len = 0;
-}
-
-static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
-{
-    s->i2s_tx_rate = out;
-    s->i2s_rx_rate = in;
-}
-
-static void tsc210x_save(QEMUFile *f, void *opaque)
-{
-    TSC210xState *s = (TSC210xState *) opaque;
-    int64_t now = qemu_get_clock_ns(vm_clock);
-    int i;
-
-    qemu_put_be16(f, s->x);
-    qemu_put_be16(f, s->y);
-    qemu_put_byte(f, s->pressure);
-
-    qemu_put_byte(f, s->state);
-    qemu_put_byte(f, s->page);
-    qemu_put_byte(f, s->offset);
-    qemu_put_byte(f, s->command);
-
-    qemu_put_byte(f, s->irq);
-    qemu_put_be16s(f, &s->dav);
-
-    qemu_put_timer(f, s->timer);
-    qemu_put_byte(f, s->enabled);
-    qemu_put_byte(f, s->host_mode);
-    qemu_put_byte(f, s->function);
-    qemu_put_byte(f, s->nextfunction);
-    qemu_put_byte(f, s->precision);
-    qemu_put_byte(f, s->nextprecision);
-    qemu_put_byte(f, s->filter);
-    qemu_put_byte(f, s->pin_func);
-    qemu_put_byte(f, s->ref);
-    qemu_put_byte(f, s->timing);
-    qemu_put_be32(f, s->noise);
-
-    qemu_put_be16s(f, &s->audio_ctrl1);
-    qemu_put_be16s(f, &s->audio_ctrl2);
-    qemu_put_be16s(f, &s->audio_ctrl3);
-    qemu_put_be16s(f, &s->pll[0]);
-    qemu_put_be16s(f, &s->pll[1]);
-    qemu_put_be16s(f, &s->volume);
-    qemu_put_sbe64(f, (s->volume_change - now));
-    qemu_put_sbe64(f, (s->powerdown - now));
-    qemu_put_byte(f, s->softstep);
-    qemu_put_be16s(f, &s->dac_power);
-
-    for (i = 0; i < 0x14; i ++)
-        qemu_put_be16s(f, &s->filter_data[i]);
-}
-
-static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
-{
-    TSC210xState *s = (TSC210xState *) opaque;
-    int64_t now = qemu_get_clock_ns(vm_clock);
-    int i;
-
-    s->x = qemu_get_be16(f);
-    s->y = qemu_get_be16(f);
-    s->pressure = qemu_get_byte(f);
-
-    s->state = qemu_get_byte(f);
-    s->page = qemu_get_byte(f);
-    s->offset = qemu_get_byte(f);
-    s->command = qemu_get_byte(f);
-
-    s->irq = qemu_get_byte(f);
-    qemu_get_be16s(f, &s->dav);
-
-    qemu_get_timer(f, s->timer);
-    s->enabled = qemu_get_byte(f);
-    s->host_mode = qemu_get_byte(f);
-    s->function = qemu_get_byte(f);
-    s->nextfunction = qemu_get_byte(f);
-    s->precision = qemu_get_byte(f);
-    s->nextprecision = qemu_get_byte(f);
-    s->filter = qemu_get_byte(f);
-    s->pin_func = qemu_get_byte(f);
-    s->ref = qemu_get_byte(f);
-    s->timing = qemu_get_byte(f);
-    s->noise = qemu_get_be32(f);
-
-    qemu_get_be16s(f, &s->audio_ctrl1);
-    qemu_get_be16s(f, &s->audio_ctrl2);
-    qemu_get_be16s(f, &s->audio_ctrl3);
-    qemu_get_be16s(f, &s->pll[0]);
-    qemu_get_be16s(f, &s->pll[1]);
-    qemu_get_be16s(f, &s->volume);
-    s->volume_change = qemu_get_sbe64(f) + now;
-    s->powerdown = qemu_get_sbe64(f) + now;
-    s->softstep = qemu_get_byte(f);
-    qemu_get_be16s(f, &s->dac_power);
-
-    for (i = 0; i < 0x14; i ++)
-        qemu_get_be16s(f, &s->filter_data[i]);
-
-    s->busy = qemu_timer_pending(s->timer);
-    qemu_set_irq(s->pint, !s->irq);
-    qemu_set_irq(s->davint, !s->dav);
-
-    return 0;
-}
-
-uWireSlave *tsc2102_init(qemu_irq pint)
-{
-    TSC210xState *s;
-
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
-    s->x = 160;
-    s->y = 160;
-    s->pressure = 0;
-    s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
-    s->pint = pint;
-    s->model = 0x2102;
-    s->name = "tsc2102";
-
-    s->tr[0] = 0;
-    s->tr[1] = 1;
-    s->tr[2] = 1;
-    s->tr[3] = 0;
-    s->tr[4] = 1;
-    s->tr[5] = 0;
-    s->tr[6] = 1;
-    s->tr[7] = 0;
-
-    s->chip.opaque = s;
-    s->chip.send = (void *) tsc210x_write;
-    s->chip.receive = (void *) tsc210x_read;
-
-    s->codec.opaque = s;
-    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
-    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
-    s->codec.in.fifo = s->in_fifo;
-    s->codec.out.fifo = s->out_fifo;
-
-    tsc210x_reset(s);
-
-    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
-                    "QEMU TSC2102-driven Touchscreen");
-
-    AUD_register_card(s->name, &s->card);
-
-    qemu_register_reset((void *) tsc210x_reset, s);
-    register_savevm(NULL, s->name, -1, 0,
-                    tsc210x_save, tsc210x_load, s);
-
-    return &s->chip;
-}
-
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
-{
-    TSC210xState *s;
-
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
-    s->x = 400;
-    s->y = 240;
-    s->pressure = 0;
-    s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
-    s->pint = penirq;
-    s->kbint = kbirq;
-    s->davint = dav;
-    s->model = 0x2301;
-    s->name = "tsc2301";
-
-    s->tr[0] = 0;
-    s->tr[1] = 1;
-    s->tr[2] = 1;
-    s->tr[3] = 0;
-    s->tr[4] = 1;
-    s->tr[5] = 0;
-    s->tr[6] = 1;
-    s->tr[7] = 0;
-
-    s->chip.opaque = s;
-    s->chip.send = (void *) tsc210x_write;
-    s->chip.receive = (void *) tsc210x_read;
-
-    s->codec.opaque = s;
-    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
-    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
-    s->codec.in.fifo = s->in_fifo;
-    s->codec.out.fifo = s->out_fifo;
-
-    tsc210x_reset(s);
-
-    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
-                    "QEMU TSC2301-driven Touchscreen");
-
-    AUD_register_card(s->name, &s->card);
-
-    qemu_register_reset((void *) tsc210x_reset, s);
-    register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
-
-    return &s->chip;
-}
-
-I2SCodec *tsc210x_codec(uWireSlave *chip)
-{
-    TSC210xState *s = (TSC210xState *) chip->opaque;
-
-    return &s->codec;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen.  Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc210x_set_transform(uWireSlave *chip,
-                MouseTransformInfo *info)
-{
-    TSC210xState *s = (TSC210xState *) chip->opaque;
-#if 0
-    int64_t ltr[8];
-
-    ltr[0] = (int64_t) info->a[1] * info->y;
-    ltr[1] = (int64_t) info->a[4] * info->x;
-    ltr[2] = (int64_t) info->a[1] * info->a[3] -
-            (int64_t) info->a[4] * info->a[0];
-    ltr[3] = (int64_t) info->a[2] * info->a[4] -
-            (int64_t) info->a[5] * info->a[1];
-    ltr[4] = (int64_t) info->a[0] * info->y;
-    ltr[5] = (int64_t) info->a[3] * info->x;
-    ltr[6] = (int64_t) info->a[4] * info->a[0] -
-            (int64_t) info->a[1] * info->a[3];
-    ltr[7] = (int64_t) info->a[2] * info->a[3] -
-            (int64_t) info->a[5] * info->a[0];
-
-    /* Avoid integer overflow */
-    s->tr[0] = ltr[0] >> 11;
-    s->tr[1] = ltr[1] >> 11;
-    s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
-    s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
-    s->tr[4] = ltr[4] >> 11;
-    s->tr[5] = ltr[5] >> 11;
-    s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
-    s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
-#else
-
-    /* This version assumes touchscreen X & Y axis are parallel or
-     * perpendicular to LCD's  X & Y axis in some way.  */
-    if (abs(info->a[0]) > abs(info->a[1])) {
-        s->tr[0] = 0;
-        s->tr[1] = -info->a[6] * info->x;
-        s->tr[2] = info->a[0];
-        s->tr[3] = -info->a[2] / info->a[0];
-        s->tr[4] = info->a[6] * info->y;
-        s->tr[5] = 0;
-        s->tr[6] = info->a[4];
-        s->tr[7] = -info->a[5] / info->a[4];
-    } else {
-        s->tr[0] = info->a[6] * info->y;
-        s->tr[1] = 0;
-        s->tr[2] = info->a[1];
-        s->tr[3] = -info->a[2] / info->a[1];
-        s->tr[4] = 0;
-        s->tr[5] = -info->a[6] * info->x;
-        s->tr[6] = info->a[3];
-        s->tr[7] = -info->a[5] / info->a[3];
-    }
-
-    s->tr[0] >>= 11;
-    s->tr[1] >>= 11;
-    s->tr[3] <<= 4;
-    s->tr[4] >>= 11;
-    s->tr[5] >>= 11;
-    s->tr[7] <<= 4;
-#endif
-}
-
-void tsc210x_key_event(uWireSlave *chip, int key, int down)
-{
-    TSC210xState *s = (TSC210xState *) chip->opaque;
-
-    if (down)
-        s->kb.down |= 1 << key;
-    else
-        s->kb.down &= ~(1 << key);
-
-    if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
-        s->kb.intr = 1;
-        qemu_irq_lower(s->kbint);
-    } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
-                    !(s->kb.mode & 1)) {
-        s->kb.intr = 0;
-        qemu_irq_raise(s->kbint);
-    }
-}
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
deleted file mode 100644 (file)
index 533938a..0000000
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * Texas Instruments TUSB6010 emulation.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/arm/omap.h"
-#include "hw/irq.h"
-#include "hw/arm/devices.h"
-#include "hw/sysbus.h"
-
-typedef struct TUSBState {
-    SysBusDevice busdev;
-    MemoryRegion iomem[2];
-    qemu_irq irq;
-    MUSBState *musb;
-    QEMUTimer *otg_timer;
-    QEMUTimer *pwr_timer;
-
-    int power;
-    uint32_t scratch;
-    uint16_t test_reset;
-    uint32_t prcm_config;
-    uint32_t prcm_mngmt;
-    uint16_t otg_status;
-    uint32_t dev_config;
-    int host_mode;
-    uint32_t intr;
-    uint32_t intr_ok;
-    uint32_t mask;
-    uint32_t usbip_intr;
-    uint32_t usbip_mask;
-    uint32_t gpio_intr;
-    uint32_t gpio_mask;
-    uint32_t gpio_config;
-    uint32_t dma_intr;
-    uint32_t dma_mask;
-    uint32_t dma_map;
-    uint32_t dma_config;
-    uint32_t ep0_config;
-    uint32_t rx_config[15];
-    uint32_t tx_config[15];
-    uint32_t wkup_mask;
-    uint32_t pullup[2];
-    uint32_t control_config;
-    uint32_t otg_timer_val;
-} TUSBState;
-
-#define TUSB_DEVCLOCK                  60000000        /* 60 MHz */
-
-#define TUSB_VLYNQ_CTRL                        0x004
-
-/* Mentor Graphics OTG core registers.  */
-#define TUSB_BASE_OFFSET               0x400
-
-/* FIFO registers, 32-bit.  */
-#define TUSB_FIFO_BASE                 0x600
-
-/* Device System & Control registers, 32-bit.  */
-#define TUSB_SYS_REG_BASE              0x800
-
-#define TUSB_DEV_CONF                  (TUSB_SYS_REG_BASE + 0x000)
-#define        TUSB_DEV_CONF_USB_HOST_MODE     (1 << 16)
-#define        TUSB_DEV_CONF_PROD_TEST_MODE    (1 << 15)
-#define        TUSB_DEV_CONF_SOFT_ID           (1 << 1)
-#define        TUSB_DEV_CONF_ID_SEL            (1 << 0)
-
-#define TUSB_PHY_OTG_CTRL_ENABLE       (TUSB_SYS_REG_BASE + 0x004)
-#define TUSB_PHY_OTG_CTRL              (TUSB_SYS_REG_BASE + 0x008)
-#define        TUSB_PHY_OTG_CTRL_WRPROTECT     (0xa5 << 24)
-#define        TUSB_PHY_OTG_CTRL_O_ID_PULLUP   (1 << 23)
-#define        TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
-#define        TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
-#define        TUSB_PHY_OTG_CTRL_TESTM2        (1 << 17)
-#define        TUSB_PHY_OTG_CTRL_TESTM1        (1 << 16)
-#define        TUSB_PHY_OTG_CTRL_TESTM0        (1 << 15)
-#define        TUSB_PHY_OTG_CTRL_TX_DATA2      (1 << 14)
-#define        TUSB_PHY_OTG_CTRL_TX_GZ2        (1 << 13)
-#define        TUSB_PHY_OTG_CTRL_TX_ENABLE2    (1 << 12)
-#define        TUSB_PHY_OTG_CTRL_DM_PULLDOWN   (1 << 11)
-#define        TUSB_PHY_OTG_CTRL_DP_PULLDOWN   (1 << 10)
-#define        TUSB_PHY_OTG_CTRL_OSC_EN        (1 << 9)
-#define        TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
-#define        TUSB_PHY_OTG_CTRL_PD            (1 << 6)
-#define        TUSB_PHY_OTG_CTRL_PLL_ON        (1 << 5)
-#define        TUSB_PHY_OTG_CTRL_EXT_RPU       (1 << 4)
-#define        TUSB_PHY_OTG_CTRL_PWR_GOOD      (1 << 3)
-#define        TUSB_PHY_OTG_CTRL_RESET         (1 << 2)
-#define        TUSB_PHY_OTG_CTRL_SUSPENDM      (1 << 1)
-#define        TUSB_PHY_OTG_CTRL_CLK_MODE      (1 << 0)
-
-/* OTG status register */
-#define TUSB_DEV_OTG_STAT              (TUSB_SYS_REG_BASE + 0x00c)
-#define        TUSB_DEV_OTG_STAT_PWR_CLK_GOOD  (1 << 8)
-#define        TUSB_DEV_OTG_STAT_SESS_END      (1 << 7)
-#define        TUSB_DEV_OTG_STAT_SESS_VALID    (1 << 6)
-#define        TUSB_DEV_OTG_STAT_VBUS_VALID    (1 << 5)
-#define        TUSB_DEV_OTG_STAT_VBUS_SENSE    (1 << 4)
-#define        TUSB_DEV_OTG_STAT_ID_STATUS     (1 << 3)
-#define        TUSB_DEV_OTG_STAT_HOST_DISCON   (1 << 2)
-#define        TUSB_DEV_OTG_STAT_LINE_STATE    (3 << 0)
-#define        TUSB_DEV_OTG_STAT_DP_ENABLE     (1 << 1)
-#define        TUSB_DEV_OTG_STAT_DM_ENABLE     (1 << 0)
-
-#define TUSB_DEV_OTG_TIMER             (TUSB_SYS_REG_BASE + 0x010)
-#define TUSB_DEV_OTG_TIMER_ENABLE      (1 << 31)
-#define TUSB_DEV_OTG_TIMER_VAL(v)      ((v) & 0x07ffffff)
-#define TUSB_PRCM_REV                  (TUSB_SYS_REG_BASE + 0x014)
-
-/* PRCM configuration register */
-#define TUSB_PRCM_CONF                 (TUSB_SYS_REG_BASE + 0x018)
-#define        TUSB_PRCM_CONF_SFW_CPEN         (1 << 24)
-#define        TUSB_PRCM_CONF_SYS_CLKSEL(v)    (((v) & 3) << 16)
-
-/* PRCM management register */
-#define TUSB_PRCM_MNGMT                        (TUSB_SYS_REG_BASE + 0x01c)
-#define        TUSB_PRCM_MNGMT_SRP_FIX_TMR(v)  (((v) & 0xf) << 25)
-#define        TUSB_PRCM_MNGMT_SRP_FIX_EN      (1 << 24)
-#define        TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
-#define        TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
-#define        TUSB_PRCM_MNGMT_DFT_CLK_DIS     (1 << 18)
-#define        TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS   (1 << 17)
-#define        TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
-#define        TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
-#define        TUSB_PRCM_MNGMT_OTG_ID_PULLUP   (1 << 8)
-#define        TUSB_PRCM_MNGMT_15_SW_EN        (1 << 4)
-#define        TUSB_PRCM_MNGMT_33_SW_EN        (1 << 3)
-#define        TUSB_PRCM_MNGMT_5V_CPEN         (1 << 2)
-#define        TUSB_PRCM_MNGMT_PM_IDLE         (1 << 1)
-#define        TUSB_PRCM_MNGMT_DEV_IDLE        (1 << 0)
-
-/* Wake-up source clear and mask registers */
-#define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
-#define TUSB_PRCM_WAKEUP_CLEAR         (TUSB_SYS_REG_BASE + 0x028)
-#define TUSB_PRCM_WAKEUP_MASK          (TUSB_SYS_REG_BASE + 0x02c)
-#define        TUSB_PRCM_WAKEUP_RESERVED_BITS  (0xffffe << 13)
-#define        TUSB_PRCM_WGPIO_7               (1 << 12)
-#define        TUSB_PRCM_WGPIO_6               (1 << 11)
-#define        TUSB_PRCM_WGPIO_5               (1 << 10)
-#define        TUSB_PRCM_WGPIO_4               (1 << 9)
-#define        TUSB_PRCM_WGPIO_3               (1 << 8)
-#define        TUSB_PRCM_WGPIO_2               (1 << 7)
-#define        TUSB_PRCM_WGPIO_1               (1 << 6)
-#define        TUSB_PRCM_WGPIO_0               (1 << 5)
-#define        TUSB_PRCM_WHOSTDISCON           (1 << 4)        /* Host disconnect */
-#define        TUSB_PRCM_WBUS                  (1 << 3)        /* USB bus resume */
-#define        TUSB_PRCM_WNORCS                (1 << 2)        /* NOR chip select */
-#define        TUSB_PRCM_WVBUS                 (1 << 1)        /* OTG PHY VBUS */
-#define        TUSB_PRCM_WID                   (1 << 0)        /* OTG PHY ID detect */
-
-#define TUSB_PULLUP_1_CTRL             (TUSB_SYS_REG_BASE + 0x030)
-#define TUSB_PULLUP_2_CTRL             (TUSB_SYS_REG_BASE + 0x034)
-#define TUSB_INT_CTRL_REV              (TUSB_SYS_REG_BASE + 0x038)
-#define TUSB_INT_CTRL_CONF             (TUSB_SYS_REG_BASE + 0x03c)
-#define TUSB_USBIP_INT_SRC             (TUSB_SYS_REG_BASE + 0x040)
-#define TUSB_USBIP_INT_SET             (TUSB_SYS_REG_BASE + 0x044)
-#define TUSB_USBIP_INT_CLEAR           (TUSB_SYS_REG_BASE + 0x048)
-#define TUSB_USBIP_INT_MASK            (TUSB_SYS_REG_BASE + 0x04c)
-#define TUSB_DMA_INT_SRC               (TUSB_SYS_REG_BASE + 0x050)
-#define TUSB_DMA_INT_SET               (TUSB_SYS_REG_BASE + 0x054)
-#define TUSB_DMA_INT_CLEAR             (TUSB_SYS_REG_BASE + 0x058)
-#define TUSB_DMA_INT_MASK              (TUSB_SYS_REG_BASE + 0x05c)
-#define TUSB_GPIO_INT_SRC              (TUSB_SYS_REG_BASE + 0x060)
-#define TUSB_GPIO_INT_SET              (TUSB_SYS_REG_BASE + 0x064)
-#define TUSB_GPIO_INT_CLEAR            (TUSB_SYS_REG_BASE + 0x068)
-#define TUSB_GPIO_INT_MASK             (TUSB_SYS_REG_BASE + 0x06c)
-
-/* NOR flash interrupt source registers */
-#define TUSB_INT_SRC                   (TUSB_SYS_REG_BASE + 0x070)
-#define TUSB_INT_SRC_SET               (TUSB_SYS_REG_BASE + 0x074)
-#define TUSB_INT_SRC_CLEAR             (TUSB_SYS_REG_BASE + 0x078)
-#define TUSB_INT_MASK                  (TUSB_SYS_REG_BASE + 0x07c)
-#define        TUSB_INT_SRC_TXRX_DMA_DONE      (1 << 24)
-#define        TUSB_INT_SRC_USB_IP_CORE        (1 << 17)
-#define        TUSB_INT_SRC_OTG_TIMEOUT        (1 << 16)
-#define        TUSB_INT_SRC_VBUS_SENSE_CHNG    (1 << 15)
-#define        TUSB_INT_SRC_ID_STATUS_CHNG     (1 << 14)
-#define        TUSB_INT_SRC_DEV_WAKEUP         (1 << 13)
-#define        TUSB_INT_SRC_DEV_READY          (1 << 12)
-#define        TUSB_INT_SRC_USB_IP_TX          (1 << 9)
-#define        TUSB_INT_SRC_USB_IP_RX          (1 << 8)
-#define        TUSB_INT_SRC_USB_IP_VBUS_ERR    (1 << 7)
-#define        TUSB_INT_SRC_USB_IP_VBUS_REQ    (1 << 6)
-#define        TUSB_INT_SRC_USB_IP_DISCON      (1 << 5)
-#define        TUSB_INT_SRC_USB_IP_CONN        (1 << 4)
-#define        TUSB_INT_SRC_USB_IP_SOF         (1 << 3)
-#define        TUSB_INT_SRC_USB_IP_RST_BABBLE  (1 << 2)
-#define        TUSB_INT_SRC_USB_IP_RESUME      (1 << 1)
-#define        TUSB_INT_SRC_USB_IP_SUSPEND     (1 << 0)
-
-#define TUSB_GPIO_REV                  (TUSB_SYS_REG_BASE + 0x080)
-#define TUSB_GPIO_CONF                 (TUSB_SYS_REG_BASE + 0x084)
-#define TUSB_DMA_CTRL_REV              (TUSB_SYS_REG_BASE + 0x100)
-#define TUSB_DMA_REQ_CONF              (TUSB_SYS_REG_BASE + 0x104)
-#define TUSB_EP0_CONF                  (TUSB_SYS_REG_BASE + 0x108)
-#define TUSB_EP_IN_SIZE                        (TUSB_SYS_REG_BASE + 0x10c)
-#define TUSB_DMA_EP_MAP                        (TUSB_SYS_REG_BASE + 0x148)
-#define TUSB_EP_OUT_SIZE               (TUSB_SYS_REG_BASE + 0x14c)
-#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
-#define TUSB_SCRATCH_PAD               (TUSB_SYS_REG_BASE + 0x1c4)
-#define TUSB_WAIT_COUNT                        (TUSB_SYS_REG_BASE + 0x1c8)
-#define TUSB_PROD_TEST_RESET           (TUSB_SYS_REG_BASE + 0x1d8)
-
-#define TUSB_DIDR1_LO                  (TUSB_SYS_REG_BASE + 0x1f8)
-#define TUSB_DIDR1_HI                  (TUSB_SYS_REG_BASE + 0x1fc)
-
-/* Device System & Control register bitfields */
-#define TUSB_INT_CTRL_CONF_INT_RLCYC(v)        (((v) & 0x7) << 18)
-#define TUSB_INT_CTRL_CONF_INT_POLARITY        (1 << 17)
-#define TUSB_INT_CTRL_CONF_INT_MODE    (1 << 16)
-#define TUSB_GPIO_CONF_DMAREQ(v)       (((v) & 0x3f) << 24)
-#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)        (((v) & 3) << 26)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v)        (((v) & 0xf) << 16)
-#define TUSB_EP0_CONFIG_SW_EN          (1 << 8)
-#define TUSB_EP0_CONFIG_DIR_TX         (1 << 7)
-#define TUSB_EP0_CONFIG_XFR_SIZE(v)    ((v) & 0x7f)
-#define TUSB_EP_CONFIG_SW_EN           (1 << 31)
-#define TUSB_EP_CONFIG_XFR_SIZE(v)     ((v) & 0x7fffffff)
-#define TUSB_PROD_TEST_RESET_VAL       0xa596
-
-static void tusb_intr_update(TUSBState *s)
-{
-    if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
-        qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
-    else
-        qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
-}
-
-static void tusb_usbip_intr_update(TUSBState *s)
-{
-    /* TX interrupt in the MUSB */
-    if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
-        s->intr |= TUSB_INT_SRC_USB_IP_TX;
-    else
-        s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
-
-    /* RX interrupt in the MUSB */
-    if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
-        s->intr |= TUSB_INT_SRC_USB_IP_RX;
-    else
-        s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
-
-    /* XXX: What about TUSB_INT_SRC_USB_IP_CORE?  */
-
-    tusb_intr_update(s);
-}
-
-static void tusb_dma_intr_update(TUSBState *s)
-{
-    if (s->dma_intr & ~s->dma_mask)
-        s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
-    else
-        s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
-
-    tusb_intr_update(s);
-}
-
-static void tusb_gpio_intr_update(TUSBState *s)
-{
-    /* TODO: How is this signalled?  */
-}
-
-extern CPUReadMemoryFunc * const musb_read[];
-extern CPUWriteMemoryFunc * const musb_write[];
-
-static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        return musb_read[0](s->musb, addr & 0x1ff);
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-    }
-
-    printf("%s: unknown register at %03x\n",
-                    __FUNCTION__, (int) (addr & 0xfff));
-    return 0;
-}
-
-static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        return musb_read[1](s->musb, addr & 0x1ff);
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-    }
-
-    printf("%s: unknown register at %03x\n",
-                    __FUNCTION__, (int) (addr & 0xfff));
-    return 0;
-}
-
-static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
-{
-    TUSBState *s = (TUSBState *) opaque;
-    int offset = addr & 0xfff;
-    int epnum;
-    uint32_t ret;
-
-    switch (offset) {
-    case TUSB_DEV_CONF:
-        return s->dev_config;
-
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        return musb_read[2](s->musb, offset & 0x1ff);
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-
-    case TUSB_PHY_OTG_CTRL_ENABLE:
-    case TUSB_PHY_OTG_CTRL:
-        return 0x00;   /* TODO */
-
-    case TUSB_DEV_OTG_STAT:
-        ret = s->otg_status;
-#if 0
-        if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
-            ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-#endif
-        return ret;
-    case TUSB_DEV_OTG_TIMER:
-        return s->otg_timer_val;
-
-    case TUSB_PRCM_REV:
-        return 0x20;
-    case TUSB_PRCM_CONF:
-        return s->prcm_config;
-    case TUSB_PRCM_MNGMT:
-        return s->prcm_mngmt;
-    case TUSB_PRCM_WAKEUP_SOURCE:
-    case TUSB_PRCM_WAKEUP_CLEAR:       /* TODO: What does this one return?  */
-        return 0x00000000;
-    case TUSB_PRCM_WAKEUP_MASK:
-        return s->wkup_mask;
-
-    case TUSB_PULLUP_1_CTRL:
-        return s->pullup[0];
-    case TUSB_PULLUP_2_CTRL:
-        return s->pullup[1];
-
-    case TUSB_INT_CTRL_REV:
-        return 0x20;
-    case TUSB_INT_CTRL_CONF:
-        return s->control_config;
-
-    case TUSB_USBIP_INT_SRC:
-    case TUSB_USBIP_INT_SET:   /* TODO: What do these two return?  */
-    case TUSB_USBIP_INT_CLEAR:
-        return s->usbip_intr;
-    case TUSB_USBIP_INT_MASK:
-        return s->usbip_mask;
-
-    case TUSB_DMA_INT_SRC:
-    case TUSB_DMA_INT_SET:     /* TODO: What do these two return?  */
-    case TUSB_DMA_INT_CLEAR:
-        return s->dma_intr;
-    case TUSB_DMA_INT_MASK:
-        return s->dma_mask;
-
-    case TUSB_GPIO_INT_SRC:    /* TODO: What do these two return?  */
-    case TUSB_GPIO_INT_SET:
-    case TUSB_GPIO_INT_CLEAR:
-        return s->gpio_intr;
-    case TUSB_GPIO_INT_MASK:
-        return s->gpio_mask;
-
-    case TUSB_INT_SRC:
-    case TUSB_INT_SRC_SET:     /* TODO: What do these two return?  */
-    case TUSB_INT_SRC_CLEAR:
-        return s->intr;
-    case TUSB_INT_MASK:
-        return s->mask;
-
-    case TUSB_GPIO_REV:
-        return 0x30;
-    case TUSB_GPIO_CONF:
-        return s->gpio_config;
-
-    case TUSB_DMA_CTRL_REV:
-        return 0x30;
-    case TUSB_DMA_REQ_CONF:
-        return s->dma_config;
-    case TUSB_EP0_CONF:
-        return s->ep0_config;
-    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
-        return s->tx_config[epnum];
-    case TUSB_DMA_EP_MAP:
-        return s->dma_map;
-    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
-        return s->rx_config[epnum];
-    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
-            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
-        return 0x00000000;     /* TODO */
-    case TUSB_WAIT_COUNT:
-        return 0x00;           /* TODO */
-
-    case TUSB_SCRATCH_PAD:
-        return s->scratch;
-
-    case TUSB_PROD_TEST_RESET:
-        return s->test_reset;
-
-    /* DIE IDs */
-    case TUSB_DIDR1_LO:
-        return 0xa9453c59;
-    case TUSB_DIDR1_HI:
-        return 0x54059adf;
-    }
-
-    printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
-    return 0;
-}
-
-static void tusb_async_writeb(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        musb_write[0](s->musb, addr & 0x1ff, value);
-        break;
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
-        break;
-
-    default:
-        printf("%s: unknown register at %03x\n",
-                        __FUNCTION__, (int) (addr & 0xfff));
-        return;
-    }
-}
-
-static void tusb_async_writeh(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        musb_write[1](s->musb, addr & 0x1ff, value);
-        break;
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
-        break;
-
-    default:
-        printf("%s: unknown register at %03x\n",
-                        __FUNCTION__, (int) (addr & 0xfff));
-        return;
-    }
-}
-
-static void tusb_async_writew(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    TUSBState *s = (TUSBState *) opaque;
-    int offset = addr & 0xfff;
-    int epnum;
-
-    switch (offset) {
-    case TUSB_VLYNQ_CTRL:
-        break;
-
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        musb_write[2](s->musb, offset & 0x1ff, value);
-        break;
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
-        break;
-
-    case TUSB_DEV_CONF:
-        s->dev_config = value;
-        s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
-        if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
-            hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
-        break;
-
-    case TUSB_PHY_OTG_CTRL_ENABLE:
-    case TUSB_PHY_OTG_CTRL:
-        return;                /* TODO */
-    case TUSB_DEV_OTG_TIMER:
-        s->otg_timer_val = value;
-        if (value & TUSB_DEV_OTG_TIMER_ENABLE)
-            qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
-                            muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
-                                     get_ticks_per_sec(), TUSB_DEVCLOCK));
-        else
-            qemu_del_timer(s->otg_timer);
-        break;
-
-    case TUSB_PRCM_CONF:
-        s->prcm_config = value;
-        break;
-    case TUSB_PRCM_MNGMT:
-        s->prcm_mngmt = value;
-        break;
-    case TUSB_PRCM_WAKEUP_CLEAR:
-        break;
-    case TUSB_PRCM_WAKEUP_MASK:
-        s->wkup_mask = value;
-        break;
-
-    case TUSB_PULLUP_1_CTRL:
-        s->pullup[0] = value;
-        break;
-    case TUSB_PULLUP_2_CTRL:
-        s->pullup[1] = value;
-        break;
-    case TUSB_INT_CTRL_CONF:
-        s->control_config = value;
-        tusb_intr_update(s);
-        break;
-
-    case TUSB_USBIP_INT_SET:
-        s->usbip_intr |= value;
-        tusb_usbip_intr_update(s);
-        break;
-    case TUSB_USBIP_INT_CLEAR:
-        s->usbip_intr &= ~value;
-        tusb_usbip_intr_update(s);
-        musb_core_intr_clear(s->musb, ~value);
-        break;
-    case TUSB_USBIP_INT_MASK:
-        s->usbip_mask = value;
-        tusb_usbip_intr_update(s);
-        break;
-
-    case TUSB_DMA_INT_SET:
-        s->dma_intr |= value;
-        tusb_dma_intr_update(s);
-        break;
-    case TUSB_DMA_INT_CLEAR:
-        s->dma_intr &= ~value;
-        tusb_dma_intr_update(s);
-        break;
-    case TUSB_DMA_INT_MASK:
-        s->dma_mask = value;
-        tusb_dma_intr_update(s);
-        break;
-
-    case TUSB_GPIO_INT_SET:
-        s->gpio_intr |= value;
-        tusb_gpio_intr_update(s);
-        break;
-    case TUSB_GPIO_INT_CLEAR:
-        s->gpio_intr &= ~value;
-        tusb_gpio_intr_update(s);
-        break;
-    case TUSB_GPIO_INT_MASK:
-        s->gpio_mask = value;
-        tusb_gpio_intr_update(s);
-        break;
-
-    case TUSB_INT_SRC_SET:
-        s->intr |= value;
-        tusb_intr_update(s);
-        break;
-    case TUSB_INT_SRC_CLEAR:
-        s->intr &= ~value;
-        tusb_intr_update(s);
-        break;
-    case TUSB_INT_MASK:
-        s->mask = value;
-        tusb_intr_update(s);
-        break;
-
-    case TUSB_GPIO_CONF:
-        s->gpio_config = value;
-        break;
-    case TUSB_DMA_REQ_CONF:
-        s->dma_config = value;
-        break;
-    case TUSB_EP0_CONF:
-        s->ep0_config = value & 0x1ff;
-        musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
-                        value & TUSB_EP0_CONFIG_DIR_TX);
-        break;
-    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
-        s->tx_config[epnum] = value;
-        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
-        break;
-    case TUSB_DMA_EP_MAP:
-        s->dma_map = value;
-        break;
-    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
-        s->rx_config[epnum] = value;
-        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
-        break;
-    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
-            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
-        return;                /* TODO */
-    case TUSB_WAIT_COUNT:
-        return;                /* TODO */
-
-    case TUSB_SCRATCH_PAD:
-        s->scratch = value;
-        break;
-
-    case TUSB_PROD_TEST_RESET:
-        s->test_reset = value;
-        break;
-
-    default:
-        printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
-        return;
-    }
-}
-
-static const MemoryRegionOps tusb_async_ops = {
-    .old_mmio = {
-        .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
-        .write =  { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void tusb_otg_tick(void *opaque)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    s->otg_timer_val = 0;
-    s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
-    tusb_intr_update(s);
-}
-
-static void tusb_power_tick(void *opaque)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    if (s->power) {
-        s->intr_ok = ~0;
-        tusb_intr_update(s);
-    }
-}
-
-static void tusb_musb_core_intr(void *opaque, int source, int level)
-{
-    TUSBState *s = (TUSBState *) opaque;
-    uint16_t otg_status = s->otg_status;
-
-    switch (source) {
-    case musb_set_vbus:
-        if (level)
-            otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
-        else
-            otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-
-        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set?  */
-        /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set?  */
-        if (s->otg_status != otg_status) {
-            s->otg_status = otg_status;
-            s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
-            tusb_intr_update(s);
-        }
-        break;
-
-    case musb_set_session:
-        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set?  */
-        /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set?  */
-        if (level) {
-            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
-            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
-        } else {
-            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
-            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
-        }
-
-        /* XXX: some IRQ or anything?  */
-        break;
-
-    case musb_irq_tx:
-    case musb_irq_rx:
-        s->usbip_intr = musb_core_intr_get(s->musb);
-        /* Fall through.  */
-    default:
-        if (level)
-            s->intr |= 1 << source;
-        else
-            s->intr &= ~(1 << source);
-        tusb_intr_update(s);
-        break;
-    }
-}
-
-static void tusb6010_power(TUSBState *s, int on)
-{
-    if (!on) {
-        s->power = 0;
-    } else if (!s->power && on) {
-        s->power = 1;
-        /* Pull the interrupt down after TUSB6010 comes up.  */
-        s->intr_ok = 0;
-        tusb_intr_update(s);
-        qemu_mod_timer(s->pwr_timer,
-                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
-    }
-}
-
-static void tusb6010_irq(void *opaque, int source, int level)
-{
-    if (source) {
-        tusb_musb_core_intr(opaque, source - 1, level);
-    } else {
-        tusb6010_power(opaque, level);
-    }
-}
-
-static void tusb6010_reset(DeviceState *dev)
-{
-    TUSBState *s = FROM_SYSBUS(TUSBState, SYS_BUS_DEVICE(dev));
-    int i;
-
-    s->test_reset = TUSB_PROD_TEST_RESET_VAL;
-    s->host_mode = 0;
-    s->dev_config = 0;
-    s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
-    s->power = 0;
-    s->mask = 0xffffffff;
-    s->intr = 0x00000000;
-    s->otg_timer_val = 0;
-    s->scratch = 0;
-    s->prcm_config = 0;
-    s->prcm_mngmt = 0;
-    s->intr_ok = 0;
-    s->usbip_intr = 0;
-    s->usbip_mask = 0;
-    s->gpio_intr = 0;
-    s->gpio_mask = 0;
-    s->gpio_config = 0;
-    s->dma_intr = 0;
-    s->dma_mask = 0;
-    s->dma_map = 0;
-    s->dma_config = 0;
-    s->ep0_config = 0;
-    s->wkup_mask = 0;
-    s->pullup[0] = s->pullup[1] = 0;
-    s->control_config = 0;
-    for (i = 0; i < 15; i++) {
-        s->rx_config[i] = s->tx_config[i] = 0;
-    }
-    musb_reset(s->musb);
-}
-
-static int tusb6010_init(SysBusDevice *dev)
-{
-    TUSBState *s = FROM_SYSBUS(TUSBState, dev);
-    s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
-    s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
-    memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
-                          UINT32_MAX);
-    sysbus_init_mmio(dev, &s->iomem[0]);
-    sysbus_init_mmio(dev, &s->iomem[1]);
-    sysbus_init_irq(dev, &s->irq);
-    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
-    s->musb = musb_init(&dev->qdev, 1);
-    return 0;
-}
-
-static void tusb6010_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = tusb6010_init;
-    dc->reset = tusb6010_reset;
-}
-
-static const TypeInfo tusb6010_info = {
-    .name          = "tusb6010",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(TUSBState),
-    .class_init    = tusb6010_class_init,
-};
-
-static void tusb6010_register_types(void)
-{
-    type_register_static(&tusb6010_info);
-}
-
-type_init(tusb6010_register_types)
index e984671129d844664ff6b41a102b7c85daadfe33..a587700a8bd3f786f434c8aa558597beb7849670 100644 (file)
@@ -2,6 +2,8 @@
 #define SUN4M_H
 
 #include "qemu-common.h"
+#include "exec/hwaddr.h"
+#include "qapi/qmp/types.h"
 
 /* Devices used by sparc32 system.  */