qemu/hw/timer/nrf51_timer.c
<<
>>
Prefs
   1/*
   2 * nRF51 System-on-Chip Timer peripheral
   3 *
   4 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
   5 * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
   6 *
   7 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
   8 * Copyright (c) 2019 Red Hat, Inc.
   9 *
  10 * This code is licensed under the GPL version 2 or later.  See
  11 * the COPYING file in the top-level directory.
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "qemu/log.h"
  16#include "qemu/module.h"
  17#include "hw/arm/nrf51.h"
  18#include "hw/timer/nrf51_timer.h"
  19#include "trace.h"
  20
  21#define TIMER_CLK_FREQ 16000000UL
  22
  23static uint32_t const bitwidths[] = {16, 8, 24, 32};
  24
  25static uint32_t ns_to_ticks(NRF51TimerState *s, int64_t ns)
  26{
  27    uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
  28
  29    return muldiv64(ns, freq, NANOSECONDS_PER_SECOND);
  30}
  31
  32static int64_t ticks_to_ns(NRF51TimerState *s, uint32_t ticks)
  33{
  34    uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
  35
  36    return muldiv64(ticks, NANOSECONDS_PER_SECOND, freq);
  37}
  38
  39/* Returns number of ticks since last call */
  40static uint32_t update_counter(NRF51TimerState *s, int64_t now)
  41{
  42    uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
  43
  44    s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
  45    s->update_counter_ns = now;
  46    return ticks;
  47}
  48
  49/* Assumes s->counter is up-to-date */
  50static void rearm_timer(NRF51TimerState *s, int64_t now)
  51{
  52    int64_t min_ns = INT64_MAX;
  53    size_t i;
  54
  55    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
  56        int64_t delta_ns;
  57
  58        if (s->events_compare[i]) {
  59            continue; /* already expired, ignore it for now */
  60        }
  61
  62        if (s->cc[i] <= s->counter) {
  63            delta_ns = ticks_to_ns(s, BIT(bitwidths[s->bitmode]) -
  64                                      s->counter + s->cc[i]);
  65        } else {
  66            delta_ns = ticks_to_ns(s, s->cc[i] - s->counter);
  67        }
  68
  69        if (delta_ns < min_ns) {
  70            min_ns = delta_ns;
  71        }
  72    }
  73
  74    if (min_ns != INT64_MAX) {
  75        timer_mod_ns(&s->timer, now + min_ns);
  76    }
  77}
  78
  79static void update_irq(NRF51TimerState *s)
  80{
  81    bool flag = false;
  82    size_t i;
  83
  84    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
  85        flag |= s->events_compare[i] && extract32(s->inten, 16 + i, 1);
  86    }
  87    qemu_set_irq(s->irq, flag);
  88}
  89
  90static void timer_expire(void *opaque)
  91{
  92    NRF51TimerState *s = NRF51_TIMER(opaque);
  93    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  94    uint32_t cc_remaining[NRF51_TIMER_REG_COUNT];
  95    bool should_stop = false;
  96    uint32_t ticks;
  97    size_t i;
  98
  99    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 100        if (s->cc[i] > s->counter) {
 101            cc_remaining[i] = s->cc[i] - s->counter;
 102        } else {
 103            cc_remaining[i] = BIT(bitwidths[s->bitmode]) -
 104                              s->counter + s->cc[i];
 105        }
 106    }
 107
 108    ticks = update_counter(s, now);
 109
 110    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 111        if (cc_remaining[i] <= ticks) {
 112            s->events_compare[i] = 1;
 113
 114            if (s->shorts & BIT(i)) {
 115                s->timer_start_ns = now;
 116                s->update_counter_ns = s->timer_start_ns;
 117                s->counter = 0;
 118            }
 119
 120            should_stop |= s->shorts & BIT(i + 8);
 121        }
 122    }
 123
 124    update_irq(s);
 125
 126    if (should_stop) {
 127        s->running = false;
 128        timer_del(&s->timer);
 129    } else {
 130        rearm_timer(s, now);
 131    }
 132}
 133
 134static void counter_compare(NRF51TimerState *s)
 135{
 136    uint32_t counter = s->counter;
 137    size_t i;
 138
 139    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 140        if (counter == s->cc[i]) {
 141            s->events_compare[i] = 1;
 142
 143            if (s->shorts & BIT(i)) {
 144                s->counter = 0;
 145            }
 146        }
 147    }
 148}
 149
 150static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size)
 151{
 152    NRF51TimerState *s = NRF51_TIMER(opaque);
 153    uint64_t r = 0;
 154
 155    switch (offset) {
 156    case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
 157        r = s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4];
 158        break;
 159    case NRF51_TIMER_REG_SHORTS:
 160        r = s->shorts;
 161        break;
 162    case NRF51_TIMER_REG_INTENSET:
 163        r = s->inten;
 164        break;
 165    case NRF51_TIMER_REG_INTENCLR:
 166        r = s->inten;
 167        break;
 168    case NRF51_TIMER_REG_MODE:
 169        r = s->mode;
 170        break;
 171    case NRF51_TIMER_REG_BITMODE:
 172        r = s->bitmode;
 173        break;
 174    case NRF51_TIMER_REG_PRESCALER:
 175        r = s->prescaler;
 176        break;
 177    case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
 178        r = s->cc[(offset - NRF51_TIMER_REG_CC0) / 4];
 179        break;
 180    default:
 181        qemu_log_mask(LOG_GUEST_ERROR,
 182                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
 183                      __func__, offset);
 184    }
 185
 186    trace_nrf51_timer_read(offset, r, size);
 187
 188    return r;
 189}
 190
 191static void nrf51_timer_write(void *opaque, hwaddr offset,
 192                       uint64_t value, unsigned int size)
 193{
 194    NRF51TimerState *s = NRF51_TIMER(opaque);
 195    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 196    size_t idx;
 197
 198    trace_nrf51_timer_write(offset, value, size);
 199
 200    switch (offset) {
 201    case NRF51_TIMER_TASK_START:
 202        if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_TIMER) {
 203            s->running = true;
 204            s->timer_start_ns = now - ticks_to_ns(s, s->counter);
 205            s->update_counter_ns = s->timer_start_ns;
 206            rearm_timer(s, now);
 207        }
 208        break;
 209    case NRF51_TIMER_TASK_STOP:
 210    case NRF51_TIMER_TASK_SHUTDOWN:
 211        if (value == NRF51_TRIGGER_TASK) {
 212            s->running = false;
 213            timer_del(&s->timer);
 214        }
 215        break;
 216    case NRF51_TIMER_TASK_COUNT:
 217        if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_COUNTER) {
 218            s->counter = (s->counter + 1) % BIT(bitwidths[s->bitmode]);
 219            counter_compare(s);
 220        }
 221        break;
 222    case NRF51_TIMER_TASK_CLEAR:
 223        if (value == NRF51_TRIGGER_TASK) {
 224            s->timer_start_ns = now;
 225            s->update_counter_ns = s->timer_start_ns;
 226            s->counter = 0;
 227            if (s->running) {
 228                rearm_timer(s, now);
 229            }
 230        }
 231        break;
 232    case NRF51_TIMER_TASK_CAPTURE_0 ... NRF51_TIMER_TASK_CAPTURE_3:
 233        if (value == NRF51_TRIGGER_TASK) {
 234            if (s->running) {
 235                timer_expire(s); /* update counter and all state */
 236            }
 237
 238            idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4;
 239            s->cc[idx] = s->counter;
 240        }
 241        break;
 242    case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
 243        if (value == NRF51_EVENT_CLEAR) {
 244            s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4] = 0;
 245
 246            if (s->running) {
 247                timer_expire(s); /* update counter and all state */
 248            }
 249        }
 250        break;
 251    case NRF51_TIMER_REG_SHORTS:
 252        s->shorts = value & NRF51_TIMER_REG_SHORTS_MASK;
 253        break;
 254    case NRF51_TIMER_REG_INTENSET:
 255        s->inten |= value & NRF51_TIMER_REG_INTEN_MASK;
 256        break;
 257    case NRF51_TIMER_REG_INTENCLR:
 258        s->inten &= ~(value & NRF51_TIMER_REG_INTEN_MASK);
 259        break;
 260    case NRF51_TIMER_REG_MODE:
 261        s->mode = value;
 262        break;
 263    case NRF51_TIMER_REG_BITMODE:
 264        if (s->mode == NRF51_TIMER_TIMER && s->running) {
 265            qemu_log_mask(LOG_GUEST_ERROR,
 266                    "%s: erroneous change of BITMODE while timer is running\n",
 267                    __func__);
 268        }
 269        s->bitmode = value & NRF51_TIMER_REG_BITMODE_MASK;
 270        break;
 271    case NRF51_TIMER_REG_PRESCALER:
 272        if (s->mode == NRF51_TIMER_TIMER && s->running) {
 273            qemu_log_mask(LOG_GUEST_ERROR,
 274                "%s: erroneous change of PRESCALER while timer is running\n",
 275                __func__);
 276        }
 277        s->prescaler = value & NRF51_TIMER_REG_PRESCALER_MASK;
 278        break;
 279    case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
 280        if (s->running) {
 281            timer_expire(s); /* update counter */
 282        }
 283
 284        idx = (offset - NRF51_TIMER_REG_CC0) / 4;
 285        s->cc[idx] = value % BIT(bitwidths[s->bitmode]);
 286
 287        if (s->running) {
 288            rearm_timer(s, now);
 289        }
 290        break;
 291    default:
 292        qemu_log_mask(LOG_GUEST_ERROR,
 293                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
 294                      __func__, offset);
 295    }
 296
 297    update_irq(s);
 298}
 299
 300static const MemoryRegionOps rng_ops = {
 301    .read =  nrf51_timer_read,
 302    .write = nrf51_timer_write,
 303    .endianness = DEVICE_LITTLE_ENDIAN,
 304    .impl.min_access_size = 4,
 305    .impl.max_access_size = 4,
 306};
 307
 308static void nrf51_timer_init(Object *obj)
 309{
 310    NRF51TimerState *s = NRF51_TIMER(obj);
 311    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 312
 313    memory_region_init_io(&s->iomem, obj, &rng_ops, s,
 314            TYPE_NRF51_TIMER, NRF51_TIMER_SIZE);
 315    sysbus_init_mmio(sbd, &s->iomem);
 316    sysbus_init_irq(sbd, &s->irq);
 317
 318    timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, timer_expire, s);
 319}
 320
 321static void nrf51_timer_reset(DeviceState *dev)
 322{
 323    NRF51TimerState *s = NRF51_TIMER(dev);
 324
 325    timer_del(&s->timer);
 326    s->timer_start_ns = 0x00;
 327    s->update_counter_ns = 0x00;
 328    s->counter = 0x00;
 329    s->running = false;
 330
 331    memset(s->events_compare, 0x00, sizeof(s->events_compare));
 332    memset(s->cc, 0x00, sizeof(s->cc));
 333
 334    s->shorts = 0x00;
 335    s->inten = 0x00;
 336    s->mode = 0x00;
 337    s->bitmode = 0x00;
 338    s->prescaler = 0x00;
 339}
 340
 341static int nrf51_timer_post_load(void *opaque, int version_id)
 342{
 343    NRF51TimerState *s = NRF51_TIMER(opaque);
 344
 345    if (s->running && s->mode == NRF51_TIMER_TIMER) {
 346        timer_expire(s);
 347    }
 348    return 0;
 349}
 350
 351static const VMStateDescription vmstate_nrf51_timer = {
 352    .name = TYPE_NRF51_TIMER,
 353    .version_id = 1,
 354    .post_load = nrf51_timer_post_load,
 355    .fields = (VMStateField[]) {
 356        VMSTATE_TIMER(timer, NRF51TimerState),
 357        VMSTATE_INT64(timer_start_ns, NRF51TimerState),
 358        VMSTATE_INT64(update_counter_ns, NRF51TimerState),
 359        VMSTATE_UINT32(counter, NRF51TimerState),
 360        VMSTATE_BOOL(running, NRF51TimerState),
 361        VMSTATE_UINT8_ARRAY(events_compare, NRF51TimerState,
 362                            NRF51_TIMER_REG_COUNT),
 363        VMSTATE_UINT32_ARRAY(cc, NRF51TimerState, NRF51_TIMER_REG_COUNT),
 364        VMSTATE_UINT32(shorts, NRF51TimerState),
 365        VMSTATE_UINT32(inten, NRF51TimerState),
 366        VMSTATE_UINT32(mode, NRF51TimerState),
 367        VMSTATE_UINT32(bitmode, NRF51TimerState),
 368        VMSTATE_UINT32(prescaler, NRF51TimerState),
 369        VMSTATE_END_OF_LIST()
 370    }
 371};
 372
 373static void nrf51_timer_class_init(ObjectClass *klass, void *data)
 374{
 375    DeviceClass *dc = DEVICE_CLASS(klass);
 376
 377    dc->reset = nrf51_timer_reset;
 378    dc->vmsd = &vmstate_nrf51_timer;
 379}
 380
 381static const TypeInfo nrf51_timer_info = {
 382    .name = TYPE_NRF51_TIMER,
 383    .parent = TYPE_SYS_BUS_DEVICE,
 384    .instance_size = sizeof(NRF51TimerState),
 385    .instance_init = nrf51_timer_init,
 386    .class_init = nrf51_timer_class_init
 387};
 388
 389static void nrf51_timer_register_types(void)
 390{
 391    type_register_static(&nrf51_timer_info);
 392}
 393
 394type_init(nrf51_timer_register_types)
 395