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