]> git.proxmox.com Git - mirror_qemu.git/blame - hw/timer/mips_gictimer.c
Merge tag 'pull-target-arm-20230113' of https://git.linaro.org/people/pmaydell/qemu...
[mirror_qemu.git] / hw / timer / mips_gictimer.c
CommitLineData
40514051
YK
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2016 Imagination Technologies
7 */
8
9#include "qemu/osdep.h"
40514051
YK
10#include "qemu/timer.h"
11#include "hw/timer/mips_gictimer.h"
12
13#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
14
eb90ab94
PB
15uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic)
16{
17 return NANOSECONDS_PER_SECOND / TIMER_PERIOD;
18}
19
40514051
YK
20static void gic_vptimer_update(MIPSGICTimerState *gictimer,
21 uint32_t vp_index, uint64_t now)
22{
23 uint64_t next;
24 uint32_t wait;
25
26 wait = gictimer->vptimers[vp_index].comparelo - gictimer->sh_counterlo -
27 (uint32_t)(now / TIMER_PERIOD);
28 next = now + (uint64_t)wait * TIMER_PERIOD;
29
30 timer_mod(gictimer->vptimers[vp_index].qtimer, next);
31}
32
33static void gic_vptimer_expire(MIPSGICTimerState *gictimer, uint32_t vp_index,
34 uint64_t now)
35{
36 if (gictimer->countstop) {
37 /* timer stopped */
38 return;
39 }
40 gictimer->cb(gictimer->opaque, vp_index);
41 gic_vptimer_update(gictimer, vp_index, now);
42}
43
44static void gic_vptimer_cb(void *opaque)
45{
46 MIPSGICTimerVPState *vptimer = opaque;
47 MIPSGICTimerState *gictimer = vptimer->gictimer;
48 gic_vptimer_expire(gictimer, vptimer->vp_index,
49 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
50}
51
52uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gictimer)
53{
54 int i;
55 if (gictimer->countstop) {
56 return gictimer->sh_counterlo;
57 } else {
58 uint64_t now;
59 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
60 for (i = 0; i < gictimer->num_vps; i++) {
61 if (timer_pending(gictimer->vptimers[i].qtimer)
62 && timer_expired(gictimer->vptimers[i].qtimer, now)) {
63 /* The timer has already expired. */
64 gic_vptimer_expire(gictimer, i, now);
65 }
66 }
67 return gictimer->sh_counterlo + (uint32_t)(now / TIMER_PERIOD);
68 }
69}
70
71void mips_gictimer_store_sh_count(MIPSGICTimerState *gictimer, uint64_t count)
72{
73 int i;
74 uint64_t now;
75
76 if (gictimer->countstop || !gictimer->vptimers[0].qtimer) {
77 gictimer->sh_counterlo = count;
78 } else {
79 /* Store new count register */
80 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
81 gictimer->sh_counterlo = count - (uint32_t)(now / TIMER_PERIOD);
82 /* Update timer timer */
83 for (i = 0; i < gictimer->num_vps; i++) {
84 gic_vptimer_update(gictimer, i, now);
85 }
86 }
87}
88
89uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer,
90 uint32_t vp_index)
91{
92 return gictimer->vptimers[vp_index].comparelo;
93}
94
95void mips_gictimer_store_vp_compare(MIPSGICTimerState *gictimer,
96 uint32_t vp_index, uint64_t compare)
97{
98 gictimer->vptimers[vp_index].comparelo = (uint32_t) compare;
99 gic_vptimer_update(gictimer, vp_index,
100 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
101}
102
103uint8_t mips_gictimer_get_countstop(MIPSGICTimerState *gictimer)
104{
105 return gictimer->countstop;
106}
107
108void mips_gictimer_start_count(MIPSGICTimerState *gictimer)
109{
110 gictimer->countstop = 0;
111 mips_gictimer_store_sh_count(gictimer, gictimer->sh_counterlo);
112}
113
114void mips_gictimer_stop_count(MIPSGICTimerState *gictimer)
115{
116 int i;
117
118 gictimer->countstop = 1;
119 /* Store the current value */
120 gictimer->sh_counterlo +=
121 (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
122 for (i = 0; i < gictimer->num_vps; i++) {
123 timer_del(gictimer->vptimers[i].qtimer);
124 }
125}
126
127MIPSGICTimerState *mips_gictimer_init(void *opaque, uint32_t nvps,
128 MIPSGICTimerCB *cb)
129{
130 int i;
131 MIPSGICTimerState *gictimer = g_new(MIPSGICTimerState, 1);
132 gictimer->vptimers = g_new(MIPSGICTimerVPState, nvps);
133 gictimer->countstop = 1;
134 gictimer->num_vps = nvps;
135 gictimer->opaque = opaque;
136 gictimer->cb = cb;
137 for (i = 0; i < nvps; i++) {
138 gictimer->vptimers[i].gictimer = gictimer;
139 gictimer->vptimers[i].vp_index = i;
140 gictimer->vptimers[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
141 &gic_vptimer_cb,
142 &gictimer->vptimers[i]);
143 }
144 return gictimer;
145}