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