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 uint32_t mips_gictimer_get_freq(MIPSGICTimerState
*gic
)
19 return NANOSECONDS_PER_SECOND
/ TIMER_PERIOD
;
22 static void gic_vptimer_update(MIPSGICTimerState
*gictimer
,
23 uint32_t vp_index
, uint64_t now
)
28 wait
= gictimer
->vptimers
[vp_index
].comparelo
- gictimer
->sh_counterlo
-
29 (uint32_t)(now
/ TIMER_PERIOD
);
30 next
= now
+ (uint64_t)wait
* TIMER_PERIOD
;
32 timer_mod(gictimer
->vptimers
[vp_index
].qtimer
, next
);
35 static void gic_vptimer_expire(MIPSGICTimerState
*gictimer
, uint32_t vp_index
,
38 if (gictimer
->countstop
) {
42 gictimer
->cb(gictimer
->opaque
, vp_index
);
43 gic_vptimer_update(gictimer
, vp_index
, now
);
46 static void gic_vptimer_cb(void *opaque
)
48 MIPSGICTimerVPState
*vptimer
= opaque
;
49 MIPSGICTimerState
*gictimer
= vptimer
->gictimer
;
50 gic_vptimer_expire(gictimer
, vptimer
->vp_index
,
51 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
54 uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState
*gictimer
)
57 if (gictimer
->countstop
) {
58 return gictimer
->sh_counterlo
;
61 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
62 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
63 if (timer_pending(gictimer
->vptimers
[i
].qtimer
)
64 && timer_expired(gictimer
->vptimers
[i
].qtimer
, now
)) {
65 /* The timer has already expired. */
66 gic_vptimer_expire(gictimer
, i
, now
);
69 return gictimer
->sh_counterlo
+ (uint32_t)(now
/ TIMER_PERIOD
);
73 void mips_gictimer_store_sh_count(MIPSGICTimerState
*gictimer
, uint64_t count
)
78 if (gictimer
->countstop
|| !gictimer
->vptimers
[0].qtimer
) {
79 gictimer
->sh_counterlo
= count
;
81 /* Store new count register */
82 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
83 gictimer
->sh_counterlo
= count
- (uint32_t)(now
/ TIMER_PERIOD
);
84 /* Update timer timer */
85 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
86 gic_vptimer_update(gictimer
, i
, now
);
91 uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState
*gictimer
,
94 return gictimer
->vptimers
[vp_index
].comparelo
;
97 void mips_gictimer_store_vp_compare(MIPSGICTimerState
*gictimer
,
98 uint32_t vp_index
, uint64_t compare
)
100 gictimer
->vptimers
[vp_index
].comparelo
= (uint32_t) compare
;
101 gic_vptimer_update(gictimer
, vp_index
,
102 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
105 uint8_t mips_gictimer_get_countstop(MIPSGICTimerState
*gictimer
)
107 return gictimer
->countstop
;
110 void mips_gictimer_start_count(MIPSGICTimerState
*gictimer
)
112 gictimer
->countstop
= 0;
113 mips_gictimer_store_sh_count(gictimer
, gictimer
->sh_counterlo
);
116 void mips_gictimer_stop_count(MIPSGICTimerState
*gictimer
)
120 gictimer
->countstop
= 1;
121 /* Store the current value */
122 gictimer
->sh_counterlo
+=
123 (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) / TIMER_PERIOD
);
124 for (i
= 0; i
< gictimer
->num_vps
; i
++) {
125 timer_del(gictimer
->vptimers
[i
].qtimer
);
129 MIPSGICTimerState
*mips_gictimer_init(void *opaque
, uint32_t nvps
,
133 MIPSGICTimerState
*gictimer
= g_new(MIPSGICTimerState
, 1);
134 gictimer
->vptimers
= g_new(MIPSGICTimerVPState
, nvps
);
135 gictimer
->countstop
= 1;
136 gictimer
->num_vps
= nvps
;
137 gictimer
->opaque
= opaque
;
139 for (i
= 0; i
< nvps
; i
++) {
140 gictimer
->vptimers
[i
].gictimer
= gictimer
;
141 gictimer
->vptimers
[i
].vp_index
= i
;
142 gictimer
->vptimers
[i
].qtimer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
,
144 &gictimer
->vptimers
[i
]);