qemu/hw/timer/aspeed_timer.c
<<
>>
Prefs
   1/*
   2 * ASPEED AST2400 Timer
   3 *
   4 * Andrew Jeffery <andrew@aj.id.au>
   5 *
   6 * Copyright (C) 2016 IBM Corp.
   7 *
   8 * This code is licensed under the GPL version 2 or later.  See
   9 * the COPYING file in the top-level directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "qapi/error.h"
  14#include "hw/irq.h"
  15#include "hw/sysbus.h"
  16#include "hw/timer/aspeed_timer.h"
  17#include "migration/vmstate.h"
  18#include "qemu/bitops.h"
  19#include "qemu/timer.h"
  20#include "qemu/log.h"
  21#include "qemu/module.h"
  22#include "hw/qdev-properties.h"
  23#include "trace.h"
  24
  25#define TIMER_NR_REGS 4
  26
  27#define TIMER_CTRL_BITS 4
  28#define TIMER_CTRL_MASK ((1 << TIMER_CTRL_BITS) - 1)
  29
  30#define TIMER_CLOCK_USE_EXT true
  31#define TIMER_CLOCK_EXT_HZ 1000000
  32#define TIMER_CLOCK_USE_APB false
  33
  34#define TIMER_REG_STATUS 0
  35#define TIMER_REG_RELOAD 1
  36#define TIMER_REG_MATCH_FIRST 2
  37#define TIMER_REG_MATCH_SECOND 3
  38
  39#define TIMER_FIRST_CAP_PULSE 4
  40
  41enum timer_ctrl_op {
  42    op_enable = 0,
  43    op_external_clock,
  44    op_overflow_interrupt,
  45    op_pulse_enable
  46};
  47
  48/*
  49 * Minimum value of the reload register to filter out short period
  50 * timers which have a noticeable impact in emulation. 5us should be
  51 * enough, use 20us for "safety".
  52 */
  53#define TIMER_MIN_NS (20 * SCALE_US)
  54
  55/**
  56 * Avoid mutual references between AspeedTimerCtrlState and AspeedTimer
  57 * structs, as it's a waste of memory. The ptimer BH callback needs to know
  58 * whether a specific AspeedTimer is enabled, but this information is held in
  59 * AspeedTimerCtrlState. So, provide a helper to hoist ourselves from an
  60 * arbitrary AspeedTimer to AspeedTimerCtrlState.
  61 */
  62static inline AspeedTimerCtrlState *timer_to_ctrl(AspeedTimer *t)
  63{
  64    const AspeedTimer (*timers)[] = (void *)t - (t->id * sizeof(*t));
  65    return container_of(timers, AspeedTimerCtrlState, timers);
  66}
  67
  68static inline bool timer_ctrl_status(AspeedTimer *t, enum timer_ctrl_op op)
  69{
  70    return !!(timer_to_ctrl(t)->ctrl & BIT(t->id * TIMER_CTRL_BITS + op));
  71}
  72
  73static inline bool timer_enabled(AspeedTimer *t)
  74{
  75    return timer_ctrl_status(t, op_enable);
  76}
  77
  78static inline bool timer_overflow_interrupt(AspeedTimer *t)
  79{
  80    return timer_ctrl_status(t, op_overflow_interrupt);
  81}
  82
  83static inline bool timer_can_pulse(AspeedTimer *t)
  84{
  85    return t->id >= TIMER_FIRST_CAP_PULSE;
  86}
  87
  88static inline bool timer_external_clock(AspeedTimer *t)
  89{
  90    return timer_ctrl_status(t, op_external_clock);
  91}
  92
  93static inline uint32_t calculate_rate(struct AspeedTimer *t)
  94{
  95    AspeedTimerCtrlState *s = timer_to_ctrl(t);
  96
  97    return timer_external_clock(t) ? TIMER_CLOCK_EXT_HZ :
  98        aspeed_scu_get_apb_freq(s->scu);
  99}
 100
 101static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
 102{
 103    uint64_t delta_ns = now_ns - MIN(now_ns, t->start);
 104    uint32_t rate = calculate_rate(t);
 105    uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND);
 106
 107    return t->reload - MIN(t->reload, ticks);
 108}
 109
 110static uint32_t calculate_min_ticks(AspeedTimer *t, uint32_t value)
 111{
 112    uint32_t rate = calculate_rate(t);
 113    uint32_t min_ticks = muldiv64(TIMER_MIN_NS, rate, NANOSECONDS_PER_SECOND);
 114
 115    return  value < min_ticks ? min_ticks : value;
 116}
 117
 118static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
 119{
 120    uint64_t delta_ns;
 121    uint64_t delta_ticks;
 122
 123    delta_ticks = t->reload - MIN(t->reload, ticks);
 124    delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t));
 125
 126    return t->start + delta_ns;
 127}
 128
 129static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
 130{
 131    return t->match[i] < t->reload ? t->match[i] : 0;
 132}
 133
 134static uint64_t calculate_next(struct AspeedTimer *t)
 135{
 136    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 137    uint64_t next;
 138
 139    /*
 140     * We don't know the relationship between the values in the match
 141     * registers, so sort using MAX/MIN/zero. We sort in that order as
 142     * the timer counts down to zero.
 143     */
 144
 145    next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
 146    if (now < next) {
 147        return next;
 148    }
 149
 150    next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
 151    if (now < next) {
 152        return next;
 153    }
 154
 155    next = calculate_time(t, 0);
 156    if (now < next) {
 157        return next;
 158    }
 159
 160    /* We've missed all deadlines, fire interrupt and try again */
 161    timer_del(&t->timer);
 162
 163    if (timer_overflow_interrupt(t)) {
 164        AspeedTimerCtrlState *s = timer_to_ctrl(t);
 165        t->level = !t->level;
 166        s->irq_sts |= BIT(t->id);
 167        qemu_set_irq(t->irq, t->level);
 168    }
 169
 170    next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
 171    t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 172
 173    return calculate_time(t, next);
 174}
 175
 176static void aspeed_timer_mod(AspeedTimer *t)
 177{
 178    uint64_t next = calculate_next(t);
 179    if (next) {
 180        timer_mod(&t->timer, next);
 181    }
 182}
 183
 184static void aspeed_timer_expire(void *opaque)
 185{
 186    AspeedTimer *t = opaque;
 187    bool interrupt = false;
 188    uint32_t ticks;
 189
 190    if (!timer_enabled(t)) {
 191        return;
 192    }
 193
 194    ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 195
 196    if (!ticks) {
 197        interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1];
 198    } else if (ticks <= MIN(t->match[0], t->match[1])) {
 199        interrupt = true;
 200    } else if (ticks <= MAX(t->match[0], t->match[1])) {
 201        interrupt = true;
 202    }
 203
 204    if (interrupt) {
 205        AspeedTimerCtrlState *s = timer_to_ctrl(t);
 206        t->level = !t->level;
 207        s->irq_sts |= BIT(t->id);
 208        qemu_set_irq(t->irq, t->level);
 209    }
 210
 211    aspeed_timer_mod(t);
 212}
 213
 214static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
 215{
 216    uint64_t value;
 217
 218    switch (reg) {
 219    case TIMER_REG_STATUS:
 220        if (timer_enabled(t)) {
 221            value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 222        } else {
 223            value = t->reload;
 224        }
 225        break;
 226    case TIMER_REG_RELOAD:
 227        value = t->reload;
 228        break;
 229    case TIMER_REG_MATCH_FIRST:
 230    case TIMER_REG_MATCH_SECOND:
 231        value = t->match[reg - 2];
 232        break;
 233    default:
 234        qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
 235                      __func__, reg);
 236        value = 0;
 237        break;
 238    }
 239    return value;
 240}
 241
 242static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
 243{
 244    AspeedTimerCtrlState *s = opaque;
 245    const int reg = (offset & 0xf) / 4;
 246    uint64_t value;
 247
 248    switch (offset) {
 249    case 0x30: /* Control Register */
 250        value = s->ctrl;
 251        break;
 252    case 0x00 ... 0x2c: /* Timers 1 - 4 */
 253        value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg);
 254        break;
 255    case 0x40 ... 0x8c: /* Timers 5 - 8 */
 256        value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
 257        break;
 258    default:
 259        value = ASPEED_TIMER_GET_CLASS(s)->read(s, offset);
 260        break;
 261    }
 262    trace_aspeed_timer_read(offset, size, value);
 263    return value;
 264}
 265
 266static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
 267                                   uint32_t value)
 268{
 269    AspeedTimer *t;
 270    uint32_t old_reload;
 271
 272    trace_aspeed_timer_set_value(timer, reg, value);
 273    t = &s->timers[timer];
 274    switch (reg) {
 275    case TIMER_REG_RELOAD:
 276        old_reload = t->reload;
 277        t->reload = calculate_min_ticks(t, value);
 278
 279        /* If the reload value was not previously set, or zero, and
 280         * the current value is valid, try to start the timer if it is
 281         * enabled.
 282         */
 283        if (old_reload || !t->reload) {
 284            break;
 285        }
 286        /* fall through to re-enable */
 287    case TIMER_REG_STATUS:
 288        if (timer_enabled(t)) {
 289            uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 290            int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
 291            uint32_t rate = calculate_rate(t);
 292
 293            if (delta >= 0) {
 294                t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
 295            } else {
 296                t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
 297            }
 298            aspeed_timer_mod(t);
 299        }
 300        break;
 301    case TIMER_REG_MATCH_FIRST:
 302    case TIMER_REG_MATCH_SECOND:
 303        t->match[reg - 2] = value;
 304        if (timer_enabled(t)) {
 305            aspeed_timer_mod(t);
 306        }
 307        break;
 308    default:
 309        qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
 310                      __func__, reg);
 311        break;
 312    }
 313}
 314
 315/* Control register operations are broken out into helpers that can be
 316 * explicitly called on aspeed_timer_reset(), but also from
 317 * aspeed_timer_ctrl_op().
 318 */
 319
 320static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
 321{
 322    trace_aspeed_timer_ctrl_enable(t->id, enable);
 323    if (enable) {
 324        t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 325        aspeed_timer_mod(t);
 326    } else {
 327        timer_del(&t->timer);
 328    }
 329}
 330
 331static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
 332{
 333    trace_aspeed_timer_ctrl_external_clock(t->id, enable);
 334}
 335
 336static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
 337{
 338    trace_aspeed_timer_ctrl_overflow_interrupt(t->id, enable);
 339}
 340
 341static void aspeed_timer_ctrl_pulse_enable(AspeedTimer *t, bool enable)
 342{
 343    if (timer_can_pulse(t)) {
 344        trace_aspeed_timer_ctrl_pulse_enable(t->id, enable);
 345    } else {
 346        qemu_log_mask(LOG_GUEST_ERROR,
 347                "%s: Timer does not support pulse mode\n", __func__);
 348    }
 349}
 350
 351/**
 352 * Given the actions are fixed in number and completely described in helper
 353 * functions, dispatch with a lookup table rather than manage control flow with
 354 * a switch statement.
 355 */
 356static void (*const ctrl_ops[])(AspeedTimer *, bool) = {
 357    [op_enable] = aspeed_timer_ctrl_enable,
 358    [op_external_clock] = aspeed_timer_ctrl_external_clock,
 359    [op_overflow_interrupt] = aspeed_timer_ctrl_overflow_interrupt,
 360    [op_pulse_enable] = aspeed_timer_ctrl_pulse_enable,
 361};
 362
 363/**
 364 * Conditionally affect changes chosen by a timer's control bit.
 365 *
 366 * The aspeed_timer_ctrl_op() interface is convenient for the
 367 * aspeed_timer_set_ctrl() function as the "no change" early exit can be
 368 * calculated for all operations, which cleans up the caller code. However the
 369 * interface isn't convenient for the reset function where we want to enter a
 370 * specific state without artificially constructing old and new values that
 371 * will fall through the change guard (and motivates extracting the actions
 372 * out to helper functions).
 373 *
 374 * @t: The timer to manipulate
 375 * @op: The type of operation to be performed
 376 * @old: The old state of the timer's control bits
 377 * @new: The incoming state for the timer's control bits
 378 */
 379static void aspeed_timer_ctrl_op(AspeedTimer *t, enum timer_ctrl_op op,
 380                                 uint8_t old, uint8_t new)
 381{
 382    const uint8_t mask = BIT(op);
 383    const bool enable = !!(new & mask);
 384    const bool changed = ((old ^ new) & mask);
 385    if (!changed) {
 386        return;
 387    }
 388    ctrl_ops[op](t, enable);
 389}
 390
 391static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg)
 392{
 393    int i;
 394    int shift;
 395    uint8_t t_old, t_new;
 396    AspeedTimer *t;
 397    const uint8_t enable_mask = BIT(op_enable);
 398
 399    /* Handle a dependency between the 'enable' and remaining three
 400     * configuration bits - i.e. if more than one bit in the control set has
 401     * changed, including the 'enable' bit, then we want either disable the
 402     * timer and perform configuration, or perform configuration and then
 403     * enable the timer
 404     */
 405    for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
 406        t = &s->timers[i];
 407        shift = (i * TIMER_CTRL_BITS);
 408        t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
 409        t_new = (reg >> shift) & TIMER_CTRL_MASK;
 410
 411        /* If we are disabling, do so first */
 412        if ((t_old & enable_mask) && !(t_new & enable_mask)) {
 413            aspeed_timer_ctrl_enable(t, false);
 414        }
 415        aspeed_timer_ctrl_op(t, op_external_clock, t_old, t_new);
 416        aspeed_timer_ctrl_op(t, op_overflow_interrupt, t_old, t_new);
 417        aspeed_timer_ctrl_op(t, op_pulse_enable, t_old, t_new);
 418        /* If we are enabling, do so last */
 419        if (!(t_old & enable_mask) && (t_new & enable_mask)) {
 420            aspeed_timer_ctrl_enable(t, true);
 421        }
 422    }
 423    s->ctrl = reg;
 424}
 425
 426static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value)
 427{
 428    trace_aspeed_timer_set_ctrl2(value);
 429}
 430
 431static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
 432                               unsigned size)
 433{
 434    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
 435    const int reg = (offset & 0xf) / 4;
 436    AspeedTimerCtrlState *s = opaque;
 437
 438    switch (offset) {
 439    /* Control Registers */
 440    case 0x30:
 441        aspeed_timer_set_ctrl(s, tv);
 442        break;
 443    /* Timer Registers */
 444    case 0x00 ... 0x2c:
 445        aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv);
 446        break;
 447    case 0x40 ... 0x8c:
 448        aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
 449        break;
 450    default:
 451        ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value);
 452        break;
 453    }
 454}
 455
 456static const MemoryRegionOps aspeed_timer_ops = {
 457    .read = aspeed_timer_read,
 458    .write = aspeed_timer_write,
 459    .endianness = DEVICE_LITTLE_ENDIAN,
 460    .valid.min_access_size = 4,
 461    .valid.max_access_size = 4,
 462    .valid.unaligned = false,
 463};
 464
 465static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
 466{
 467    uint64_t value;
 468
 469    switch (offset) {
 470    case 0x34:
 471        value = s->ctrl2;
 472        break;
 473    case 0x38:
 474    case 0x3C:
 475    default:
 476        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 477                __func__, offset);
 478        value = 0;
 479        break;
 480    }
 481    return value;
 482}
 483
 484static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
 485                                    uint64_t value)
 486{
 487    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
 488
 489    switch (offset) {
 490    case 0x34:
 491        aspeed_timer_set_ctrl2(s, tv);
 492        break;
 493    case 0x38:
 494    case 0x3C:
 495    default:
 496        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 497                __func__, offset);
 498        break;
 499    }
 500}
 501
 502static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
 503{
 504    uint64_t value;
 505
 506    switch (offset) {
 507    case 0x34:
 508        value = s->ctrl2;
 509        break;
 510    case 0x38:
 511        value = s->ctrl3 & BIT(0);
 512        break;
 513    case 0x3C:
 514    default:
 515        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 516                __func__, offset);
 517        value = 0;
 518        break;
 519    }
 520    return value;
 521}
 522
 523static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
 524                                    uint64_t value)
 525{
 526    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
 527    uint8_t command;
 528
 529    switch (offset) {
 530    case 0x34:
 531        aspeed_timer_set_ctrl2(s, tv);
 532        break;
 533    case 0x38:
 534        command = (value >> 1) & 0xFF;
 535        if (command == 0xAE) {
 536            s->ctrl3 = 0x1;
 537        } else if (command == 0xEA) {
 538            s->ctrl3 = 0x0;
 539        }
 540        break;
 541    case 0x3C:
 542        if (s->ctrl3 & BIT(0)) {
 543            aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
 544        }
 545        break;
 546
 547    default:
 548        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 549                __func__, offset);
 550        break;
 551    }
 552}
 553
 554static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
 555{
 556    uint64_t value;
 557
 558    switch (offset) {
 559    case 0x34:
 560        value = s->irq_sts;
 561        break;
 562    case 0x38:
 563    case 0x3C:
 564    default:
 565        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 566                __func__, offset);
 567        value = 0;
 568        break;
 569    }
 570    return value;
 571}
 572
 573static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
 574                                    uint64_t value)
 575{
 576    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
 577
 578    switch (offset) {
 579    case 0x34:
 580        s->irq_sts &= tv;
 581        break;
 582    case 0x3C:
 583        aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
 584        break;
 585
 586    case 0x38:
 587    default:
 588        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 589                __func__, offset);
 590        break;
 591    }
 592}
 593
 594static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
 595{
 596    AspeedTimer *t = &s->timers[id];
 597
 598    t->id = id;
 599    timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t);
 600}
 601
 602static void aspeed_timer_realize(DeviceState *dev, Error **errp)
 603{
 604    int i;
 605    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 606    AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
 607
 608    assert(s->scu);
 609
 610    for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
 611        aspeed_init_one_timer(s, i);
 612        sysbus_init_irq(sbd, &s->timers[i].irq);
 613    }
 614    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_timer_ops, s,
 615                          TYPE_ASPEED_TIMER, 0x1000);
 616    sysbus_init_mmio(sbd, &s->iomem);
 617}
 618
 619static void aspeed_timer_reset(DeviceState *dev)
 620{
 621    int i;
 622    AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
 623
 624    for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
 625        AspeedTimer *t = &s->timers[i];
 626        /* Explicitly call helpers to avoid any conditional behaviour through
 627         * aspeed_timer_set_ctrl().
 628         */
 629        aspeed_timer_ctrl_enable(t, false);
 630        aspeed_timer_ctrl_external_clock(t, TIMER_CLOCK_USE_APB);
 631        aspeed_timer_ctrl_overflow_interrupt(t, false);
 632        aspeed_timer_ctrl_pulse_enable(t, false);
 633        t->level = 0;
 634        t->reload = 0;
 635        t->match[0] = 0;
 636        t->match[1] = 0;
 637    }
 638    s->ctrl = 0;
 639    s->ctrl2 = 0;
 640    s->ctrl3 = 0;
 641    s->irq_sts = 0;
 642}
 643
 644static const VMStateDescription vmstate_aspeed_timer = {
 645    .name = "aspeed.timer",
 646    .version_id = 2,
 647    .minimum_version_id = 2,
 648    .fields = (VMStateField[]) {
 649        VMSTATE_UINT8(id, AspeedTimer),
 650        VMSTATE_INT32(level, AspeedTimer),
 651        VMSTATE_TIMER(timer, AspeedTimer),
 652        VMSTATE_UINT32(reload, AspeedTimer),
 653        VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
 654        VMSTATE_END_OF_LIST()
 655    }
 656};
 657
 658static const VMStateDescription vmstate_aspeed_timer_state = {
 659    .name = "aspeed.timerctrl",
 660    .version_id = 2,
 661    .minimum_version_id = 2,
 662    .fields = (VMStateField[]) {
 663        VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
 664        VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
 665        VMSTATE_UINT32(ctrl3, AspeedTimerCtrlState),
 666        VMSTATE_UINT32(irq_sts, AspeedTimerCtrlState),
 667        VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
 668                             ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
 669                             AspeedTimer),
 670        VMSTATE_END_OF_LIST()
 671    }
 672};
 673
 674static Property aspeed_timer_properties[] = {
 675    DEFINE_PROP_LINK("scu", AspeedTimerCtrlState, scu, TYPE_ASPEED_SCU,
 676                     AspeedSCUState *),
 677    DEFINE_PROP_END_OF_LIST(),
 678};
 679
 680static void timer_class_init(ObjectClass *klass, void *data)
 681{
 682    DeviceClass *dc = DEVICE_CLASS(klass);
 683
 684    dc->realize = aspeed_timer_realize;
 685    dc->reset = aspeed_timer_reset;
 686    dc->desc = "ASPEED Timer";
 687    dc->vmsd = &vmstate_aspeed_timer_state;
 688    device_class_set_props(dc, aspeed_timer_properties);
 689}
 690
 691static const TypeInfo aspeed_timer_info = {
 692    .name = TYPE_ASPEED_TIMER,
 693    .parent = TYPE_SYS_BUS_DEVICE,
 694    .instance_size = sizeof(AspeedTimerCtrlState),
 695    .class_init = timer_class_init,
 696    .class_size = sizeof(AspeedTimerClass),
 697    .abstract   = true,
 698};
 699
 700static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data)
 701{
 702    DeviceClass *dc = DEVICE_CLASS(klass);
 703    AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
 704
 705    dc->desc = "ASPEED 2400 Timer";
 706    awc->read = aspeed_2400_timer_read;
 707    awc->write = aspeed_2400_timer_write;
 708}
 709
 710static const TypeInfo aspeed_2400_timer_info = {
 711    .name = TYPE_ASPEED_2400_TIMER,
 712    .parent = TYPE_ASPEED_TIMER,
 713    .class_init = aspeed_2400_timer_class_init,
 714};
 715
 716static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data)
 717{
 718    DeviceClass *dc = DEVICE_CLASS(klass);
 719    AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
 720
 721    dc->desc = "ASPEED 2500 Timer";
 722    awc->read = aspeed_2500_timer_read;
 723    awc->write = aspeed_2500_timer_write;
 724}
 725
 726static const TypeInfo aspeed_2500_timer_info = {
 727    .name = TYPE_ASPEED_2500_TIMER,
 728    .parent = TYPE_ASPEED_TIMER,
 729    .class_init = aspeed_2500_timer_class_init,
 730};
 731
 732static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data)
 733{
 734    DeviceClass *dc = DEVICE_CLASS(klass);
 735    AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
 736
 737    dc->desc = "ASPEED 2600 Timer";
 738    awc->read = aspeed_2600_timer_read;
 739    awc->write = aspeed_2600_timer_write;
 740}
 741
 742static const TypeInfo aspeed_2600_timer_info = {
 743    .name = TYPE_ASPEED_2600_TIMER,
 744    .parent = TYPE_ASPEED_TIMER,
 745    .class_init = aspeed_2600_timer_class_init,
 746};
 747
 748static void aspeed_timer_register_types(void)
 749{
 750    type_register_static(&aspeed_timer_info);
 751    type_register_static(&aspeed_2400_timer_info);
 752    type_register_static(&aspeed_2500_timer_info);
 753    type_register_static(&aspeed_2600_timer_info);
 754}
 755
 756type_init(aspeed_timer_register_types)
 757