2 * QEMU OpenRISC timer support
4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 * Zhizhou Zhang <etouzh@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
24 #include "qemu/timer.h"
26 #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */
28 /* Tick Timer global state to allow all cores to be in sync */
29 typedef struct OR1KTimerState
{
34 static OR1KTimerState
*or1k_timer
;
36 void cpu_openrisc_count_set(OpenRISCCPU
*cpu
, uint32_t val
)
38 or1k_timer
->ttcr
= val
;
41 uint32_t cpu_openrisc_count_get(OpenRISCCPU
*cpu
)
43 return or1k_timer
->ttcr
;
46 /* Add elapsed ticks to ttcr */
47 void cpu_openrisc_count_update(OpenRISCCPU
*cpu
)
51 if (!cpu
->env
.is_counting
) {
54 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
55 or1k_timer
->ttcr
+= (uint32_t)((now
- or1k_timer
->last_clk
)
57 or1k_timer
->last_clk
= now
;
60 /* Update the next timeout time as difference between ttmr and ttcr */
61 void cpu_openrisc_timer_update(OpenRISCCPU
*cpu
)
66 if (!cpu
->env
.is_counting
) {
70 cpu_openrisc_count_update(cpu
);
71 now
= or1k_timer
->last_clk
;
73 if ((cpu
->env
.ttmr
& TTMR_TP
) <= (or1k_timer
->ttcr
& TTMR_TP
)) {
74 wait
= TTMR_TP
- (or1k_timer
->ttcr
& TTMR_TP
) + 1;
75 wait
+= cpu
->env
.ttmr
& TTMR_TP
;
77 wait
= (cpu
->env
.ttmr
& TTMR_TP
) - (or1k_timer
->ttcr
& TTMR_TP
);
79 next
= now
+ (uint64_t)wait
* TIMER_PERIOD
;
80 timer_mod(cpu
->env
.timer
, next
);
83 void cpu_openrisc_count_start(OpenRISCCPU
*cpu
)
85 cpu
->env
.is_counting
= 1;
86 cpu_openrisc_count_update(cpu
);
89 void cpu_openrisc_count_stop(OpenRISCCPU
*cpu
)
91 timer_del(cpu
->env
.timer
);
92 cpu_openrisc_count_update(cpu
);
93 cpu
->env
.is_counting
= 0;
96 static void openrisc_timer_cb(void *opaque
)
98 OpenRISCCPU
*cpu
= opaque
;
100 if ((cpu
->env
.ttmr
& TTMR_IE
) &&
101 timer_expired(cpu
->env
.timer
, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
))) {
102 CPUState
*cs
= CPU(cpu
);
104 cpu
->env
.ttmr
|= TTMR_IP
;
105 cs
->interrupt_request
|= CPU_INTERRUPT_TIMER
;
108 switch (cpu
->env
.ttmr
& TTMR_M
) {
112 or1k_timer
->ttcr
= 0;
115 cpu_openrisc_count_stop(cpu
);
121 cpu_openrisc_timer_update(cpu
);
122 qemu_cpu_kick(CPU(cpu
));
125 static const VMStateDescription vmstate_or1k_timer
= {
126 .name
= "or1k_timer",
128 .minimum_version_id
= 1,
129 .fields
= (VMStateField
[]) {
130 VMSTATE_UINT32(ttcr
, OR1KTimerState
),
131 VMSTATE_UINT64(last_clk
, OR1KTimerState
),
132 VMSTATE_END_OF_LIST()
136 void cpu_openrisc_clock_init(OpenRISCCPU
*cpu
)
138 cpu
->env
.timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, &openrisc_timer_cb
, cpu
);
139 cpu
->env
.ttmr
= 0x00000000;
141 if (or1k_timer
== NULL
) {
142 or1k_timer
= g_new0(OR1KTimerState
, 1);
143 vmstate_register(NULL
, 0, &vmstate_or1k_timer
, or1k_timer
);