qemu/hw/timer/cmsdk-apb-dualtimer.c
<<
>>
Prefs
   1/*
   2 * ARM CMSDK APB dual-timer emulation
   3 *
   4 * Copyright (c) 2018 Linaro Limited
   5 * Written by Peter Maydell
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License version 2 or
   9 *  (at your option) any later version.
  10 */
  11
  12/*
  13 * This is a model of the "APB dual-input timer" which is part of the Cortex-M
  14 * System Design Kit (CMSDK) and documented in the Cortex-M System
  15 * Design Kit Technical Reference Manual (ARM DDI0479C):
  16 * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
  17 */
  18
  19#include "qemu/osdep.h"
  20#include "qemu/log.h"
  21#include "trace.h"
  22#include "qapi/error.h"
  23#include "qemu/module.h"
  24#include "hw/sysbus.h"
  25#include "hw/irq.h"
  26#include "hw/qdev-properties.h"
  27#include "hw/registerfields.h"
  28#include "hw/timer/cmsdk-apb-dualtimer.h"
  29#include "migration/vmstate.h"
  30
  31REG32(TIMER1LOAD, 0x0)
  32REG32(TIMER1VALUE, 0x4)
  33REG32(TIMER1CONTROL, 0x8)
  34    FIELD(CONTROL, ONESHOT, 0, 1)
  35    FIELD(CONTROL, SIZE, 1, 1)
  36    FIELD(CONTROL, PRESCALE, 2, 2)
  37    FIELD(CONTROL, INTEN, 5, 1)
  38    FIELD(CONTROL, MODE, 6, 1)
  39    FIELD(CONTROL, ENABLE, 7, 1)
  40#define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
  41                              R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
  42                              R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
  43REG32(TIMER1INTCLR, 0xc)
  44REG32(TIMER1RIS, 0x10)
  45REG32(TIMER1MIS, 0x14)
  46REG32(TIMER1BGLOAD, 0x18)
  47REG32(TIMER2LOAD, 0x20)
  48REG32(TIMER2VALUE, 0x24)
  49REG32(TIMER2CONTROL, 0x28)
  50REG32(TIMER2INTCLR, 0x2c)
  51REG32(TIMER2RIS, 0x30)
  52REG32(TIMER2MIS, 0x34)
  53REG32(TIMER2BGLOAD, 0x38)
  54REG32(TIMERITCR, 0xf00)
  55    FIELD(TIMERITCR, ENABLE, 0, 1)
  56#define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
  57REG32(TIMERITOP, 0xf04)
  58    FIELD(TIMERITOP, TIMINT1, 0, 1)
  59    FIELD(TIMERITOP, TIMINT2, 1, 1)
  60#define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
  61                                R_TIMERITOP_TIMINT2_MASK)
  62REG32(PID4, 0xfd0)
  63REG32(PID5, 0xfd4)
  64REG32(PID6, 0xfd8)
  65REG32(PID7, 0xfdc)
  66REG32(PID0, 0xfe0)
  67REG32(PID1, 0xfe4)
  68REG32(PID2, 0xfe8)
  69REG32(PID3, 0xfec)
  70REG32(CID0, 0xff0)
  71REG32(CID1, 0xff4)
  72REG32(CID2, 0xff8)
  73REG32(CID3, 0xffc)
  74
  75/* PID/CID values */
  76static const int timer_id[] = {
  77    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
  78    0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
  79    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
  80};
  81
  82static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
  83{
  84    /* Return masked interrupt status for the timer module */
  85    return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
  86}
  87
  88static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
  89{
  90    bool timint1, timint2, timintc;
  91
  92    if (s->timeritcr) {
  93        /* Integration test mode: outputs driven directly from TIMERITOP bits */
  94        timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
  95        timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
  96    } else {
  97        timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
  98        timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
  99    }
 100
 101    timintc = timint1 || timint2;
 102
 103    qemu_set_irq(s->timermod[0].timerint, timint1);
 104    qemu_set_irq(s->timermod[1].timerint, timint2);
 105    qemu_set_irq(s->timerintc, timintc);
 106}
 107
 108static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
 109                                             uint32_t newctrl)
 110{
 111    /* Handle a write to the CONTROL register */
 112    uint32_t changed;
 113
 114    ptimer_transaction_begin(m->timer);
 115
 116    newctrl &= R_CONTROL_VALID_MASK;
 117
 118    changed = m->control ^ newctrl;
 119
 120    if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
 121        /* ENABLE cleared, stop timer before any further changes */
 122        ptimer_stop(m->timer);
 123    }
 124
 125    if (changed & R_CONTROL_PRESCALE_MASK) {
 126        int divisor;
 127
 128        switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
 129        case 0:
 130            divisor = 1;
 131            break;
 132        case 1:
 133            divisor = 16;
 134            break;
 135        case 2:
 136            divisor = 256;
 137            break;
 138        case 3:
 139            /* UNDEFINED; complain, and arbitrarily treat like 2 */
 140            qemu_log_mask(LOG_GUEST_ERROR,
 141                          "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
 142                          " is undefined behaviour\n");
 143            divisor = 256;
 144            break;
 145        default:
 146            g_assert_not_reached();
 147        }
 148        ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor);
 149    }
 150
 151    if (changed & R_CONTROL_MODE_MASK) {
 152        uint32_t load;
 153        if (newctrl & R_CONTROL_MODE_MASK) {
 154            /* Periodic: the limit is the LOAD register value */
 155            load = m->load;
 156        } else {
 157            /* Free-running: counter wraps around */
 158            load = ptimer_get_limit(m->timer);
 159            if (!(m->control & R_CONTROL_SIZE_MASK)) {
 160                load = deposit32(m->load, 0, 16, load);
 161            }
 162            m->load = load;
 163            load = 0xffffffff;
 164        }
 165        if (!(m->control & R_CONTROL_SIZE_MASK)) {
 166            load &= 0xffff;
 167        }
 168        ptimer_set_limit(m->timer, load, 0);
 169    }
 170
 171    if (changed & R_CONTROL_SIZE_MASK) {
 172        /* Timer switched between 16 and 32 bit count */
 173        uint32_t value, load;
 174
 175        value = ptimer_get_count(m->timer);
 176        load = ptimer_get_limit(m->timer);
 177        if (newctrl & R_CONTROL_SIZE_MASK) {
 178            /* 16 -> 32, top half of VALUE is in struct field */
 179            value = deposit32(m->value, 0, 16, value);
 180        } else {
 181            /* 32 -> 16: save top half to struct field and truncate */
 182            m->value = value;
 183            value &= 0xffff;
 184        }
 185
 186        if (newctrl & R_CONTROL_MODE_MASK) {
 187            /* Periodic, timer limit has LOAD value */
 188            if (newctrl & R_CONTROL_SIZE_MASK) {
 189                load = deposit32(m->load, 0, 16, load);
 190            } else {
 191                m->load = load;
 192                load &= 0xffff;
 193            }
 194        } else {
 195            /* Free-running, timer limit is set to give wraparound */
 196            if (newctrl & R_CONTROL_SIZE_MASK) {
 197                load = 0xffffffff;
 198            } else {
 199                load = 0xffff;
 200            }
 201        }
 202        ptimer_set_count(m->timer, value);
 203        ptimer_set_limit(m->timer, load, 0);
 204    }
 205
 206    if (newctrl & R_CONTROL_ENABLE_MASK) {
 207        /*
 208         * ENABLE is set; start the timer after all other changes.
 209         * We start it even if the ENABLE bit didn't actually change,
 210         * in case the timer was an expired one-shot timer that has
 211         * now been changed into a free-running or periodic timer.
 212         */
 213        ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
 214    }
 215
 216    m->control = newctrl;
 217
 218    ptimer_transaction_commit(m->timer);
 219}
 220
 221static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
 222                                          unsigned size)
 223{
 224    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
 225    uint64_t r;
 226
 227    if (offset >= A_TIMERITCR) {
 228        switch (offset) {
 229        case A_TIMERITCR:
 230            r = s->timeritcr;
 231            break;
 232        case A_PID4 ... A_CID3:
 233            r = timer_id[(offset - A_PID4) / 4];
 234            break;
 235        default:
 236        bad_offset:
 237            qemu_log_mask(LOG_GUEST_ERROR,
 238                          "CMSDK APB dual-timer read: bad offset %x\n",
 239                          (int) offset);
 240            r = 0;
 241            break;
 242        }
 243    } else {
 244        int timer = offset >> 5;
 245        CMSDKAPBDualTimerModule *m;
 246
 247        if (timer >= ARRAY_SIZE(s->timermod)) {
 248            goto bad_offset;
 249        }
 250
 251        m = &s->timermod[timer];
 252
 253        switch (offset & 0x1F) {
 254        case A_TIMER1LOAD:
 255        case A_TIMER1BGLOAD:
 256            if (m->control & R_CONTROL_MODE_MASK) {
 257                /*
 258                 * Periodic: the ptimer limit is the LOAD register value, (or
 259                 * just the low 16 bits of it if the timer is in 16-bit mode)
 260                 */
 261                r = ptimer_get_limit(m->timer);
 262                if (!(m->control & R_CONTROL_SIZE_MASK)) {
 263                    r = deposit32(m->load, 0, 16, r);
 264                }
 265            } else {
 266                /* Free-running: LOAD register value is just in m->load */
 267                r = m->load;
 268            }
 269            break;
 270        case A_TIMER1VALUE:
 271            r = ptimer_get_count(m->timer);
 272            if (!(m->control & R_CONTROL_SIZE_MASK)) {
 273                r = deposit32(m->value, 0, 16, r);
 274            }
 275            break;
 276        case A_TIMER1CONTROL:
 277            r = m->control;
 278            break;
 279        case A_TIMER1RIS:
 280            r = m->intstatus;
 281            break;
 282        case A_TIMER1MIS:
 283            r = cmsdk_dualtimermod_intstatus(m);
 284            break;
 285        default:
 286            goto bad_offset;
 287        }
 288    }
 289
 290    trace_cmsdk_apb_dualtimer_read(offset, r, size);
 291    return r;
 292}
 293
 294static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
 295                                       uint64_t value, unsigned size)
 296{
 297    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
 298
 299    trace_cmsdk_apb_dualtimer_write(offset, value, size);
 300
 301    if (offset >= A_TIMERITCR) {
 302        switch (offset) {
 303        case A_TIMERITCR:
 304            s->timeritcr = value & R_TIMERITCR_VALID_MASK;
 305            cmsdk_apb_dualtimer_update(s);
 306            break;
 307        case A_TIMERITOP:
 308            s->timeritop = value & R_TIMERITOP_VALID_MASK;
 309            cmsdk_apb_dualtimer_update(s);
 310            break;
 311        default:
 312        bad_offset:
 313            qemu_log_mask(LOG_GUEST_ERROR,
 314                          "CMSDK APB dual-timer write: bad offset %x\n",
 315                          (int) offset);
 316            break;
 317        }
 318    } else {
 319        int timer = offset >> 5;
 320        CMSDKAPBDualTimerModule *m;
 321
 322        if (timer >= ARRAY_SIZE(s->timermod)) {
 323            goto bad_offset;
 324        }
 325
 326        m = &s->timermod[timer];
 327
 328        switch (offset & 0x1F) {
 329        case A_TIMER1LOAD:
 330            /* Set the limit, and immediately reload the count from it */
 331            m->load = value;
 332            m->value = value;
 333            if (!(m->control & R_CONTROL_SIZE_MASK)) {
 334                value &= 0xffff;
 335            }
 336            ptimer_transaction_begin(m->timer);
 337            if (!(m->control & R_CONTROL_MODE_MASK)) {
 338                /*
 339                 * In free-running mode this won't set the limit but will
 340                 * still change the current count value.
 341                 */
 342                ptimer_set_count(m->timer, value);
 343            } else {
 344                if (!value) {
 345                    ptimer_stop(m->timer);
 346                }
 347                ptimer_set_limit(m->timer, value, 1);
 348                if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
 349                    /* Force possibly-expired oneshot timer to restart */
 350                    ptimer_run(m->timer, 1);
 351                }
 352            }
 353            ptimer_transaction_commit(m->timer);
 354            break;
 355        case A_TIMER1BGLOAD:
 356            /* Set the limit, but not the current count */
 357            m->load = value;
 358            if (!(m->control & R_CONTROL_MODE_MASK)) {
 359                /* In free-running mode there is no limit */
 360                break;
 361            }
 362            if (!(m->control & R_CONTROL_SIZE_MASK)) {
 363                value &= 0xffff;
 364            }
 365            ptimer_transaction_begin(m->timer);
 366            ptimer_set_limit(m->timer, value, 0);
 367            ptimer_transaction_commit(m->timer);
 368            break;
 369        case A_TIMER1CONTROL:
 370            cmsdk_dualtimermod_write_control(m, value);
 371            cmsdk_apb_dualtimer_update(s);
 372            break;
 373        case A_TIMER1INTCLR:
 374            m->intstatus = 0;
 375            cmsdk_apb_dualtimer_update(s);
 376            break;
 377        default:
 378            goto bad_offset;
 379        }
 380    }
 381}
 382
 383static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
 384    .read = cmsdk_apb_dualtimer_read,
 385    .write = cmsdk_apb_dualtimer_write,
 386    .endianness = DEVICE_LITTLE_ENDIAN,
 387    /* byte/halfword accesses are just zero-padded on reads and writes */
 388    .impl.min_access_size = 4,
 389    .impl.max_access_size = 4,
 390    .valid.min_access_size = 1,
 391    .valid.max_access_size = 4,
 392};
 393
 394static void cmsdk_dualtimermod_tick(void *opaque)
 395{
 396    CMSDKAPBDualTimerModule *m = opaque;
 397
 398    m->intstatus = 1;
 399    cmsdk_apb_dualtimer_update(m->parent);
 400}
 401
 402static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
 403{
 404    m->control = R_CONTROL_INTEN_MASK;
 405    m->intstatus = 0;
 406    m->load = 0;
 407    m->value = 0xffffffff;
 408    ptimer_transaction_begin(m->timer);
 409    ptimer_stop(m->timer);
 410    /*
 411     * We start in free-running mode, with VALUE at 0xffffffff, and
 412     * in 16-bit counter mode. This means that the ptimer count and
 413     * limit must both be set to 0xffff, so we wrap at 16 bits.
 414     */
 415    ptimer_set_limit(m->timer, 0xffff, 1);
 416    ptimer_set_freq(m->timer, m->parent->pclk_frq);
 417    ptimer_transaction_commit(m->timer);
 418}
 419
 420static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
 421{
 422    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
 423    int i;
 424
 425    trace_cmsdk_apb_dualtimer_reset();
 426
 427    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
 428        cmsdk_dualtimermod_reset(&s->timermod[i]);
 429    }
 430    s->timeritcr = 0;
 431    s->timeritop = 0;
 432}
 433
 434static void cmsdk_apb_dualtimer_init(Object *obj)
 435{
 436    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 437    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
 438    int i;
 439
 440    memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
 441                          s, "cmsdk-apb-dualtimer", 0x1000);
 442    sysbus_init_mmio(sbd, &s->iomem);
 443    sysbus_init_irq(sbd, &s->timerintc);
 444
 445    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
 446        sysbus_init_irq(sbd, &s->timermod[i].timerint);
 447    }
 448}
 449
 450static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
 451{
 452    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
 453    int i;
 454
 455    if (s->pclk_frq == 0) {
 456        error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
 457        return;
 458    }
 459
 460    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
 461        CMSDKAPBDualTimerModule *m = &s->timermod[i];
 462
 463        m->parent = s;
 464        m->timer = ptimer_init(cmsdk_dualtimermod_tick, m,
 465                               PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
 466                               PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
 467                               PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
 468                               PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 469    }
 470}
 471
 472static const VMStateDescription cmsdk_dualtimermod_vmstate = {
 473    .name = "cmsdk-apb-dualtimer-module",
 474    .version_id = 1,
 475    .minimum_version_id = 1,
 476    .fields = (VMStateField[]) {
 477        VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
 478        VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
 479        VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
 480        VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
 481        VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
 482        VMSTATE_END_OF_LIST()
 483    }
 484};
 485
 486static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
 487    .name = "cmsdk-apb-dualtimer",
 488    .version_id = 1,
 489    .minimum_version_id = 1,
 490    .fields = (VMStateField[]) {
 491        VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
 492                             CMSDK_APB_DUALTIMER_NUM_MODULES,
 493                             1, cmsdk_dualtimermod_vmstate,
 494                             CMSDKAPBDualTimerModule),
 495        VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
 496        VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
 497        VMSTATE_END_OF_LIST()
 498    }
 499};
 500
 501static Property cmsdk_apb_dualtimer_properties[] = {
 502    DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0),
 503    DEFINE_PROP_END_OF_LIST(),
 504};
 505
 506static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
 507{
 508    DeviceClass *dc = DEVICE_CLASS(klass);
 509
 510    dc->realize = cmsdk_apb_dualtimer_realize;
 511    dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
 512    dc->reset = cmsdk_apb_dualtimer_reset;
 513    dc->props = cmsdk_apb_dualtimer_properties;
 514}
 515
 516static const TypeInfo cmsdk_apb_dualtimer_info = {
 517    .name = TYPE_CMSDK_APB_DUALTIMER,
 518    .parent = TYPE_SYS_BUS_DEVICE,
 519    .instance_size = sizeof(CMSDKAPBDualTimer),
 520    .instance_init = cmsdk_apb_dualtimer_init,
 521    .class_init = cmsdk_apb_dualtimer_class_init,
 522};
 523
 524static void cmsdk_apb_dualtimer_register_types(void)
 525{
 526    type_register_static(&cmsdk_apb_dualtimer_info);
 527}
 528
 529type_init(cmsdk_apb_dualtimer_register_types);
 530