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"
10 #include "qemu/timer.h"
11 #include "hw/timer/mips_gictimer.h"
13 #define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
15 uint32_t mips_gictimer_get_freq(MIPSGICTimerState
*gic
)
17 return NANOSECONDS_PER_SECOND
/ TIMER_PERIOD
;
20 static void gic_vptimer_update(MIPSGICTimerState
*gictimer
,
21 uint32_t vp_index
, uint64_t now
)
26 wait
= gictimer
->vptimers
[vp_index
].comparelo
- gictimer
->sh_counterlo
-
27 (uint32_t)(now
/ TIMER_PERIOD
);
28 next
= now
+ (uint64_t)wait
* TIMER_PERIOD
;
30 timer_mod(gictimer
->vptimers
[vp_index
].qtimer
, next
);
33 static void gic_vptimer_expire(MIPSGICTimerState
*gictimer
, uint32_t vp_index
,
36 if (gictimer
->countstop
) {
40 gictimer
->cb(gictimer
->opaque
, vp_index
);
41 gic_vptimer_update(gictimer
, vp_index
, now
);
44 static void gic_vptimer_cb(void *opaque
)
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
));
52 uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState
*gictimer
)
55 if (gictimer
->countstop
) {
56 return gictimer
->sh_counterlo
;
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
);
67 return gictimer
->sh_counterlo
+ (uint32_t)(now
/ TIMER_PERIOD
);
71 void mips_gictimer_store_sh_count(MIPSGICTimerState
*gictimer
, uint64_t count
)
76 if (gictimer
->countstop
|| !gictimer
->vptimers
[0].qtimer
) {
77 gictimer
->sh_counterlo
= count
;
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
);
89 uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState
*gictimer
,
92 return gictimer
->vptimers
[vp_index
].comparelo
;
95 void mips_gictimer_store_vp_compare(MIPSGICTimerState
*gictimer
,
96 uint32_t vp_index
, uint64_t compare
)
98 gictimer
->vptimers
[vp_index
].comparelo
= (uint32_t) compare
;
99 gic_vptimer_update(gictimer
, vp_index
,
100 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
103 uint8_t mips_gictimer_get_countstop(MIPSGICTimerState
*gictimer
)
105 return gictimer
->countstop
;
108 void mips_gictimer_start_count(MIPSGICTimerState
*gictimer
)
110 gictimer
->countstop
= 0;
111 mips_gictimer_store_sh_count(gictimer
, gictimer
->sh_counterlo
);
114 void mips_gictimer_stop_count(MIPSGICTimerState
*gictimer
)
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
);
127 MIPSGICTimerState
*mips_gictimer_init(void *opaque
, uint32_t nvps
,
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
;
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
,
142 &gictimer
->vptimers
[i
]);