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#include "qom/object.h"
  20
  21/* Common timer implementation.  */
  22
  23#define TIMER_CTRL_ONESHOT      (1 << 0)
  24#define TIMER_CTRL_32BIT        (1 << 1)
  25#define TIMER_CTRL_DIV1         (0 << 2)
  26#define TIMER_CTRL_DIV16        (1 << 2)
  27#define TIMER_CTRL_DIV256       (2 << 2)
  28#define TIMER_CTRL_IE           (1 << 5)
  29#define TIMER_CTRL_PERIODIC     (1 << 6)
  30#define TIMER_CTRL_ENABLE       (1 << 7)
  31
  32typedef struct {
  33    ptimer_state *timer;
  34    uint32_t control;
  35    uint32_t limit;
  36    int freq;
  37    int int_level;
  38    qemu_irq irq;
  39} arm_timer_state;
  40
  41/* Check all active timers, and schedule the next timer interrupt.  */
  42
  43static void arm_timer_update(arm_timer_state *s)
  44{
  45    /* Update interrupts.  */
  46    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
  47        qemu_irq_raise(s->irq);
  48    } else {
  49        qemu_irq_lower(s->irq);
  50    }
  51}
  52
  53static uint32_t arm_timer_read(void *opaque, hwaddr offset)
  54{
  55    arm_timer_state *s = (arm_timer_state *)opaque;
  56
  57    switch (offset >> 2) {
  58    case 0: /* TimerLoad */
  59    case 6: /* TimerBGLoad */
  60        return s->limit;
  61    case 1: /* TimerValue */
  62        return ptimer_get_count(s->timer);
  63    case 2: /* TimerControl */
  64        return s->control;
  65    case 4: /* TimerRIS */
  66        return s->int_level;
  67    case 5: /* TimerMIS */
  68        if ((s->control & TIMER_CTRL_IE) == 0)
  69            return 0;
  70        return s->int_level;
  71    default:
  72        qemu_log_mask(LOG_GUEST_ERROR,
  73                      "%s: Bad offset %x\n", __func__, (int)offset);
  74        return 0;
  75    }
  76}
  77
  78/*
  79 * Reset the timer limit after settings have changed.
  80 * May only be called from inside a ptimer transaction block.
  81 */
  82static void arm_timer_recalibrate(arm_timer_state *s, int reload)
  83{
  84    uint32_t limit;
  85
  86    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
  87        /* Free running.  */
  88        if (s->control & TIMER_CTRL_32BIT)
  89            limit = 0xffffffff;
  90        else
  91            limit = 0xffff;
  92    } else {
  93          /* Periodic.  */
  94          limit = s->limit;
  95    }
  96    ptimer_set_limit(s->timer, limit, reload);
  97}
  98
  99static void arm_timer_write(void *opaque, hwaddr offset,
 100                            uint32_t value)
 101{
 102    arm_timer_state *s = (arm_timer_state *)opaque;
 103    int freq;
 104
 105    switch (offset >> 2) {
 106    case 0: /* TimerLoad */
 107        s->limit = value;
 108        ptimer_transaction_begin(s->timer);
 109        arm_timer_recalibrate(s, 1);
 110        ptimer_transaction_commit(s->timer);
 111        break;
 112    case 1: /* TimerValue */
 113        /* ??? Linux seems to want to write to this readonly register.
 114           Ignore it.  */
 115        break;
 116    case 2: /* TimerControl */
 117        ptimer_transaction_begin(s->timer);
 118        if (s->control & TIMER_CTRL_ENABLE) {
 119            /* Pause the timer if it is running.  This may cause some
 120               inaccuracy dure to rounding, but avoids a whole lot of other
 121               messyness.  */
 122            ptimer_stop(s->timer);
 123        }
 124        s->control = value;
 125        freq = s->freq;
 126        /* ??? Need to recalculate expiry time after changing divisor.  */
 127        switch ((value >> 2) & 3) {
 128        case 1: freq >>= 4; break;
 129        case 2: freq >>= 8; break;
 130        }
 131        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
 132        ptimer_set_freq(s->timer, freq);
 133        if (s->control & TIMER_CTRL_ENABLE) {
 134            /* Restart the timer if still enabled.  */
 135            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
 136        }
 137        ptimer_transaction_commit(s->timer);
 138        break;
 139    case 3: /* TimerIntClr */
 140        s->int_level = 0;
 141        break;
 142    case 6: /* TimerBGLoad */
 143        s->limit = value;
 144        ptimer_transaction_begin(s->timer);
 145        arm_timer_recalibrate(s, 0);
 146        ptimer_transaction_commit(s->timer);
 147        break;
 148    default:
 149        qemu_log_mask(LOG_GUEST_ERROR,
 150                      "%s: Bad offset %x\n", __func__, (int)offset);
 151    }
 152    arm_timer_update(s);
 153}
 154
 155static void arm_timer_tick(void *opaque)
 156{
 157    arm_timer_state *s = (arm_timer_state *)opaque;
 158    s->int_level = 1;
 159    arm_timer_update(s);
 160}
 161
 162static const VMStateDescription vmstate_arm_timer = {
 163    .name = "arm_timer",
 164    .version_id = 1,
 165    .minimum_version_id = 1,
 166    .fields = (VMStateField[]) {
 167        VMSTATE_UINT32(control, arm_timer_state),
 168        VMSTATE_UINT32(limit, arm_timer_state),
 169        VMSTATE_INT32(int_level, arm_timer_state),
 170        VMSTATE_PTIMER(timer, arm_timer_state),
 171        VMSTATE_END_OF_LIST()
 172    }
 173};
 174
 175static arm_timer_state *arm_timer_init(uint32_t freq)
 176{
 177    arm_timer_state *s;
 178
 179    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
 180    s->freq = freq;
 181    s->control = TIMER_CTRL_IE;
 182
 183    s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT);
 184    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s);
 185    return s;
 186}
 187
 188/* ARM PrimeCell SP804 dual timer module.
 189 * Docs at
 190 * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
 191*/
 192
 193#define TYPE_SP804 "sp804"
 194OBJECT_DECLARE_SIMPLE_TYPE(SP804State, SP804)
 195
 196struct SP804State {
 197    SysBusDevice parent_obj;
 198
 199    MemoryRegion iomem;
 200    arm_timer_state *timer[2];
 201    uint32_t freq0, freq1;
 202    int level[2];
 203    qemu_irq irq;
 204};
 205
 206static const uint8_t sp804_ids[] = {
 207    /* Timer ID */
 208    0x04, 0x18, 0x14, 0,
 209    /* PrimeCell ID */
 210    0xd, 0xf0, 0x05, 0xb1
 211};
 212
 213/* Merge the IRQs from the two component devices.  */
 214static void sp804_set_irq(void *opaque, int irq, int level)
 215{
 216    SP804State *s = (SP804State *)opaque;
 217
 218    s->level[irq] = level;
 219    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 220}
 221
 222static uint64_t sp804_read(void *opaque, hwaddr offset,
 223                           unsigned size)
 224{
 225    SP804State *s = (SP804State *)opaque;
 226
 227    if (offset < 0x20) {
 228        return arm_timer_read(s->timer[0], offset);
 229    }
 230    if (offset < 0x40) {
 231        return arm_timer_read(s->timer[1], offset - 0x20);
 232    }
 233
 234    /* TimerPeriphID */
 235    if (offset >= 0xfe0 && offset <= 0xffc) {
 236        return sp804_ids[(offset - 0xfe0) >> 2];
 237    }
 238
 239    switch (offset) {
 240    /* Integration Test control registers, which we won't support */
 241    case 0xf00: /* TimerITCR */
 242    case 0xf04: /* TimerITOP (strictly write only but..) */
 243        qemu_log_mask(LOG_UNIMP,
 244                      "%s: integration test registers unimplemented\n",
 245                      __func__);
 246        return 0;
 247    }
 248
 249    qemu_log_mask(LOG_GUEST_ERROR,
 250                  "%s: Bad offset %x\n", __func__, (int)offset);
 251    return 0;
 252}
 253
 254static void sp804_write(void *opaque, hwaddr offset,
 255                        uint64_t value, unsigned size)
 256{
 257    SP804State *s = (SP804State *)opaque;
 258
 259    if (offset < 0x20) {
 260        arm_timer_write(s->timer[0], offset, value);
 261        return;
 262    }
 263
 264    if (offset < 0x40) {
 265        arm_timer_write(s->timer[1], offset - 0x20, value);
 266        return;
 267    }
 268
 269    /* Technically we could be writing to the Test Registers, but not likely */
 270    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
 271                  __func__, (int)offset);
 272}
 273
 274static const MemoryRegionOps sp804_ops = {
 275    .read = sp804_read,
 276    .write = sp804_write,
 277    .endianness = DEVICE_NATIVE_ENDIAN,
 278};
 279
 280static const VMStateDescription vmstate_sp804 = {
 281    .name = "sp804",
 282    .version_id = 1,
 283    .minimum_version_id = 1,
 284    .fields = (VMStateField[]) {
 285        VMSTATE_INT32_ARRAY(level, SP804State, 2),
 286        VMSTATE_END_OF_LIST()
 287    }
 288};
 289
 290static void sp804_init(Object *obj)
 291{
 292    SP804State *s = SP804(obj);
 293    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 294
 295    sysbus_init_irq(sbd, &s->irq);
 296    memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
 297                          "sp804", 0x1000);
 298    sysbus_init_mmio(sbd, &s->iomem);
 299}
 300
 301static void sp804_realize(DeviceState *dev, Error **errp)
 302{
 303    SP804State *s = SP804(dev);
 304
 305    s->timer[0] = arm_timer_init(s->freq0);
 306    s->timer[1] = arm_timer_init(s->freq1);
 307    s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
 308    s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
 309}
 310
 311/* Integrator/CP timer module.  */
 312
 313#define TYPE_INTEGRATOR_PIT "integrator_pit"
 314OBJECT_DECLARE_SIMPLE_TYPE(icp_pit_state, INTEGRATOR_PIT)
 315
 316struct icp_pit_state {
 317    SysBusDevice parent_obj;
 318
 319    MemoryRegion iomem;
 320    arm_timer_state *timer[3];
 321};
 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