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
6 * Copyright (C) 2016 Imagination Technologies
9 #include "qemu/osdep.h"
11 #include "hw/sysbus.h"
12 #include "qemu/timer.h"
13 #include "hw/timer/mips_gictimer.h"
15 #define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
17 static void gic_vptimer_update(MIPSGICTimerState
*gictimer
,
18 uint32_t vp_index
, uint64_t now
)
23 wait
= gictimer
->vptimers
[vp_index
].comparelo
- gictimer
->sh_counterlo
-
24 (uint32_t)(now
/ TIMER_PERIOD
);
25 next
= now
+ (uint64_t)wait
* TIMER_PERIOD
;
27 timer_mod(gictimer
->vptimers
[vp_index
].qtimer
, next
);
30 static void gic_vptimer_expire(MIPSGICTimerState
*gictimer
, uint32_t vp_index
,
33 if (gictimer
->countstop
) {
37 gictimer
->cb(gictimer
->opaque
, vp_index
);
38 gic_vptimer_update(gictimer
, vp_index
, now
);
41 static void gic_vptimer_cb(void *opaque
)
43 MIPSGICTimerVPState
*vptimer
= opaque
;
44 MIPSGICTimerState
*gictimer
= vptimer
->gictimer
;
45 gic_vptimer_expire(gictimer
, vptimer
->vp_index
,
46 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
49 uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState
*gictimer
)
52 if (gictimer
->countstop
) {
53 return gictimer
->sh_counterlo
;
56 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
57 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
58 if (timer_pending(gictimer
->vptimers
[i
].qtimer
)
59 && timer_expired(gictimer
->vptimers
[i
].qtimer
, now
)) {
60 /* The timer has already expired. */
61 gic_vptimer_expire(gictimer
, i
, now
);
64 return gictimer
->sh_counterlo
+ (uint32_t)(now
/ TIMER_PERIOD
);
68 void mips_gictimer_store_sh_count(MIPSGICTimerState
*gictimer
, uint64_t count
)
73 if (gictimer
->countstop
|| !gictimer
->vptimers
[0].qtimer
) {
74 gictimer
->sh_counterlo
= count
;
76 /* Store new count register */
77 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
78 gictimer
->sh_counterlo
= count
- (uint32_t)(now
/ TIMER_PERIOD
);
79 /* Update timer timer */
80 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
81 gic_vptimer_update(gictimer
, i
, now
);
86 uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState
*gictimer
,
89 return gictimer
->vptimers
[vp_index
].comparelo
;
92 void mips_gictimer_store_vp_compare(MIPSGICTimerState
*gictimer
,
93 uint32_t vp_index
, uint64_t compare
)
95 gictimer
->vptimers
[vp_index
].comparelo
= (uint32_t) compare
;
96 gic_vptimer_update(gictimer
, vp_index
,
97 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
100 uint8_t mips_gictimer_get_countstop(MIPSGICTimerState
*gictimer
)
102 return gictimer
->countstop
;
105 void mips_gictimer_start_count(MIPSGICTimerState
*gictimer
)
107 gictimer
->countstop
= 0;
108 mips_gictimer_store_sh_count(gictimer
, gictimer
->sh_counterlo
);
111 void mips_gictimer_stop_count(MIPSGICTimerState
*gictimer
)
115 gictimer
->countstop
= 1;
116 /* Store the current value */
117 gictimer
->sh_counterlo
+=
118 (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) / TIMER_PERIOD
);
119 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
120 timer_del(gictimer
->vptimers
[i
].qtimer
);
124 MIPSGICTimerState
*mips_gictimer_init(void *opaque
, uint32_t nvps
,
128 MIPSGICTimerState
*gictimer
= g_new(MIPSGICTimerState
, 1);
129 gictimer
->vptimers
= g_new(MIPSGICTimerVPState
, nvps
);
130 gictimer
->countstop
= 1;
131 gictimer
->num_vps
= nvps
;
132 gictimer
->opaque
= opaque
;
134 for (i
= 0; i
< nvps
; i
++) {
135 gictimer
->vptimers
[i
].gictimer
= gictimer
;
136 gictimer
->vptimers
[i
].vp_index
= i
;
137 gictimer
->vptimers
[i
].qtimer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
,
139 &gictimer
->vptimers
[i
]);