/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Western Digital Corporation or its affiliates. * * Authors: * Anup Patel */ #include #include #include #include #include #include static unsigned long time_delta_off; #if __riscv_xlen == 32 u64 get_ticks(void) { u32 lo, hi, tmp; __asm__ __volatile__("1:\n" "rdtimeh %0\n" "rdtime %1\n" "rdtimeh %2\n" "bne %0, %2, 1b" : "=&r"(hi), "=&r"(lo), "=&r"(tmp)); return ((u64)hi << 32) | lo; } #else u64 get_ticks(void) { unsigned long n; __asm__ __volatile__("rdtime %0" : "=r"(n)); return n; } #endif u64 sbi_timer_value(void) { const struct sbi_platform *plat = sbi_platform_thishart_ptr(); if (sbi_platform_has_timer_value(plat)) return sbi_platform_timer_value(plat); else return get_ticks(); } u64 sbi_timer_virt_value(void) { u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(), time_delta_off); return sbi_timer_value() + *time_delta; } u64 sbi_timer_get_delta(void) { u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(), time_delta_off); return *time_delta; } void sbi_timer_set_delta(ulong delta) { u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(), time_delta_off); *time_delta = (u64)delta; } void sbi_timer_set_delta_upper(ulong delta_upper) { u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(), time_delta_off); *time_delta &= 0xffffffffULL; *time_delta |= ((u64)delta_upper << 32); } void sbi_timer_event_start(u64 next_event) { sbi_platform_timer_event_start(sbi_platform_thishart_ptr(), next_event); csr_clear(CSR_MIP, MIP_STIP); csr_set(CSR_MIE, MIP_MTIP); } void sbi_timer_process(void) { csr_clear(CSR_MIE, MIP_MTIP); csr_set(CSR_MIP, MIP_STIP); } int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) { u64 *time_delta; if (cold_boot) { time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta), "TIME_DELTA"); if (!time_delta_off) return SBI_ENOMEM; } else { if (!time_delta_off) return SBI_ENOMEM; } time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off); *time_delta = 0; return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot); } void sbi_timer_exit(struct sbi_scratch *scratch) { sbi_platform_timer_event_stop(sbi_platform_ptr(scratch)); csr_clear(CSR_MIP, MIP_STIP); csr_clear(CSR_MIE, MIP_MTIP); sbi_platform_timer_exit(sbi_platform_ptr(scratch)); }