| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * LoongArch Constant Timer specific interface | |
| */ | |
| #ifndef SELFTEST_KVM_ARCH_TIMER_H | |
| #define SELFTEST_KVM_ARCH_TIMER_H | |
| #include "processor.h" | |
| /* LoongArch timer frequency is constant 100MHZ */ | |
| #define TIMER_FREQ (100UL << 20) | |
| #define msec_to_cycles(msec) (TIMER_FREQ * (unsigned long)(msec) / 1000) | |
| #define usec_to_cycles(usec) (TIMER_FREQ * (unsigned long)(usec) / 1000000) | |
| #define cycles_to_usec(cycles) ((unsigned long)(cycles) * 1000000 / TIMER_FREQ) | |
| static inline unsigned long timer_get_cycles(void) | |
| { | |
| unsigned long val = 0; | |
| __asm__ __volatile__( | |
| "rdtime.d %0, $zero\n\t" | |
| : "=r"(val) | |
| : | |
| ); | |
| return val; | |
| } | |
| static inline unsigned long timer_get_cfg(void) | |
| { | |
| return csr_read(LOONGARCH_CSR_TCFG); | |
| } | |
| static inline unsigned long timer_get_val(void) | |
| { | |
| return csr_read(LOONGARCH_CSR_TVAL); | |
| } | |
| static inline void disable_timer(void) | |
| { | |
| csr_write(0, LOONGARCH_CSR_TCFG); | |
| } | |
| static inline void timer_irq_enable(void) | |
| { | |
| unsigned long val; | |
| val = csr_read(LOONGARCH_CSR_ECFG); | |
| val |= ECFGF_TIMER; | |
| csr_write(val, LOONGARCH_CSR_ECFG); | |
| } | |
| static inline void timer_irq_disable(void) | |
| { | |
| unsigned long val; | |
| val = csr_read(LOONGARCH_CSR_ECFG); | |
| val &= ~ECFGF_TIMER; | |
| csr_write(val, LOONGARCH_CSR_ECFG); | |
| } | |
| static inline void timer_set_next_cmp_ms(unsigned int msec, bool period) | |
| { | |
| unsigned long val; | |
| val = msec_to_cycles(msec) & CSR_TCFG_VAL; | |
| val |= CSR_TCFG_EN; | |
| if (period) | |
| val |= CSR_TCFG_PERIOD; | |
| csr_write(val, LOONGARCH_CSR_TCFG); | |
| } | |
| static inline void __delay(u64 cycles) | |
| { | |
| u64 start = timer_get_cycles(); | |
| while ((timer_get_cycles() - start) < cycles) | |
| cpu_relax(); | |
| } | |
| static inline void udelay(unsigned long usec) | |
| { | |
| __delay(usec_to_cycles(usec)); | |
| } | |
| #endif /* SELFTEST_KVM_ARCH_TIMER_H */ |