13bd88451SPaolo Bonzini /*
23bd88451SPaolo Bonzini * QEMU Sparc SLAVIO timer controller emulation
33bd88451SPaolo Bonzini *
43bd88451SPaolo Bonzini * Copyright (c) 2003-2005 Fabrice Bellard
53bd88451SPaolo Bonzini *
63bd88451SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
73bd88451SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
83bd88451SPaolo Bonzini * in the Software without restriction, including without limitation the rights
93bd88451SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
103bd88451SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
113bd88451SPaolo Bonzini * furnished to do so, subject to the following conditions:
123bd88451SPaolo Bonzini *
133bd88451SPaolo Bonzini * The above copyright notice and this permission notice shall be included in
143bd88451SPaolo Bonzini * all copies or substantial portions of the Software.
153bd88451SPaolo Bonzini *
163bd88451SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
173bd88451SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183bd88451SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
193bd88451SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
203bd88451SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
213bd88451SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
223bd88451SPaolo Bonzini * THE SOFTWARE.
233bd88451SPaolo Bonzini */
243bd88451SPaolo Bonzini
25282bc81eSPeter Maydell #include "qemu/osdep.h"
263bd88451SPaolo Bonzini #include "qemu/timer.h"
2764552b6bSMarkus Armbruster #include "hw/irq.h"
283bd88451SPaolo Bonzini #include "hw/ptimer.h"
29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
303bd88451SPaolo Bonzini #include "hw/sysbus.h"
31d6454270SMarkus Armbruster #include "migration/vmstate.h"
323bd88451SPaolo Bonzini #include "trace.h"
330b8fa32fSMarkus Armbruster #include "qemu/module.h"
34db1015e9SEduardo Habkost #include "qom/object.h"
353bd88451SPaolo Bonzini
363bd88451SPaolo Bonzini /*
373bd88451SPaolo Bonzini * Registers of hardware timer in sun4m.
383bd88451SPaolo Bonzini *
393bd88451SPaolo Bonzini * This is the timer/counter part of chip STP2001 (Slave I/O), also
403bd88451SPaolo Bonzini * produced as NCR89C105. See
413bd88451SPaolo Bonzini * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
423bd88451SPaolo Bonzini *
433bd88451SPaolo Bonzini * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
443bd88451SPaolo Bonzini * are zero. Bit 31 is 1 when count has been reached.
453bd88451SPaolo Bonzini *
463bd88451SPaolo Bonzini * Per-CPU timers interrupt local CPU, system timer uses normal
473bd88451SPaolo Bonzini * interrupt routing.
483bd88451SPaolo Bonzini *
493bd88451SPaolo Bonzini */
503bd88451SPaolo Bonzini
513bd88451SPaolo Bonzini #define MAX_CPUS 16
523bd88451SPaolo Bonzini
533bd88451SPaolo Bonzini typedef struct CPUTimerState {
543bd88451SPaolo Bonzini qemu_irq irq;
553bd88451SPaolo Bonzini ptimer_state *timer;
563bd88451SPaolo Bonzini uint32_t count, counthigh, reached;
573bd88451SPaolo Bonzini /* processor only */
58ead4cf04SMark Cave-Ayland uint32_t run;
593bd88451SPaolo Bonzini uint64_t limit;
603bd88451SPaolo Bonzini } CPUTimerState;
613bd88451SPaolo Bonzini
62c275471eSAndreas Färber #define TYPE_SLAVIO_TIMER "slavio_timer"
638063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_TIMERState, SLAVIO_TIMER)
64c275471eSAndreas Färber
65db1015e9SEduardo Habkost struct SLAVIO_TIMERState {
66c275471eSAndreas Färber SysBusDevice parent_obj;
67c275471eSAndreas Färber
683bd88451SPaolo Bonzini uint32_t num_cpus;
693bd88451SPaolo Bonzini uint32_t cputimer_mode;
703bd88451SPaolo Bonzini CPUTimerState cputimer[MAX_CPUS + 1];
71db1015e9SEduardo Habkost };
723bd88451SPaolo Bonzini
733bd88451SPaolo Bonzini typedef struct TimerContext {
743bd88451SPaolo Bonzini MemoryRegion iomem;
753bd88451SPaolo Bonzini SLAVIO_TIMERState *s;
763bd88451SPaolo Bonzini unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
773bd88451SPaolo Bonzini } TimerContext;
783bd88451SPaolo Bonzini
793bd88451SPaolo Bonzini #define SYS_TIMER_SIZE 0x14
803bd88451SPaolo Bonzini #define CPU_TIMER_SIZE 0x10
813bd88451SPaolo Bonzini
823bd88451SPaolo Bonzini #define TIMER_LIMIT 0
833bd88451SPaolo Bonzini #define TIMER_COUNTER 1
843bd88451SPaolo Bonzini #define TIMER_COUNTER_NORST 2
853bd88451SPaolo Bonzini #define TIMER_STATUS 3
863bd88451SPaolo Bonzini #define TIMER_MODE 4
873bd88451SPaolo Bonzini
883bd88451SPaolo Bonzini #define TIMER_COUNT_MASK32 0xfffffe00
893bd88451SPaolo Bonzini #define TIMER_LIMIT_MASK32 0x7fffffff
903bd88451SPaolo Bonzini #define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL
913bd88451SPaolo Bonzini #define TIMER_MAX_COUNT32 0x7ffffe00ULL
923bd88451SPaolo Bonzini #define TIMER_REACHED 0x80000000
933bd88451SPaolo Bonzini #define TIMER_PERIOD 500ULL // 500ns
943bd88451SPaolo Bonzini #define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
953bd88451SPaolo Bonzini #define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
963bd88451SPaolo Bonzini
slavio_timer_is_user(TimerContext * tc)973bd88451SPaolo Bonzini static int slavio_timer_is_user(TimerContext *tc)
983bd88451SPaolo Bonzini {
993bd88451SPaolo Bonzini SLAVIO_TIMERState *s = tc->s;
1003bd88451SPaolo Bonzini unsigned int timer_index = tc->timer_index;
1013bd88451SPaolo Bonzini
1023bd88451SPaolo Bonzini return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
1033bd88451SPaolo Bonzini }
1043bd88451SPaolo Bonzini
1053bd88451SPaolo Bonzini // Update count, set irq, update expire_time
1063bd88451SPaolo Bonzini // Convert from ptimer countdown units
slavio_timer_get_out(CPUTimerState * t)1073bd88451SPaolo Bonzini static void slavio_timer_get_out(CPUTimerState *t)
1083bd88451SPaolo Bonzini {
1093bd88451SPaolo Bonzini uint64_t count, limit;
1103bd88451SPaolo Bonzini
1113bd88451SPaolo Bonzini if (t->limit == 0) { /* free-run system or processor counter */
1123bd88451SPaolo Bonzini limit = TIMER_MAX_COUNT32;
1133bd88451SPaolo Bonzini } else {
1143bd88451SPaolo Bonzini limit = t->limit;
1153bd88451SPaolo Bonzini }
1163bd88451SPaolo Bonzini count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
1173bd88451SPaolo Bonzini
1183bd88451SPaolo Bonzini trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
1193bd88451SPaolo Bonzini t->count = count & TIMER_COUNT_MASK32;
1203bd88451SPaolo Bonzini t->counthigh = count >> 32;
1213bd88451SPaolo Bonzini }
1223bd88451SPaolo Bonzini
1233bd88451SPaolo Bonzini // timer callback
slavio_timer_irq(void * opaque)1243bd88451SPaolo Bonzini static void slavio_timer_irq(void *opaque)
1253bd88451SPaolo Bonzini {
1263bd88451SPaolo Bonzini TimerContext *tc = opaque;
1273bd88451SPaolo Bonzini SLAVIO_TIMERState *s = tc->s;
1283bd88451SPaolo Bonzini CPUTimerState *t = &s->cputimer[tc->timer_index];
1293bd88451SPaolo Bonzini
1303bd88451SPaolo Bonzini slavio_timer_get_out(t);
1313bd88451SPaolo Bonzini trace_slavio_timer_irq(t->counthigh, t->count);
1323bd88451SPaolo Bonzini /* if limit is 0 (free-run), there will be no match */
1333bd88451SPaolo Bonzini if (t->limit != 0) {
1343bd88451SPaolo Bonzini t->reached = TIMER_REACHED;
1353bd88451SPaolo Bonzini }
1363bd88451SPaolo Bonzini /* there is no interrupt if user timer or free-run */
1373bd88451SPaolo Bonzini if (!slavio_timer_is_user(tc) && t->limit != 0) {
1383bd88451SPaolo Bonzini qemu_irq_raise(t->irq);
1393bd88451SPaolo Bonzini }
1403bd88451SPaolo Bonzini }
1413bd88451SPaolo Bonzini
slavio_timer_mem_readl(void * opaque,hwaddr addr,unsigned size)1423bd88451SPaolo Bonzini static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
1433bd88451SPaolo Bonzini unsigned size)
1443bd88451SPaolo Bonzini {
1453bd88451SPaolo Bonzini TimerContext *tc = opaque;
1463bd88451SPaolo Bonzini SLAVIO_TIMERState *s = tc->s;
1473bd88451SPaolo Bonzini uint32_t saddr, ret;
1483bd88451SPaolo Bonzini unsigned int timer_index = tc->timer_index;
1493bd88451SPaolo Bonzini CPUTimerState *t = &s->cputimer[timer_index];
1503bd88451SPaolo Bonzini
1513bd88451SPaolo Bonzini saddr = addr >> 2;
1523bd88451SPaolo Bonzini switch (saddr) {
1533bd88451SPaolo Bonzini case TIMER_LIMIT:
1543bd88451SPaolo Bonzini // read limit (system counter mode) or read most signifying
1553bd88451SPaolo Bonzini // part of counter (user mode)
1563bd88451SPaolo Bonzini if (slavio_timer_is_user(tc)) {
1573bd88451SPaolo Bonzini // read user timer MSW
1583bd88451SPaolo Bonzini slavio_timer_get_out(t);
1593bd88451SPaolo Bonzini ret = t->counthigh | t->reached;
1603bd88451SPaolo Bonzini } else {
1613bd88451SPaolo Bonzini // read limit
1623bd88451SPaolo Bonzini // clear irq
1633bd88451SPaolo Bonzini qemu_irq_lower(t->irq);
1643bd88451SPaolo Bonzini t->reached = 0;
1653bd88451SPaolo Bonzini ret = t->limit & TIMER_LIMIT_MASK32;
1663bd88451SPaolo Bonzini }
1673bd88451SPaolo Bonzini break;
1683bd88451SPaolo Bonzini case TIMER_COUNTER:
1693bd88451SPaolo Bonzini // read counter and reached bit (system mode) or read lsbits
1703bd88451SPaolo Bonzini // of counter (user mode)
1713bd88451SPaolo Bonzini slavio_timer_get_out(t);
1723bd88451SPaolo Bonzini if (slavio_timer_is_user(tc)) { // read user timer LSW
1733bd88451SPaolo Bonzini ret = t->count & TIMER_MAX_COUNT64;
1743bd88451SPaolo Bonzini } else { // read limit
1753bd88451SPaolo Bonzini ret = (t->count & TIMER_MAX_COUNT32) |
1763bd88451SPaolo Bonzini t->reached;
1773bd88451SPaolo Bonzini }
1783bd88451SPaolo Bonzini break;
1793bd88451SPaolo Bonzini case TIMER_STATUS:
1803bd88451SPaolo Bonzini // only available in processor counter/timer
1813bd88451SPaolo Bonzini // read start/stop status
1823bd88451SPaolo Bonzini if (timer_index > 0) {
183ead4cf04SMark Cave-Ayland ret = t->run;
1843bd88451SPaolo Bonzini } else {
1853bd88451SPaolo Bonzini ret = 0;
1863bd88451SPaolo Bonzini }
1873bd88451SPaolo Bonzini break;
1883bd88451SPaolo Bonzini case TIMER_MODE:
1893bd88451SPaolo Bonzini // only available in system counter
1903bd88451SPaolo Bonzini // read user/system mode
1913bd88451SPaolo Bonzini ret = s->cputimer_mode;
1923bd88451SPaolo Bonzini break;
1933bd88451SPaolo Bonzini default:
1943bd88451SPaolo Bonzini trace_slavio_timer_mem_readl_invalid(addr);
1953bd88451SPaolo Bonzini ret = 0;
1963bd88451SPaolo Bonzini break;
1973bd88451SPaolo Bonzini }
1983bd88451SPaolo Bonzini trace_slavio_timer_mem_readl(addr, ret);
1993bd88451SPaolo Bonzini return ret;
2003bd88451SPaolo Bonzini }
2013bd88451SPaolo Bonzini
slavio_timer_mem_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size)2023bd88451SPaolo Bonzini static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
2033bd88451SPaolo Bonzini uint64_t val, unsigned size)
2043bd88451SPaolo Bonzini {
2053bd88451SPaolo Bonzini TimerContext *tc = opaque;
2063bd88451SPaolo Bonzini SLAVIO_TIMERState *s = tc->s;
2073bd88451SPaolo Bonzini uint32_t saddr;
2083bd88451SPaolo Bonzini unsigned int timer_index = tc->timer_index;
2093bd88451SPaolo Bonzini CPUTimerState *t = &s->cputimer[timer_index];
2103bd88451SPaolo Bonzini
2113bd88451SPaolo Bonzini trace_slavio_timer_mem_writel(addr, val);
2123bd88451SPaolo Bonzini saddr = addr >> 2;
2133bd88451SPaolo Bonzini switch (saddr) {
2143bd88451SPaolo Bonzini case TIMER_LIMIT:
2152ee62f32SPeter Maydell ptimer_transaction_begin(t->timer);
2163bd88451SPaolo Bonzini if (slavio_timer_is_user(tc)) {
2173bd88451SPaolo Bonzini uint64_t count;
2183bd88451SPaolo Bonzini
2193bd88451SPaolo Bonzini // set user counter MSW, reset counter
2203bd88451SPaolo Bonzini t->limit = TIMER_MAX_COUNT64;
2213bd88451SPaolo Bonzini t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
2223bd88451SPaolo Bonzini t->reached = 0;
2233bd88451SPaolo Bonzini count = ((uint64_t)t->counthigh << 32) | t->count;
2243bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_limit(timer_index, count);
2253bd88451SPaolo Bonzini ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
2263bd88451SPaolo Bonzini } else {
2273bd88451SPaolo Bonzini // set limit, reset counter
2283bd88451SPaolo Bonzini qemu_irq_lower(t->irq);
2293bd88451SPaolo Bonzini t->limit = val & TIMER_MAX_COUNT32;
2303bd88451SPaolo Bonzini if (t->limit == 0) { /* free-run */
2313bd88451SPaolo Bonzini ptimer_set_limit(t->timer,
2323bd88451SPaolo Bonzini LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
2333bd88451SPaolo Bonzini } else {
2343bd88451SPaolo Bonzini ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
2353bd88451SPaolo Bonzini }
2363bd88451SPaolo Bonzini }
2372ee62f32SPeter Maydell ptimer_transaction_commit(t->timer);
2383bd88451SPaolo Bonzini break;
2393bd88451SPaolo Bonzini case TIMER_COUNTER:
2403bd88451SPaolo Bonzini if (slavio_timer_is_user(tc)) {
2413bd88451SPaolo Bonzini uint64_t count;
2423bd88451SPaolo Bonzini
2433bd88451SPaolo Bonzini // set user counter LSW, reset counter
2443bd88451SPaolo Bonzini t->limit = TIMER_MAX_COUNT64;
2453bd88451SPaolo Bonzini t->count = val & TIMER_MAX_COUNT64;
2463bd88451SPaolo Bonzini t->reached = 0;
2473bd88451SPaolo Bonzini count = ((uint64_t)t->counthigh) << 32 | t->count;
2483bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_limit(timer_index, count);
2492ee62f32SPeter Maydell ptimer_transaction_begin(t->timer);
2503bd88451SPaolo Bonzini ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
2512ee62f32SPeter Maydell ptimer_transaction_commit(t->timer);
2523bd88451SPaolo Bonzini } else {
2533bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_counter_invalid();
2543bd88451SPaolo Bonzini }
2553bd88451SPaolo Bonzini break;
2563bd88451SPaolo Bonzini case TIMER_COUNTER_NORST:
2573bd88451SPaolo Bonzini // set limit without resetting counter
2583bd88451SPaolo Bonzini t->limit = val & TIMER_MAX_COUNT32;
2592ee62f32SPeter Maydell ptimer_transaction_begin(t->timer);
2603bd88451SPaolo Bonzini if (t->limit == 0) { /* free-run */
2613bd88451SPaolo Bonzini ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
2623bd88451SPaolo Bonzini } else {
2633bd88451SPaolo Bonzini ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
2643bd88451SPaolo Bonzini }
2652ee62f32SPeter Maydell ptimer_transaction_commit(t->timer);
2663bd88451SPaolo Bonzini break;
2673bd88451SPaolo Bonzini case TIMER_STATUS:
2682ee62f32SPeter Maydell ptimer_transaction_begin(t->timer);
2693bd88451SPaolo Bonzini if (slavio_timer_is_user(tc)) {
2703bd88451SPaolo Bonzini // start/stop user counter
271ead4cf04SMark Cave-Ayland if (val & 1) {
2723bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_status_start(timer_index);
2733bd88451SPaolo Bonzini ptimer_run(t->timer, 0);
274ead4cf04SMark Cave-Ayland } else {
2753bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_status_stop(timer_index);
2763bd88451SPaolo Bonzini ptimer_stop(t->timer);
2773bd88451SPaolo Bonzini }
2783bd88451SPaolo Bonzini }
279ead4cf04SMark Cave-Ayland t->run = val & 1;
2802ee62f32SPeter Maydell ptimer_transaction_commit(t->timer);
2813bd88451SPaolo Bonzini break;
2823bd88451SPaolo Bonzini case TIMER_MODE:
2833bd88451SPaolo Bonzini if (timer_index == 0) {
2843bd88451SPaolo Bonzini unsigned int i;
2853bd88451SPaolo Bonzini
2863bd88451SPaolo Bonzini for (i = 0; i < s->num_cpus; i++) {
2873bd88451SPaolo Bonzini unsigned int processor = 1 << i;
2883bd88451SPaolo Bonzini CPUTimerState *curr_timer = &s->cputimer[i + 1];
2893bd88451SPaolo Bonzini
2902ee62f32SPeter Maydell ptimer_transaction_begin(curr_timer->timer);
2913bd88451SPaolo Bonzini // check for a change in timer mode for this processor
2923bd88451SPaolo Bonzini if ((val & processor) != (s->cputimer_mode & processor)) {
2933bd88451SPaolo Bonzini if (val & processor) { // counter -> user timer
2943bd88451SPaolo Bonzini qemu_irq_lower(curr_timer->irq);
2953bd88451SPaolo Bonzini // counters are always running
296ead4cf04SMark Cave-Ayland if (!curr_timer->run) {
2973bd88451SPaolo Bonzini ptimer_stop(curr_timer->timer);
298ead4cf04SMark Cave-Ayland }
2993bd88451SPaolo Bonzini // user timer limit is always the same
3003bd88451SPaolo Bonzini curr_timer->limit = TIMER_MAX_COUNT64;
3013bd88451SPaolo Bonzini ptimer_set_limit(curr_timer->timer,
3023bd88451SPaolo Bonzini LIMIT_TO_PERIODS(curr_timer->limit),
3033bd88451SPaolo Bonzini 1);
3043bd88451SPaolo Bonzini // set this processors user timer bit in config
3053bd88451SPaolo Bonzini // register
3063bd88451SPaolo Bonzini s->cputimer_mode |= processor;
3073bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_mode_user(timer_index);
3083bd88451SPaolo Bonzini } else { // user timer -> counter
3093bd88451SPaolo Bonzini // start the counter
3103bd88451SPaolo Bonzini ptimer_run(curr_timer->timer, 0);
3113bd88451SPaolo Bonzini // clear this processors user timer bit in config
3123bd88451SPaolo Bonzini // register
3133bd88451SPaolo Bonzini s->cputimer_mode &= ~processor;
3143bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_mode_counter(timer_index);
3153bd88451SPaolo Bonzini }
3163bd88451SPaolo Bonzini }
3172ee62f32SPeter Maydell ptimer_transaction_commit(curr_timer->timer);
3183bd88451SPaolo Bonzini }
3193bd88451SPaolo Bonzini } else {
3203bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_mode_invalid();
3213bd88451SPaolo Bonzini }
3223bd88451SPaolo Bonzini break;
3233bd88451SPaolo Bonzini default:
3243bd88451SPaolo Bonzini trace_slavio_timer_mem_writel_invalid(addr);
3253bd88451SPaolo Bonzini break;
3263bd88451SPaolo Bonzini }
3273bd88451SPaolo Bonzini }
3283bd88451SPaolo Bonzini
3293bd88451SPaolo Bonzini static const MemoryRegionOps slavio_timer_mem_ops = {
3303bd88451SPaolo Bonzini .read = slavio_timer_mem_readl,
3313bd88451SPaolo Bonzini .write = slavio_timer_mem_writel,
3323bd88451SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
3333bd88451SPaolo Bonzini .valid = {
3343bd88451SPaolo Bonzini .min_access_size = 4,
33562a9b228SPhilippe Mathieu-Daudé .max_access_size = 8,
33662a9b228SPhilippe Mathieu-Daudé },
33762a9b228SPhilippe Mathieu-Daudé .impl = {
33862a9b228SPhilippe Mathieu-Daudé .min_access_size = 4,
3393bd88451SPaolo Bonzini .max_access_size = 4,
3403bd88451SPaolo Bonzini },
3413bd88451SPaolo Bonzini };
3423bd88451SPaolo Bonzini
3433bd88451SPaolo Bonzini static const VMStateDescription vmstate_timer = {
3443bd88451SPaolo Bonzini .name ="timer",
3453bd88451SPaolo Bonzini .version_id = 3,
3463bd88451SPaolo Bonzini .minimum_version_id = 3,
347ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
3483bd88451SPaolo Bonzini VMSTATE_UINT64(limit, CPUTimerState),
3493bd88451SPaolo Bonzini VMSTATE_UINT32(count, CPUTimerState),
3503bd88451SPaolo Bonzini VMSTATE_UINT32(counthigh, CPUTimerState),
3513bd88451SPaolo Bonzini VMSTATE_UINT32(reached, CPUTimerState),
352ead4cf04SMark Cave-Ayland VMSTATE_UINT32(run , CPUTimerState),
3533bd88451SPaolo Bonzini VMSTATE_PTIMER(timer, CPUTimerState),
3543bd88451SPaolo Bonzini VMSTATE_END_OF_LIST()
3553bd88451SPaolo Bonzini }
3563bd88451SPaolo Bonzini };
3573bd88451SPaolo Bonzini
3583bd88451SPaolo Bonzini static const VMStateDescription vmstate_slavio_timer = {
3593bd88451SPaolo Bonzini .name ="slavio_timer",
3603bd88451SPaolo Bonzini .version_id = 3,
3613bd88451SPaolo Bonzini .minimum_version_id = 3,
362ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
3633bd88451SPaolo Bonzini VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
3643bd88451SPaolo Bonzini vmstate_timer, CPUTimerState),
3653bd88451SPaolo Bonzini VMSTATE_END_OF_LIST()
3663bd88451SPaolo Bonzini }
3673bd88451SPaolo Bonzini };
3683bd88451SPaolo Bonzini
slavio_timer_reset(DeviceState * d)3693bd88451SPaolo Bonzini static void slavio_timer_reset(DeviceState *d)
3703bd88451SPaolo Bonzini {
371c275471eSAndreas Färber SLAVIO_TIMERState *s = SLAVIO_TIMER(d);
3723bd88451SPaolo Bonzini unsigned int i;
3733bd88451SPaolo Bonzini CPUTimerState *curr_timer;
3743bd88451SPaolo Bonzini
3753bd88451SPaolo Bonzini for (i = 0; i <= MAX_CPUS; i++) {
3763bd88451SPaolo Bonzini curr_timer = &s->cputimer[i];
3773bd88451SPaolo Bonzini curr_timer->limit = 0;
3783bd88451SPaolo Bonzini curr_timer->count = 0;
3793bd88451SPaolo Bonzini curr_timer->reached = 0;
3803bd88451SPaolo Bonzini if (i <= s->num_cpus) {
3812ee62f32SPeter Maydell ptimer_transaction_begin(curr_timer->timer);
3823bd88451SPaolo Bonzini ptimer_set_limit(curr_timer->timer,
3833bd88451SPaolo Bonzini LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
3843bd88451SPaolo Bonzini ptimer_run(curr_timer->timer, 0);
385ead4cf04SMark Cave-Ayland curr_timer->run = 1;
3862ee62f32SPeter Maydell ptimer_transaction_commit(curr_timer->timer);
3873bd88451SPaolo Bonzini }
3883bd88451SPaolo Bonzini }
3893bd88451SPaolo Bonzini s->cputimer_mode = 0;
3903bd88451SPaolo Bonzini }
3913bd88451SPaolo Bonzini
slavio_timer_init(Object * obj)3924410b94cSxiaoqiang zhao static void slavio_timer_init(Object *obj)
3933bd88451SPaolo Bonzini {
3944410b94cSxiaoqiang zhao SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
3954410b94cSxiaoqiang zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj);
3963bd88451SPaolo Bonzini unsigned int i;
3973bd88451SPaolo Bonzini TimerContext *tc;
3983bd88451SPaolo Bonzini
3993bd88451SPaolo Bonzini for (i = 0; i <= MAX_CPUS; i++) {
4003bd88451SPaolo Bonzini uint64_t size;
4013bd88451SPaolo Bonzini char timer_name[20];
4023bd88451SPaolo Bonzini
403b21e2380SMarkus Armbruster tc = g_new0(TimerContext, 1);
4043bd88451SPaolo Bonzini tc->s = s;
4053bd88451SPaolo Bonzini tc->timer_index = i;
4063bd88451SPaolo Bonzini
4072ee62f32SPeter Maydell s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc,
4089598c1bbSPeter Maydell PTIMER_POLICY_LEGACY);
4092ee62f32SPeter Maydell ptimer_transaction_begin(s->cputimer[i].timer);
4103bd88451SPaolo Bonzini ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
4112ee62f32SPeter Maydell ptimer_transaction_commit(s->cputimer[i].timer);
4123bd88451SPaolo Bonzini
4133bd88451SPaolo Bonzini size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
4143bd88451SPaolo Bonzini snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
4154410b94cSxiaoqiang zhao memory_region_init_io(&tc->iomem, obj, &slavio_timer_mem_ops, tc,
4163bd88451SPaolo Bonzini timer_name, size);
4173bd88451SPaolo Bonzini sysbus_init_mmio(dev, &tc->iomem);
4183bd88451SPaolo Bonzini
4193bd88451SPaolo Bonzini sysbus_init_irq(dev, &s->cputimer[i].irq);
4203bd88451SPaolo Bonzini }
4213bd88451SPaolo Bonzini }
4223bd88451SPaolo Bonzini
4233bd88451SPaolo Bonzini static Property slavio_timer_properties[] = {
4243bd88451SPaolo Bonzini DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
4253bd88451SPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
4263bd88451SPaolo Bonzini };
4273bd88451SPaolo Bonzini
slavio_timer_class_init(ObjectClass * klass,void * data)4283bd88451SPaolo Bonzini static void slavio_timer_class_init(ObjectClass *klass, void *data)
4293bd88451SPaolo Bonzini {
4303bd88451SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
4313bd88451SPaolo Bonzini
432*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, slavio_timer_reset);
4333bd88451SPaolo Bonzini dc->vmsd = &vmstate_slavio_timer;
4344f67d30bSMarc-André Lureau device_class_set_props(dc, slavio_timer_properties);
4353bd88451SPaolo Bonzini }
4363bd88451SPaolo Bonzini
4373bd88451SPaolo Bonzini static const TypeInfo slavio_timer_info = {
438c275471eSAndreas Färber .name = TYPE_SLAVIO_TIMER,
4393bd88451SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
4403bd88451SPaolo Bonzini .instance_size = sizeof(SLAVIO_TIMERState),
4414410b94cSxiaoqiang zhao .instance_init = slavio_timer_init,
4423bd88451SPaolo Bonzini .class_init = slavio_timer_class_init,
4433bd88451SPaolo Bonzini };
4443bd88451SPaolo Bonzini
slavio_timer_register_types(void)4453bd88451SPaolo Bonzini static void slavio_timer_register_types(void)
4463bd88451SPaolo Bonzini {
4473bd88451SPaolo Bonzini type_register_static(&slavio_timer_info);
4483bd88451SPaolo Bonzini }
4493bd88451SPaolo Bonzini
4503bd88451SPaolo Bonzini type_init(slavio_timer_register_types)
451