13bd88451SPaolo Bonzini /*
23bd88451SPaolo Bonzini * QEMU GRLIB GPTimer Emulator
33bd88451SPaolo Bonzini *
4f432962eSClément Chigot * SPDX-License-Identifier: MIT
5f432962eSClément Chigot *
6f432962eSClément Chigot * Copyright (c) 2010-2024 AdaCore
73bd88451SPaolo Bonzini *
83bd88451SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
93bd88451SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
103bd88451SPaolo Bonzini * in the Software without restriction, including without limitation the rights
113bd88451SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
123bd88451SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
133bd88451SPaolo Bonzini * furnished to do so, subject to the following conditions:
143bd88451SPaolo Bonzini *
153bd88451SPaolo Bonzini * The above copyright notice and this permission notice shall be included in
163bd88451SPaolo Bonzini * all copies or substantial portions of the Software.
173bd88451SPaolo Bonzini *
183bd88451SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
193bd88451SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
203bd88451SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
213bd88451SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
223bd88451SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
233bd88451SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
243bd88451SPaolo Bonzini * THE SOFTWARE.
253bd88451SPaolo Bonzini */
263bd88451SPaolo Bonzini
27db5ebe5fSPeter Maydell #include "qemu/osdep.h"
28f432962eSClément Chigot #include "hw/timer/grlib_gptimer.h"
293bd88451SPaolo Bonzini #include "hw/sysbus.h"
303bd88451SPaolo Bonzini #include "qemu/timer.h"
3164552b6bSMarkus Armbruster #include "hw/irq.h"
323bd88451SPaolo Bonzini #include "hw/ptimer.h"
33a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
340b8fa32fSMarkus Armbruster #include "qemu/module.h"
353bd88451SPaolo Bonzini
363bd88451SPaolo Bonzini #include "trace.h"
37db1015e9SEduardo Habkost #include "qom/object.h"
383bd88451SPaolo Bonzini
393bd88451SPaolo Bonzini #define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */
403bd88451SPaolo Bonzini #define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */
413bd88451SPaolo Bonzini
423bd88451SPaolo Bonzini #define GPTIMER_MAX_TIMERS 8
433bd88451SPaolo Bonzini
443bd88451SPaolo Bonzini /* GPTimer Config register fields */
453bd88451SPaolo Bonzini #define GPTIMER_ENABLE (1 << 0)
463bd88451SPaolo Bonzini #define GPTIMER_RESTART (1 << 1)
473bd88451SPaolo Bonzini #define GPTIMER_LOAD (1 << 2)
483bd88451SPaolo Bonzini #define GPTIMER_INT_ENABLE (1 << 3)
493bd88451SPaolo Bonzini #define GPTIMER_INT_PENDING (1 << 4)
503bd88451SPaolo Bonzini #define GPTIMER_CHAIN (1 << 5) /* Not supported */
513bd88451SPaolo Bonzini #define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */
523bd88451SPaolo Bonzini
533bd88451SPaolo Bonzini /* Memory mapped register offsets */
543bd88451SPaolo Bonzini #define SCALER_OFFSET 0x00
553bd88451SPaolo Bonzini #define SCALER_RELOAD_OFFSET 0x04
563bd88451SPaolo Bonzini #define CONFIG_OFFSET 0x08
573bd88451SPaolo Bonzini #define COUNTER_OFFSET 0x00
583bd88451SPaolo Bonzini #define COUNTER_RELOAD_OFFSET 0x04
593bd88451SPaolo Bonzini #define TIMER_BASE 0x10
603bd88451SPaolo Bonzini
618063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(GPTimerUnit, GRLIB_GPTIMER)
62541ab55fSAndreas Färber
633bd88451SPaolo Bonzini typedef struct GPTimer GPTimer;
643bd88451SPaolo Bonzini
653bd88451SPaolo Bonzini struct GPTimer {
663bd88451SPaolo Bonzini struct ptimer_state *ptimer;
673bd88451SPaolo Bonzini
683bd88451SPaolo Bonzini qemu_irq irq;
693bd88451SPaolo Bonzini int id;
703bd88451SPaolo Bonzini GPTimerUnit *unit;
713bd88451SPaolo Bonzini
723bd88451SPaolo Bonzini /* registers */
733bd88451SPaolo Bonzini uint32_t counter;
743bd88451SPaolo Bonzini uint32_t reload;
753bd88451SPaolo Bonzini uint32_t config;
763bd88451SPaolo Bonzini };
773bd88451SPaolo Bonzini
783bd88451SPaolo Bonzini struct GPTimerUnit {
79541ab55fSAndreas Färber SysBusDevice parent_obj;
80541ab55fSAndreas Färber
813bd88451SPaolo Bonzini MemoryRegion iomem;
823bd88451SPaolo Bonzini
833bd88451SPaolo Bonzini uint32_t nr_timers; /* Number of timers available */
843bd88451SPaolo Bonzini uint32_t freq_hz; /* System frequency */
853bd88451SPaolo Bonzini uint32_t irq_line; /* Base irq line */
863bd88451SPaolo Bonzini
873bd88451SPaolo Bonzini GPTimer *timers;
883bd88451SPaolo Bonzini
893bd88451SPaolo Bonzini /* registers */
903bd88451SPaolo Bonzini uint32_t scaler;
913bd88451SPaolo Bonzini uint32_t reload;
923bd88451SPaolo Bonzini uint32_t config;
933bd88451SPaolo Bonzini };
943bd88451SPaolo Bonzini
grlib_gptimer_tx_begin(GPTimer * timer)95663e475fSPeter Maydell static void grlib_gptimer_tx_begin(GPTimer *timer)
96663e475fSPeter Maydell {
97663e475fSPeter Maydell ptimer_transaction_begin(timer->ptimer);
98663e475fSPeter Maydell }
99663e475fSPeter Maydell
grlib_gptimer_tx_commit(GPTimer * timer)100663e475fSPeter Maydell static void grlib_gptimer_tx_commit(GPTimer *timer)
101663e475fSPeter Maydell {
102663e475fSPeter Maydell ptimer_transaction_commit(timer->ptimer);
103663e475fSPeter Maydell }
104663e475fSPeter Maydell
105663e475fSPeter Maydell /* Must be called within grlib_gptimer_tx_begin/commit block */
grlib_gptimer_enable(GPTimer * timer)1063bd88451SPaolo Bonzini static void grlib_gptimer_enable(GPTimer *timer)
1073bd88451SPaolo Bonzini {
1083bd88451SPaolo Bonzini assert(timer != NULL);
1093bd88451SPaolo Bonzini
1103bd88451SPaolo Bonzini
1113bd88451SPaolo Bonzini ptimer_stop(timer->ptimer);
1123bd88451SPaolo Bonzini
1133bd88451SPaolo Bonzini if (!(timer->config & GPTIMER_ENABLE)) {
1143bd88451SPaolo Bonzini /* Timer disabled */
1153bd88451SPaolo Bonzini trace_grlib_gptimer_disabled(timer->id, timer->config);
1163bd88451SPaolo Bonzini return;
1173bd88451SPaolo Bonzini }
1183bd88451SPaolo Bonzini
1193bd88451SPaolo Bonzini /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
1203bd88451SPaolo Bonzini underflow. Set count + 1 to simulate the GPTimer behavior. */
1213bd88451SPaolo Bonzini
1229d5614d5SSebastian Huber trace_grlib_gptimer_enable(timer->id, timer->counter);
1233bd88451SPaolo Bonzini
1249d5614d5SSebastian Huber ptimer_set_count(timer->ptimer, (uint64_t)timer->counter + 1);
1253bd88451SPaolo Bonzini ptimer_run(timer->ptimer, 1);
1263bd88451SPaolo Bonzini }
1273bd88451SPaolo Bonzini
128663e475fSPeter Maydell /* Must be called within grlib_gptimer_tx_begin/commit block */
grlib_gptimer_restart(GPTimer * timer)1293bd88451SPaolo Bonzini static void grlib_gptimer_restart(GPTimer *timer)
1303bd88451SPaolo Bonzini {
1313bd88451SPaolo Bonzini assert(timer != NULL);
1323bd88451SPaolo Bonzini
1333bd88451SPaolo Bonzini trace_grlib_gptimer_restart(timer->id, timer->reload);
1343bd88451SPaolo Bonzini
1353bd88451SPaolo Bonzini timer->counter = timer->reload;
1363bd88451SPaolo Bonzini grlib_gptimer_enable(timer);
1373bd88451SPaolo Bonzini }
1383bd88451SPaolo Bonzini
grlib_gptimer_set_scaler(GPTimerUnit * unit,uint32_t scaler)1393bd88451SPaolo Bonzini static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
1403bd88451SPaolo Bonzini {
1413bd88451SPaolo Bonzini int i = 0;
1423bd88451SPaolo Bonzini uint32_t value = 0;
1433bd88451SPaolo Bonzini
1443bd88451SPaolo Bonzini assert(unit != NULL);
1453bd88451SPaolo Bonzini
1463bd88451SPaolo Bonzini if (scaler > 0) {
1473bd88451SPaolo Bonzini value = unit->freq_hz / (scaler + 1);
1483bd88451SPaolo Bonzini } else {
1493bd88451SPaolo Bonzini value = unit->freq_hz;
1503bd88451SPaolo Bonzini }
1513bd88451SPaolo Bonzini
1523bd88451SPaolo Bonzini trace_grlib_gptimer_set_scaler(scaler, value);
1533bd88451SPaolo Bonzini
1543bd88451SPaolo Bonzini for (i = 0; i < unit->nr_timers; i++) {
155663e475fSPeter Maydell ptimer_transaction_begin(unit->timers[i].ptimer);
1563bd88451SPaolo Bonzini ptimer_set_freq(unit->timers[i].ptimer, value);
157663e475fSPeter Maydell ptimer_transaction_commit(unit->timers[i].ptimer);
1583bd88451SPaolo Bonzini }
1593bd88451SPaolo Bonzini }
1603bd88451SPaolo Bonzini
grlib_gptimer_hit(void * opaque)1613bd88451SPaolo Bonzini static void grlib_gptimer_hit(void *opaque)
1623bd88451SPaolo Bonzini {
1633bd88451SPaolo Bonzini GPTimer *timer = opaque;
1643bd88451SPaolo Bonzini assert(timer != NULL);
1653bd88451SPaolo Bonzini
1663bd88451SPaolo Bonzini trace_grlib_gptimer_hit(timer->id);
1673bd88451SPaolo Bonzini
1683bd88451SPaolo Bonzini /* Timer expired */
1693bd88451SPaolo Bonzini
1703bd88451SPaolo Bonzini if (timer->config & GPTIMER_INT_ENABLE) {
1713bd88451SPaolo Bonzini /* Set the pending bit (only unset by write in the config register) */
1723bd88451SPaolo Bonzini timer->config |= GPTIMER_INT_PENDING;
1733bd88451SPaolo Bonzini qemu_irq_pulse(timer->irq);
1743bd88451SPaolo Bonzini }
1753bd88451SPaolo Bonzini
1763bd88451SPaolo Bonzini if (timer->config & GPTIMER_RESTART) {
1773bd88451SPaolo Bonzini grlib_gptimer_restart(timer);
1783bd88451SPaolo Bonzini }
1793bd88451SPaolo Bonzini }
1803bd88451SPaolo Bonzini
grlib_gptimer_read(void * opaque,hwaddr addr,unsigned size)1813bd88451SPaolo Bonzini static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
1823bd88451SPaolo Bonzini unsigned size)
1833bd88451SPaolo Bonzini {
1843bd88451SPaolo Bonzini GPTimerUnit *unit = opaque;
1853bd88451SPaolo Bonzini hwaddr timer_addr;
1863bd88451SPaolo Bonzini int id;
1873bd88451SPaolo Bonzini uint32_t value = 0;
1883bd88451SPaolo Bonzini
1893bd88451SPaolo Bonzini addr &= 0xff;
1903bd88451SPaolo Bonzini
1913bd88451SPaolo Bonzini /* Unit registers */
1923bd88451SPaolo Bonzini switch (addr) {
1933bd88451SPaolo Bonzini case SCALER_OFFSET:
1943bd88451SPaolo Bonzini trace_grlib_gptimer_readl(-1, addr, unit->scaler);
1953bd88451SPaolo Bonzini return unit->scaler;
1963bd88451SPaolo Bonzini
1973bd88451SPaolo Bonzini case SCALER_RELOAD_OFFSET:
1983bd88451SPaolo Bonzini trace_grlib_gptimer_readl(-1, addr, unit->reload);
1993bd88451SPaolo Bonzini return unit->reload;
2003bd88451SPaolo Bonzini
2013bd88451SPaolo Bonzini case CONFIG_OFFSET:
2023bd88451SPaolo Bonzini trace_grlib_gptimer_readl(-1, addr, unit->config);
2033bd88451SPaolo Bonzini return unit->config;
2043bd88451SPaolo Bonzini
2053bd88451SPaolo Bonzini default:
2063bd88451SPaolo Bonzini break;
2073bd88451SPaolo Bonzini }
2083bd88451SPaolo Bonzini
2093bd88451SPaolo Bonzini timer_addr = (addr % TIMER_BASE);
2103bd88451SPaolo Bonzini id = (addr - TIMER_BASE) / TIMER_BASE;
2113bd88451SPaolo Bonzini
2123bd88451SPaolo Bonzini if (id >= 0 && id < unit->nr_timers) {
2133bd88451SPaolo Bonzini
2143bd88451SPaolo Bonzini /* GPTimer registers */
2153bd88451SPaolo Bonzini switch (timer_addr) {
2163bd88451SPaolo Bonzini case COUNTER_OFFSET:
2173bd88451SPaolo Bonzini value = ptimer_get_count(unit->timers[id].ptimer);
2183bd88451SPaolo Bonzini trace_grlib_gptimer_readl(id, addr, value);
2193bd88451SPaolo Bonzini return value;
2203bd88451SPaolo Bonzini
2213bd88451SPaolo Bonzini case COUNTER_RELOAD_OFFSET:
2223bd88451SPaolo Bonzini value = unit->timers[id].reload;
2233bd88451SPaolo Bonzini trace_grlib_gptimer_readl(id, addr, value);
2243bd88451SPaolo Bonzini return value;
2253bd88451SPaolo Bonzini
2263bd88451SPaolo Bonzini case CONFIG_OFFSET:
2273bd88451SPaolo Bonzini trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
2283bd88451SPaolo Bonzini return unit->timers[id].config;
2293bd88451SPaolo Bonzini
2303bd88451SPaolo Bonzini default:
2313bd88451SPaolo Bonzini break;
2323bd88451SPaolo Bonzini }
2333bd88451SPaolo Bonzini
2343bd88451SPaolo Bonzini }
2353bd88451SPaolo Bonzini
2363bd88451SPaolo Bonzini trace_grlib_gptimer_readl(-1, addr, 0);
2373bd88451SPaolo Bonzini return 0;
2383bd88451SPaolo Bonzini }
2393bd88451SPaolo Bonzini
grlib_gptimer_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)2403bd88451SPaolo Bonzini static void grlib_gptimer_write(void *opaque, hwaddr addr,
2413bd88451SPaolo Bonzini uint64_t value, unsigned size)
2423bd88451SPaolo Bonzini {
2433bd88451SPaolo Bonzini GPTimerUnit *unit = opaque;
2443bd88451SPaolo Bonzini hwaddr timer_addr;
2453bd88451SPaolo Bonzini int id;
2463bd88451SPaolo Bonzini
2473bd88451SPaolo Bonzini addr &= 0xff;
2483bd88451SPaolo Bonzini
2493bd88451SPaolo Bonzini /* Unit registers */
2503bd88451SPaolo Bonzini switch (addr) {
2513bd88451SPaolo Bonzini case SCALER_OFFSET:
2523bd88451SPaolo Bonzini value &= 0xFFFF; /* clean up the value */
2533bd88451SPaolo Bonzini unit->scaler = value;
2543bd88451SPaolo Bonzini trace_grlib_gptimer_writel(-1, addr, unit->scaler);
2553bd88451SPaolo Bonzini return;
2563bd88451SPaolo Bonzini
2573bd88451SPaolo Bonzini case SCALER_RELOAD_OFFSET:
2583bd88451SPaolo Bonzini value &= 0xFFFF; /* clean up the value */
2593bd88451SPaolo Bonzini unit->reload = value;
2603bd88451SPaolo Bonzini trace_grlib_gptimer_writel(-1, addr, unit->reload);
2613bd88451SPaolo Bonzini grlib_gptimer_set_scaler(unit, value);
2623bd88451SPaolo Bonzini return;
2633bd88451SPaolo Bonzini
2643bd88451SPaolo Bonzini case CONFIG_OFFSET:
2653bd88451SPaolo Bonzini /* Read Only (disable timer freeze not supported) */
2663bd88451SPaolo Bonzini trace_grlib_gptimer_writel(-1, addr, 0);
2673bd88451SPaolo Bonzini return;
2683bd88451SPaolo Bonzini
2693bd88451SPaolo Bonzini default:
2703bd88451SPaolo Bonzini break;
2713bd88451SPaolo Bonzini }
2723bd88451SPaolo Bonzini
2733bd88451SPaolo Bonzini timer_addr = (addr % TIMER_BASE);
2743bd88451SPaolo Bonzini id = (addr - TIMER_BASE) / TIMER_BASE;
2753bd88451SPaolo Bonzini
2763bd88451SPaolo Bonzini if (id >= 0 && id < unit->nr_timers) {
2773bd88451SPaolo Bonzini
2783bd88451SPaolo Bonzini /* GPTimer registers */
2793bd88451SPaolo Bonzini switch (timer_addr) {
2803bd88451SPaolo Bonzini case COUNTER_OFFSET:
2813bd88451SPaolo Bonzini trace_grlib_gptimer_writel(id, addr, value);
282663e475fSPeter Maydell grlib_gptimer_tx_begin(&unit->timers[id]);
2833bd88451SPaolo Bonzini unit->timers[id].counter = value;
2843bd88451SPaolo Bonzini grlib_gptimer_enable(&unit->timers[id]);
285663e475fSPeter Maydell grlib_gptimer_tx_commit(&unit->timers[id]);
2863bd88451SPaolo Bonzini return;
2873bd88451SPaolo Bonzini
2883bd88451SPaolo Bonzini case COUNTER_RELOAD_OFFSET:
2893bd88451SPaolo Bonzini trace_grlib_gptimer_writel(id, addr, value);
2903bd88451SPaolo Bonzini unit->timers[id].reload = value;
2913bd88451SPaolo Bonzini return;
2923bd88451SPaolo Bonzini
2933bd88451SPaolo Bonzini case CONFIG_OFFSET:
2943bd88451SPaolo Bonzini trace_grlib_gptimer_writel(id, addr, value);
2953bd88451SPaolo Bonzini
2963bd88451SPaolo Bonzini if (value & GPTIMER_INT_PENDING) {
2973bd88451SPaolo Bonzini /* clear pending bit */
2983bd88451SPaolo Bonzini value &= ~GPTIMER_INT_PENDING;
2993bd88451SPaolo Bonzini } else {
3003bd88451SPaolo Bonzini /* keep pending bit */
3013bd88451SPaolo Bonzini value |= unit->timers[id].config & GPTIMER_INT_PENDING;
3023bd88451SPaolo Bonzini }
3033bd88451SPaolo Bonzini
3043bd88451SPaolo Bonzini unit->timers[id].config = value;
3053bd88451SPaolo Bonzini
3063bd88451SPaolo Bonzini /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
3073bd88451SPaolo Bonzini bits are present, we just have to call restart. */
3083bd88451SPaolo Bonzini
309663e475fSPeter Maydell grlib_gptimer_tx_begin(&unit->timers[id]);
3103bd88451SPaolo Bonzini if (value & GPTIMER_LOAD) {
3113bd88451SPaolo Bonzini grlib_gptimer_restart(&unit->timers[id]);
3123bd88451SPaolo Bonzini } else if (value & GPTIMER_ENABLE) {
3133bd88451SPaolo Bonzini grlib_gptimer_enable(&unit->timers[id]);
3143bd88451SPaolo Bonzini }
3153bd88451SPaolo Bonzini
3163bd88451SPaolo Bonzini /* These fields must always be read as 0 */
3173bd88451SPaolo Bonzini value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
3183bd88451SPaolo Bonzini
3193bd88451SPaolo Bonzini unit->timers[id].config = value;
320663e475fSPeter Maydell grlib_gptimer_tx_commit(&unit->timers[id]);
3213bd88451SPaolo Bonzini return;
3223bd88451SPaolo Bonzini
3233bd88451SPaolo Bonzini default:
3243bd88451SPaolo Bonzini break;
3253bd88451SPaolo Bonzini }
3263bd88451SPaolo Bonzini
3273bd88451SPaolo Bonzini }
3283bd88451SPaolo Bonzini
3293bd88451SPaolo Bonzini trace_grlib_gptimer_writel(-1, addr, value);
3303bd88451SPaolo Bonzini }
3313bd88451SPaolo Bonzini
3323bd88451SPaolo Bonzini static const MemoryRegionOps grlib_gptimer_ops = {
3333bd88451SPaolo Bonzini .read = grlib_gptimer_read,
3343bd88451SPaolo Bonzini .write = grlib_gptimer_write,
3353bd88451SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
3363bd88451SPaolo Bonzini .valid = {
3373bd88451SPaolo Bonzini .min_access_size = 4,
3383bd88451SPaolo Bonzini .max_access_size = 4,
3393bd88451SPaolo Bonzini },
3403bd88451SPaolo Bonzini };
3413bd88451SPaolo Bonzini
grlib_gptimer_reset(DeviceState * d)3423bd88451SPaolo Bonzini static void grlib_gptimer_reset(DeviceState *d)
3433bd88451SPaolo Bonzini {
344541ab55fSAndreas Färber GPTimerUnit *unit = GRLIB_GPTIMER(d);
3453bd88451SPaolo Bonzini int i = 0;
3463bd88451SPaolo Bonzini
3473bd88451SPaolo Bonzini assert(unit != NULL);
3483bd88451SPaolo Bonzini
3493bd88451SPaolo Bonzini unit->scaler = 0;
3503bd88451SPaolo Bonzini unit->reload = 0;
3513bd88451SPaolo Bonzini
3523bd88451SPaolo Bonzini unit->config = unit->nr_timers;
3533bd88451SPaolo Bonzini unit->config |= unit->irq_line << 3;
3543bd88451SPaolo Bonzini unit->config |= 1 << 8; /* separate interrupt */
3553bd88451SPaolo Bonzini unit->config |= 1 << 9; /* Disable timer freeze */
3563bd88451SPaolo Bonzini
3573bd88451SPaolo Bonzini
3583bd88451SPaolo Bonzini for (i = 0; i < unit->nr_timers; i++) {
3593bd88451SPaolo Bonzini GPTimer *timer = &unit->timers[i];
3603bd88451SPaolo Bonzini
3613bd88451SPaolo Bonzini timer->counter = 0;
3623bd88451SPaolo Bonzini timer->reload = 0;
3633bd88451SPaolo Bonzini timer->config = 0;
364663e475fSPeter Maydell ptimer_transaction_begin(timer->ptimer);
3653bd88451SPaolo Bonzini ptimer_stop(timer->ptimer);
3663bd88451SPaolo Bonzini ptimer_set_count(timer->ptimer, 0);
3673bd88451SPaolo Bonzini ptimer_set_freq(timer->ptimer, unit->freq_hz);
368663e475fSPeter Maydell ptimer_transaction_commit(timer->ptimer);
3693bd88451SPaolo Bonzini }
3703bd88451SPaolo Bonzini }
3713bd88451SPaolo Bonzini
grlib_gptimer_realize(DeviceState * dev,Error ** errp)37223251fb8SMao Zhongyi static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
3733bd88451SPaolo Bonzini {
374541ab55fSAndreas Färber GPTimerUnit *unit = GRLIB_GPTIMER(dev);
3753bd88451SPaolo Bonzini unsigned int i;
37623251fb8SMao Zhongyi SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
3773bd88451SPaolo Bonzini
3783bd88451SPaolo Bonzini assert(unit->nr_timers > 0);
3793bd88451SPaolo Bonzini assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
3803bd88451SPaolo Bonzini
3813bd88451SPaolo Bonzini unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
3823bd88451SPaolo Bonzini
3833bd88451SPaolo Bonzini for (i = 0; i < unit->nr_timers; i++) {
3843bd88451SPaolo Bonzini GPTimer *timer = &unit->timers[i];
3853bd88451SPaolo Bonzini
3863bd88451SPaolo Bonzini timer->unit = unit;
387663e475fSPeter Maydell timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
3889598c1bbSPeter Maydell PTIMER_POLICY_LEGACY);
3893bd88451SPaolo Bonzini timer->id = i;
3903bd88451SPaolo Bonzini
3913bd88451SPaolo Bonzini /* One IRQ line for each timer */
39223251fb8SMao Zhongyi sysbus_init_irq(sbd, &timer->irq);
3933bd88451SPaolo Bonzini
394663e475fSPeter Maydell ptimer_transaction_begin(timer->ptimer);
3953bd88451SPaolo Bonzini ptimer_set_freq(timer->ptimer, unit->freq_hz);
396663e475fSPeter Maydell ptimer_transaction_commit(timer->ptimer);
3973bd88451SPaolo Bonzini }
3983bd88451SPaolo Bonzini
399853dca12SPaolo Bonzini memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
400853dca12SPaolo Bonzini unit, "gptimer",
4013bd88451SPaolo Bonzini UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
4023bd88451SPaolo Bonzini
40323251fb8SMao Zhongyi sysbus_init_mmio(sbd, &unit->iomem);
4043bd88451SPaolo Bonzini }
4053bd88451SPaolo Bonzini
4063bd88451SPaolo Bonzini static Property grlib_gptimer_properties[] = {
4073bd88451SPaolo Bonzini DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
4083bd88451SPaolo Bonzini DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
4093bd88451SPaolo Bonzini DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
4103bd88451SPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
4113bd88451SPaolo Bonzini };
4123bd88451SPaolo Bonzini
grlib_gptimer_class_init(ObjectClass * klass,void * data)4133bd88451SPaolo Bonzini static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
4143bd88451SPaolo Bonzini {
4153bd88451SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
4163bd88451SPaolo Bonzini
41723251fb8SMao Zhongyi dc->realize = grlib_gptimer_realize;
418*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, grlib_gptimer_reset);
4194f67d30bSMarc-André Lureau device_class_set_props(dc, grlib_gptimer_properties);
4203bd88451SPaolo Bonzini }
4213bd88451SPaolo Bonzini
4223bd88451SPaolo Bonzini static const TypeInfo grlib_gptimer_info = {
423541ab55fSAndreas Färber .name = TYPE_GRLIB_GPTIMER,
4243bd88451SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
4253bd88451SPaolo Bonzini .instance_size = sizeof(GPTimerUnit),
4263bd88451SPaolo Bonzini .class_init = grlib_gptimer_class_init,
4273bd88451SPaolo Bonzini };
4283bd88451SPaolo Bonzini
grlib_gptimer_register_types(void)4293bd88451SPaolo Bonzini static void grlib_gptimer_register_types(void)
4303bd88451SPaolo Bonzini {
4313bd88451SPaolo Bonzini type_register_static(&grlib_gptimer_info);
4323bd88451SPaolo Bonzini }
4333bd88451SPaolo Bonzini
4343bd88451SPaolo Bonzini type_init(grlib_gptimer_register_types)
435