qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

nrf51_timer.c (11583B)


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