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