]>
Commit | Line | Data |
---|---|---|
dd615fa4 XY |
1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* | |
3 | * QEMU LoongArch constant timer support | |
4 | * | |
5 | * Copyright (c) 2021 Loongson Technology Corporation Limited | |
6 | */ | |
7 | ||
8 | #include "qemu/osdep.h" | |
9 | #include "qemu/timer.h" | |
10 | #include "cpu.h" | |
11 | #include "internals.h" | |
12 | #include "cpu-csr.h" | |
13 | ||
14 | #define TIMER_PERIOD 10 /* 10 ns period for 100 MHz frequency */ | |
15 | #define CONSTANT_TIMER_TICK_MASK 0xfffffffffffcUL | |
16 | #define CONSTANT_TIMER_ENABLE 0x1UL | |
17 | ||
18 | uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu) | |
19 | { | |
20 | return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; | |
21 | } | |
22 | ||
23 | uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) | |
24 | { | |
25 | uint64_t now, expire; | |
26 | ||
27 | now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
28 | expire = timer_expire_time_ns(&cpu->timer); | |
29 | ||
30 | return (expire - now) / TIMER_PERIOD; | |
31 | } | |
32 | ||
33 | void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, | |
34 | uint64_t value) | |
35 | { | |
36 | CPULoongArchState *env = &cpu->env; | |
37 | uint64_t now, next; | |
38 | ||
39 | env->CSR_TCFG = value; | |
40 | if (value & CONSTANT_TIMER_ENABLE) { | |
41 | now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
42 | next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; | |
43 | timer_mod(&cpu->timer, next); | |
44 | } else { | |
45 | timer_del(&cpu->timer); | |
46 | } | |
47 | } | |
48 | ||
49 | void loongarch_constant_timer_cb(void *opaque) | |
50 | { | |
51 | LoongArchCPU *cpu = opaque; | |
52 | CPULoongArchState *env = &cpu->env; | |
53 | uint64_t now, next; | |
54 | ||
55 | if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) { | |
56 | now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
57 | next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; | |
58 | timer_mod(&cpu->timer, next); | |
59 | } else { | |
60 | env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); | |
61 | } | |
62 | ||
63 | loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); | |
64 | } |