qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

constant_timer.c (1821B)


      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 }