qemu/hw/timer/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 licensed under the GPL.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "hw/sysbus.h"
  12#include "qemu/timer.h"
  13#include "qemu-common.h"
  14#include "hw/qdev.h"
  15#include "hw/ptimer.h"
  16#include "qemu/main-loop.h"
  17
  18/* Common timer implementation.  */
  19
  20#define TIMER_CTRL_ONESHOT      (1 << 0)
  21#define TIMER_CTRL_32BIT        (1 << 1)
  22#define TIMER_CTRL_DIV1         (0 << 2)
  23#define TIMER_CTRL_DIV16        (1 << 2)
  24#define TIMER_CTRL_DIV256       (2 << 2)
  25#define TIMER_CTRL_IE           (1 << 5)
  26#define TIMER_CTRL_PERIODIC     (1 << 6)
  27#define TIMER_CTRL_ENABLE       (1 << 7)
  28
  29typedef struct {
  30    ptimer_state *timer;
  31    uint32_t control;
  32    uint32_t limit;
  33    int freq;
  34    int int_level;
  35    qemu_irq irq;
  36} arm_timer_state;
  37
  38/* Check all active timers, and schedule the next timer interrupt.  */
  39
  40static void arm_timer_update(arm_timer_state *s)
  41{
  42    /* Update interrupts.  */
  43    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
  44        qemu_irq_raise(s->irq);
  45    } else {
  46        qemu_irq_lower(s->irq);
  47    }
  48}
  49
  50static uint32_t arm_timer_read(void *opaque, hwaddr offset)
  51{
  52    arm_timer_state *s = (arm_timer_state *)opaque;
  53
  54    switch (offset >> 2) {
  55    case 0: /* TimerLoad */
  56    case 6: /* TimerBGLoad */
  57        return s->limit;
  58    case 1: /* TimerValue */
  59        return ptimer_get_count(s->timer);
  60    case 2: /* TimerControl */
  61        return s->control;
  62    case 4: /* TimerRIS */
  63        return s->int_level;
  64    case 5: /* TimerMIS */
  65        if ((s->control & TIMER_CTRL_IE) == 0)
  66            return 0;
  67        return s->int_level;
  68    default:
  69        qemu_log_mask(LOG_GUEST_ERROR,
  70                      "%s: Bad offset %x\n", __func__, (int)offset);
  71        return 0;
  72    }
  73}
  74
  75/* Reset the timer limit after settings have changed.  */
  76static void arm_timer_recalibrate(arm_timer_state *s, int reload)
  77{
  78    uint32_t limit;
  79
  80    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
  81        /* Free running.  */
  82        if (s->control & TIMER_CTRL_32BIT)
  83            limit = 0xffffffff;
  84        else
  85            limit = 0xffff;
  86    } else {
  87          /* Periodic.  */
  88          limit = s->limit;
  89    }
  90    ptimer_set_limit(s->timer, limit, reload);
  91}
  92
  93static void arm_timer_write(void *opaque, hwaddr offset,
  94                            uint32_t value)
  95{
  96    arm_timer_state *s = (arm_timer_state *)opaque;
  97    int freq;
  98
  99    switch (offset >> 2) {
 100    case 0: /* TimerLoad */
 101        s->limit = value;
 102        arm_timer_recalibrate(s, 1);
 103        break;
 104    case 1: /* TimerValue */
 105        /* ??? Linux seems to want to write to this readonly register.
 106           Ignore it.  */
 107        break;
 108    case 2: /* TimerControl */
 109        if (s->control & TIMER_CTRL_ENABLE) {
 110            /* Pause the timer if it is running.  This may cause some
 111               inaccuracy dure to rounding, but avoids a whole lot of other
 112               messyness.  */
 113            ptimer_stop(s->timer);
 114        }
 115        s->control = value;
 116        freq = s->freq;
 117        /* ??? Need to recalculate expiry time after changing divisor.  */
 118        switch ((value >> 2) & 3) {
 119        case 1: freq >>= 4; break;
 120        case 2: freq >>= 8; break;
 121        }
 122        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
 123        ptimer_set_freq(s->timer, freq);
 124        if (s->control & TIMER_CTRL_ENABLE) {
 125            /* Restart the timer if still enabled.  */
 126            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
 127        }
 128        break;
 129    case 3: /* TimerIntClr */
 130        s->int_level = 0;
 131        break;
 132    case 6: /* TimerBGLoad */
 133        s->limit = value;
 134        arm_timer_recalibrate(s, 0);
 135        break;
 136    default:
 137        qemu_log_mask(LOG_GUEST_ERROR,
 138                      "%s: Bad offset %x\n", __func__, (int)offset);
 139    }
 140    arm_timer_update(s);
 141}
 142
 143static void arm_timer_tick(void *opaque)
 144{
 145    arm_timer_state *s = (arm_timer_state *)opaque;
 146    s->int_level = 1;
 147    arm_timer_update(s);
 148}
 149
 150static const VMStateDescription vmstate_arm_timer = {
 151    .name = "arm_timer",
 152    .version_id = 1,
 153    .minimum_version_id = 1,
 154    .fields = (VMStateField[]) {
 155        VMSTATE_UINT32(control, arm_timer_state),
 156        VMSTATE_UINT32(limit, arm_timer_state),
 157        VMSTATE_INT32(int_level, arm_timer_state),
 158        VMSTATE_PTIMER(timer, arm_timer_state),
 159        VMSTATE_END_OF_LIST()
 160    }
 161};
 162
 163static arm_timer_state *arm_timer_init(uint32_t freq)
 164{
 165    arm_timer_state *s;
 166    QEMUBH *bh;
 167
 168    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
 169    s->freq = freq;
 170    s->control = TIMER_CTRL_IE;
 171
 172    bh = qemu_bh_new(arm_timer_tick, s);
 173    s->timer = ptimer_init(bh);
 174    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
 175    return s;
 176}
 177
 178/* ARM PrimeCell SP804 dual timer module.
 179 * Docs at
 180 * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
 181*/
 182
 183#define TYPE_SP804 "sp804"
 184#define SP804(obj) OBJECT_CHECK(SP804State, (obj), TYPE_SP804)
 185
 186typedef struct SP804State {
 187    SysBusDevice parent_obj;
 188
 189    MemoryRegion iomem;
 190    arm_timer_state *timer[2];
 191    uint32_t freq0, freq1;
 192    int level[2];
 193    qemu_irq irq;
 194} SP804State;
 195
 196static const uint8_t sp804_ids[] = {
 197    /* Timer ID */
 198    0x04, 0x18, 0x14, 0,
 199    /* PrimeCell ID */
 200    0xd, 0xf0, 0x05, 0xb1
 201};
 202
 203/* Merge the IRQs from the two component devices.  */
 204static void sp804_set_irq(void *opaque, int irq, int level)
 205{
 206    SP804State *s = (SP804State *)opaque;
 207
 208    s->level[irq] = level;
 209    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 210}
 211
 212static uint64_t sp804_read(void *opaque, hwaddr offset,
 213                           unsigned size)
 214{
 215    SP804State *s = (SP804State *)opaque;
 216
 217    if (offset < 0x20) {
 218        return arm_timer_read(s->timer[0], offset);
 219    }
 220    if (offset < 0x40) {
 221        return arm_timer_read(s->timer[1], offset - 0x20);
 222    }
 223
 224    /* TimerPeriphID */
 225    if (offset >= 0xfe0 && offset <= 0xffc) {
 226        return sp804_ids[(offset - 0xfe0) >> 2];
 227    }
 228
 229    switch (offset) {
 230    /* Integration Test control registers, which we won't support */
 231    case 0xf00: /* TimerITCR */
 232    case 0xf04: /* TimerITOP (strictly write only but..) */
 233        qemu_log_mask(LOG_UNIMP,
 234                      "%s: integration test registers unimplemented\n",
 235                      __func__);
 236        return 0;
 237    }
 238
 239    qemu_log_mask(LOG_GUEST_ERROR,
 240                  "%s: Bad offset %x\n", __func__, (int)offset);
 241    return 0;
 242}
 243
 244static void sp804_write(void *opaque, hwaddr offset,
 245                        uint64_t value, unsigned size)
 246{
 247    SP804State *s = (SP804State *)opaque;
 248
 249    if (offset < 0x20) {
 250        arm_timer_write(s->timer[0], offset, value);
 251        return;
 252    }
 253
 254    if (offset < 0x40) {
 255        arm_timer_write(s->timer[1], offset - 0x20, value);
 256        return;
 257    }
 258
 259    /* Technically we could be writing to the Test Registers, but not likely */
 260    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
 261                  __func__, (int)offset);
 262}
 263
 264static const MemoryRegionOps sp804_ops = {
 265    .read = sp804_read,
 266    .write = sp804_write,
 267    .endianness = DEVICE_NATIVE_ENDIAN,
 268};
 269
 270static const VMStateDescription vmstate_sp804 = {
 271    .name = "sp804",
 272    .version_id = 1,
 273    .minimum_version_id = 1,
 274    .fields = (VMStateField[]) {
 275        VMSTATE_INT32_ARRAY(level, SP804State, 2),
 276        VMSTATE_END_OF_LIST()
 277    }
 278};
 279
 280static void sp804_init(Object *obj)
 281{
 282    SP804State *s = SP804(obj);
 283    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 284
 285    sysbus_init_irq(sbd, &s->irq);
 286    memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
 287                          "sp804", 0x1000);
 288    sysbus_init_mmio(sbd, &s->iomem);
 289}
 290
 291static void sp804_realize(DeviceState *dev, Error **errp)
 292{
 293    SP804State *s = SP804(dev);
 294
 295    s->timer[0] = arm_timer_init(s->freq0);
 296    s->timer[1] = arm_timer_init(s->freq1);
 297    s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
 298    s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
 299}
 300
 301/* Integrator/CP timer module.  */
 302
 303#define TYPE_INTEGRATOR_PIT "integrator_pit"
 304#define INTEGRATOR_PIT(obj) \
 305    OBJECT_CHECK(icp_pit_state, (obj), TYPE_INTEGRATOR_PIT)
 306
 307typedef struct {
 308    SysBusDevice parent_obj;
 309
 310    MemoryRegion iomem;
 311    arm_timer_state *timer[3];
 312} icp_pit_state;
 313
 314static uint64_t icp_pit_read(void *opaque, hwaddr offset,
 315                             unsigned size)
 316{
 317    icp_pit_state *s = (icp_pit_state *)opaque;
 318    int n;
 319
 320    /* ??? Don't know the PrimeCell ID for this device.  */
 321    n = offset >> 8;
 322    if (n > 2) {
 323        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
 324        return 0;
 325    }
 326
 327    return arm_timer_read(s->timer[n], offset & 0xff);
 328}
 329
 330static void icp_pit_write(void *opaque, hwaddr offset,
 331                          uint64_t value, unsigned size)
 332{
 333    icp_pit_state *s = (icp_pit_state *)opaque;
 334    int n;
 335
 336    n = offset >> 8;
 337    if (n > 2) {
 338        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
 339        return;
 340    }
 341
 342    arm_timer_write(s->timer[n], offset & 0xff, value);
 343}
 344
 345static const MemoryRegionOps icp_pit_ops = {
 346    .read = icp_pit_read,
 347    .write = icp_pit_write,
 348    .endianness = DEVICE_NATIVE_ENDIAN,
 349};
 350
 351static void icp_pit_init(Object *obj)
 352{
 353    icp_pit_state *s = INTEGRATOR_PIT(obj);
 354    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 355
 356    /* Timer 0 runs at the system clock speed (40MHz).  */
 357    s->timer[0] = arm_timer_init(40000000);
 358    /* The other two timers run at 1MHz.  */
 359    s->timer[1] = arm_timer_init(1000000);
 360    s->timer[2] = arm_timer_init(1000000);
 361
 362    sysbus_init_irq(dev, &s->timer[0]->irq);
 363    sysbus_init_irq(dev, &s->timer[1]->irq);
 364    sysbus_init_irq(dev, &s->timer[2]->irq);
 365
 366    memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
 367                          "icp_pit", 0x1000);
 368    sysbus_init_mmio(dev, &s->iomem);
 369    /* This device has no state to save/restore.  The component timers will
 370       save themselves.  */
 371}
 372
 373static const TypeInfo icp_pit_info = {
 374    .name          = TYPE_INTEGRATOR_PIT,
 375    .parent        = TYPE_SYS_BUS_DEVICE,
 376    .instance_size = sizeof(icp_pit_state),
 377    .instance_init = icp_pit_init,
 378};
 379
 380static Property sp804_properties[] = {
 381    DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
 382    DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
 383    DEFINE_PROP_END_OF_LIST(),
 384};
 385
 386static void sp804_class_init(ObjectClass *klass, void *data)
 387{
 388    DeviceClass *k = DEVICE_CLASS(klass);
 389
 390    k->realize = sp804_realize;
 391    k->props = sp804_properties;
 392    k->vmsd = &vmstate_sp804;
 393}
 394
 395static const TypeInfo sp804_info = {
 396    .name          = TYPE_SP804,
 397    .parent        = TYPE_SYS_BUS_DEVICE,
 398    .instance_size = sizeof(SP804State),
 399    .instance_init = sp804_init,
 400    .class_init    = sp804_class_init,
 401};
 402
 403static void arm_timer_register_types(void)
 404{
 405    type_register_static(&icp_pit_info);
 406    type_register_static(&sp804_info);
 407}
 408
 409type_init(arm_timer_register_types)
 410