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 "hw/sysbus.h"
11 #include "qemu/timer.h"
12 #include "hw/timer/mips_gictimer.h"
14 #define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
16 uint32_t mips_gictimer_get_freq(MIPSGICTimerState
*gic
)
18 return NANOSECONDS_PER_SECOND
/ TIMER_PERIOD
;
21 static void gic_vptimer_update(MIPSGICTimerState
*gictimer
,
22 uint32_t vp_index
, uint64_t now
)
27 wait
= gictimer
->vptimers
[vp_index
].comparelo
- gictimer
->sh_counterlo
-
28 (uint32_t)(now
/ TIMER_PERIOD
);
29 next
= now
+ (uint64_t)wait
* TIMER_PERIOD
;
31 timer_mod(gictimer
->vptimers
[vp_index
].qtimer
, next
);
34 static void gic_vptimer_expire(MIPSGICTimerState
*gictimer
, uint32_t vp_index
,
37 if (gictimer
->countstop
) {
41 gictimer
->cb(gictimer
->opaque
, vp_index
);
42 gic_vptimer_update(gictimer
, vp_index
, now
);
45 static void gic_vptimer_cb(void *opaque
)
47 MIPSGICTimerVPState
*vptimer
= opaque
;
48 MIPSGICTimerState
*gictimer
= vptimer
->gictimer
;
49 gic_vptimer_expire(gictimer
, vptimer
->vp_index
,
50 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
53 uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState
*gictimer
)
56 if (gictimer
->countstop
) {
57 return gictimer
->sh_counterlo
;
60 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
61 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
62 if (timer_pending(gictimer
->vptimers
[i
].qtimer
)
63 && timer_expired(gictimer
->vptimers
[i
].qtimer
, now
)) {
64 /* The timer has already expired. */
65 gic_vptimer_expire(gictimer
, i
, now
);
68 return gictimer
->sh_counterlo
+ (uint32_t)(now
/ TIMER_PERIOD
);
72 void mips_gictimer_store_sh_count(MIPSGICTimerState
*gictimer
, uint64_t count
)
77 if (gictimer
->countstop
|| !gictimer
->vptimers
[0].qtimer
) {
78 gictimer
->sh_counterlo
= count
;
80 /* Store new count register */
81 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
82 gictimer
->sh_counterlo
= count
- (uint32_t)(now
/ TIMER_PERIOD
);
83 /* Update timer timer */
84 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
85 gic_vptimer_update(gictimer
, i
, now
);
90 uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState
*gictimer
,
93 return gictimer
->vptimers
[vp_index
].comparelo
;
96 void mips_gictimer_store_vp_compare(MIPSGICTimerState
*gictimer
,
97 uint32_t vp_index
, uint64_t compare
)
99 gictimer
->vptimers
[vp_index
].comparelo
= (uint32_t) compare
;
100 gic_vptimer_update(gictimer
, vp_index
,
101 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
104 uint8_t mips_gictimer_get_countstop(MIPSGICTimerState
*gictimer
)
106 return gictimer
->countstop
;
109 void mips_gictimer_start_count(MIPSGICTimerState
*gictimer
)
111 gictimer
->countstop
= 0;
112 mips_gictimer_store_sh_count(gictimer
, gictimer
->sh_counterlo
);
115 void mips_gictimer_stop_count(MIPSGICTimerState
*gictimer
)
119 gictimer
->countstop
= 1;
120 /* Store the current value */
121 gictimer
->sh_counterlo
+=
122 (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) / TIMER_PERIOD
);
123 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
124 timer_del(gictimer
->vptimers
[i
].qtimer
);
128 MIPSGICTimerState
*mips_gictimer_init(void *opaque
, uint32_t nvps
,
132 MIPSGICTimerState
*gictimer
= g_new(MIPSGICTimerState
, 1);
133 gictimer
->vptimers
= g_new(MIPSGICTimerVPState
, nvps
);
134 gictimer
->countstop
= 1;
135 gictimer
->num_vps
= nvps
;
136 gictimer
->opaque
= opaque
;
138 for (i
= 0; i
< nvps
; i
++) {
139 gictimer
->vptimers
[i
].gictimer
= gictimer
;
140 gictimer
->vptimers
[i
].vp_index
= i
;
141 gictimer
->vptimers
[i
].qtimer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
,
143 &gictimer
->vptimers
[i
]);