qemu/hw/arm_timer.c
<<
>>
Prefs
   1/*
   2 * ARM PrimeCell Timer modules.
   3 *
   4 * Copyright (c) 2005-2006 CodeSourcery.
   5 * Written by Paul Brook
   6 *
   7 * This code is licenced under the GPL.
   8 */
   9
  10#include "sysbus.h"
  11#include "qemu-timer.h"
  12
  13/* Common timer implementation.  */
  14
  15#define TIMER_CTRL_ONESHOT      (1 << 0)
  16#define TIMER_CTRL_32BIT        (1 << 1)
  17#define TIMER_CTRL_DIV1         (0 << 2)
  18#define TIMER_CTRL_DIV16        (1 << 2)
  19#define TIMER_CTRL_DIV256       (2 << 2)
  20#define TIMER_CTRL_IE           (1 << 5)
  21#define TIMER_CTRL_PERIODIC     (1 << 6)
  22#define TIMER_CTRL_ENABLE       (1 << 7)
  23
  24typedef struct {
  25    ptimer_state *timer;
  26    uint32_t control;
  27    uint32_t limit;
  28    int freq;
  29    int int_level;
  30    qemu_irq irq;
  31} arm_timer_state;
  32
  33/* Check all active timers, and schedule the next timer interrupt.  */
  34
  35static void arm_timer_update(arm_timer_state *s)
  36{
  37    /* Update interrupts.  */
  38    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
  39        qemu_irq_raise(s->irq);
  40    } else {
  41        qemu_irq_lower(s->irq);
  42    }
  43}
  44
  45static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
  46{
  47    arm_timer_state *s = (arm_timer_state *)opaque;
  48
  49    switch (offset >> 2) {
  50    case 0: /* TimerLoad */
  51    case 6: /* TimerBGLoad */
  52        return s->limit;
  53    case 1: /* TimerValue */
  54        return ptimer_get_count(s->timer);
  55    case 2: /* TimerControl */
  56        return s->control;
  57    case 4: /* TimerRIS */
  58        return s->int_level;
  59    case 5: /* TimerMIS */
  60        if ((s->control & TIMER_CTRL_IE) == 0)
  61            return 0;
  62        return s->int_level;
  63    default:
  64        hw_error("arm_timer_read: Bad offset %x\n", (int)offset);
  65        return 0;
  66    }
  67}
  68
  69/* Reset the timer limit after settings have changed.  */
  70static void arm_timer_recalibrate(arm_timer_state *s, int reload)
  71{
  72    uint32_t limit;
  73
  74    if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
  75        /* Free running.  */
  76        if (s->control & TIMER_CTRL_32BIT)
  77            limit = 0xffffffff;
  78        else
  79            limit = 0xffff;
  80    } else {
  81          /* Periodic.  */
  82          limit = s->limit;
  83    }
  84    ptimer_set_limit(s->timer, limit, reload);
  85}
  86
  87static void arm_timer_write(void *opaque, target_phys_addr_t offset,
  88                            uint32_t value)
  89{
  90    arm_timer_state *s = (arm_timer_state *)opaque;
  91    int freq;
  92
  93    switch (offset >> 2) {
  94    case 0: /* TimerLoad */
  95        s->limit = value;
  96        arm_timer_recalibrate(s, 1);
  97        break;
  98    case 1: /* TimerValue */
  99        /* ??? Linux seems to want to write to this readonly register.
 100           Ignore it.  */
 101        break;
 102    case 2: /* TimerControl */
 103        if (s->control & TIMER_CTRL_ENABLE) {
 104            /* Pause the timer if it is running.  This may cause some
 105               inaccuracy dure to rounding, but avoids a whole lot of other
 106               messyness.  */
 107            ptimer_stop(s->timer);
 108        }
 109        s->control = value;
 110        freq = s->freq;
 111        /* ??? Need to recalculate expiry time after changing divisor.  */
 112        switch ((value >> 2) & 3) {
 113        case 1: freq >>= 4; break;
 114        case 2: freq >>= 8; break;
 115        }
 116        arm_timer_recalibrate(s, 0);
 117        ptimer_set_freq(s->timer, freq);
 118        if (s->control & TIMER_CTRL_ENABLE) {
 119            /* Restart the timer if still enabled.  */
 120            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
 121        }
 122        break;
 123    case 3: /* TimerIntClr */
 124        s->int_level = 0;
 125        break;
 126    case 6: /* TimerBGLoad */
 127        s->limit = value;
 128        arm_timer_recalibrate(s, 0);
 129        break;
 130    default:
 131        hw_error("arm_timer_write: Bad offset %x\n", (int)offset);
 132    }
 133    arm_timer_update(s);
 134}
 135
 136static void arm_timer_tick(void *opaque)
 137{
 138    arm_timer_state *s = (arm_timer_state *)opaque;
 139    s->int_level = 1;
 140    arm_timer_update(s);
 141}
 142
 143static void arm_timer_save(QEMUFile *f, void *opaque)
 144{
 145    arm_timer_state *s = (arm_timer_state *)opaque;
 146    qemu_put_be32(f, s->control);
 147    qemu_put_be32(f, s->limit);
 148    qemu_put_be32(f, s->int_level);
 149    qemu_put_ptimer(f, s->timer);
 150}
 151
 152static int arm_timer_load(QEMUFile *f, void *opaque, int version_id)
 153{
 154    arm_timer_state *s = (arm_timer_state *)opaque;
 155
 156    if (version_id != 1)
 157        return -EINVAL;
 158
 159    s->control = qemu_get_be32(f);
 160    s->limit = qemu_get_be32(f);
 161    s->int_level = qemu_get_be32(f);
 162    qemu_get_ptimer(f, s->timer);
 163    return 0;
 164}
 165
 166static arm_timer_state *arm_timer_init(uint32_t freq)
 167{
 168    arm_timer_state *s;
 169    QEMUBH *bh;
 170
 171    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
 172    s->freq = freq;
 173    s->control = TIMER_CTRL_IE;
 174
 175    bh = qemu_bh_new(arm_timer_tick, s);
 176    s->timer = ptimer_init(bh);
 177    register_savevm("arm_timer", -1, 1, arm_timer_save, arm_timer_load, s);
 178    return s;
 179}
 180
 181/* ARM PrimeCell SP804 dual timer module.
 182   Docs for this device don't seem to be publicly available.  This
 183   implementation is based on guesswork, the linux kernel sources and the
 184   Integrator/CP timer modules.  */
 185
 186typedef struct {
 187    SysBusDevice busdev;
 188    arm_timer_state *timer[2];
 189    int level[2];
 190    qemu_irq irq;
 191} sp804_state;
 192
 193/* Merge the IRQs from the two component devices.  */
 194static void sp804_set_irq(void *opaque, int irq, int level)
 195{
 196    sp804_state *s = (sp804_state *)opaque;
 197
 198    s->level[irq] = level;
 199    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 200}
 201
 202static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
 203{
 204    sp804_state *s = (sp804_state *)opaque;
 205
 206    /* ??? Don't know the PrimeCell ID for this device.  */
 207    if (offset < 0x20) {
 208        return arm_timer_read(s->timer[0], offset);
 209    } else {
 210        return arm_timer_read(s->timer[1], offset - 0x20);
 211    }
 212}
 213
 214static void sp804_write(void *opaque, target_phys_addr_t offset,
 215                        uint32_t value)
 216{
 217    sp804_state *s = (sp804_state *)opaque;
 218
 219    if (offset < 0x20) {
 220        arm_timer_write(s->timer[0], offset, value);
 221    } else {
 222        arm_timer_write(s->timer[1], offset - 0x20, value);
 223    }
 224}
 225
 226static CPUReadMemoryFunc *sp804_readfn[] = {
 227   sp804_read,
 228   sp804_read,
 229   sp804_read
 230};
 231
 232static CPUWriteMemoryFunc *sp804_writefn[] = {
 233   sp804_write,
 234   sp804_write,
 235   sp804_write
 236};
 237
 238static void sp804_save(QEMUFile *f, void *opaque)
 239{
 240    sp804_state *s = (sp804_state *)opaque;
 241    qemu_put_be32(f, s->level[0]);
 242    qemu_put_be32(f, s->level[1]);
 243}
 244
 245static int sp804_load(QEMUFile *f, void *opaque, int version_id)
 246{
 247    sp804_state *s = (sp804_state *)opaque;
 248
 249    if (version_id != 1)
 250        return -EINVAL;
 251
 252    s->level[0] = qemu_get_be32(f);
 253    s->level[1] = qemu_get_be32(f);
 254    return 0;
 255}
 256
 257static void sp804_init(SysBusDevice *dev)
 258{
 259    int iomemtype;
 260    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
 261    qemu_irq *qi;
 262
 263    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
 264    sysbus_init_irq(dev, &s->irq);
 265    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
 266       we don't implement that.  */
 267    s->timer[0] = arm_timer_init(1000000);
 268    s->timer[1] = arm_timer_init(1000000);
 269    s->timer[0]->irq = qi[0];
 270    s->timer[1]->irq = qi[1];
 271    iomemtype = cpu_register_io_memory(sp804_readfn,
 272                                       sp804_writefn, s);
 273    sysbus_init_mmio(dev, 0x1000, iomemtype);
 274    register_savevm("sp804", -1, 1, sp804_save, sp804_load, s);
 275}
 276
 277
 278/* Integrator/CP timer module.  */
 279
 280typedef struct {
 281    SysBusDevice busdev;
 282    arm_timer_state *timer[3];
 283} icp_pit_state;
 284
 285static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
 286{
 287    icp_pit_state *s = (icp_pit_state *)opaque;
 288    int n;
 289
 290    /* ??? Don't know the PrimeCell ID for this device.  */
 291    n = offset >> 8;
 292    if (n > 3) {
 293        hw_error("sp804_read: Bad timer %d\n", n);
 294    }
 295
 296    return arm_timer_read(s->timer[n], offset & 0xff);
 297}
 298
 299static void icp_pit_write(void *opaque, target_phys_addr_t offset,
 300                          uint32_t value)
 301{
 302    icp_pit_state *s = (icp_pit_state *)opaque;
 303    int n;
 304
 305    n = offset >> 8;
 306    if (n > 3) {
 307        hw_error("sp804_write: Bad timer %d\n", n);
 308    }
 309
 310    arm_timer_write(s->timer[n], offset & 0xff, value);
 311}
 312
 313
 314static CPUReadMemoryFunc *icp_pit_readfn[] = {
 315   icp_pit_read,
 316   icp_pit_read,
 317   icp_pit_read
 318};
 319
 320static CPUWriteMemoryFunc *icp_pit_writefn[] = {
 321   icp_pit_write,
 322   icp_pit_write,
 323   icp_pit_write
 324};
 325
 326static void icp_pit_init(SysBusDevice *dev)
 327{
 328    int iomemtype;
 329    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
 330
 331    /* Timer 0 runs at the system clock speed (40MHz).  */
 332    s->timer[0] = arm_timer_init(40000000);
 333    /* The other two timers run at 1MHz.  */
 334    s->timer[1] = arm_timer_init(1000000);
 335    s->timer[2] = arm_timer_init(1000000);
 336
 337    sysbus_init_irq(dev, &s->timer[0]->irq);
 338    sysbus_init_irq(dev, &s->timer[1]->irq);
 339    sysbus_init_irq(dev, &s->timer[2]->irq);
 340
 341    iomemtype = cpu_register_io_memory(icp_pit_readfn,
 342                                       icp_pit_writefn, s);
 343    sysbus_init_mmio(dev, 0x1000, iomemtype);
 344    /* This device has no state to save/restore.  The component timers will
 345       save themselves.  */
 346}
 347
 348static void arm_timer_register_devices(void)
 349{
 350    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
 351    sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
 352}
 353
 354device_init(arm_timer_register_devices)
 355