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