summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sbi/sbi_hart.h2
-rw-r--r--lib/sbi/sbi_hart.c6
-rw-r--r--lib/sbi/sbi_timer.c29
3 files changed, 28 insertions, 9 deletions
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index f7870d9..beb61b6 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -20,6 +20,8 @@ enum sbi_hart_features {
SBI_HART_HAS_SCOUNTEREN = (1 << 1),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
+ /** HART has timer csr implementation in hardware */
+ SBI_HART_HAS_TIME = (1 << 3),
};
struct sbi_scratch;
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 10972c8..181cea4 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -271,6 +271,12 @@ static void sbi_hart_detect_features(u32 hartid)
feature |= SBI_HART_HAS_MCOUNTEREN;
}
+ /* Detect if hart supports time CSR */
+ trap.cause = 0;
+ csr_read_allowed(CSR_TIME, (unsigned long)&trap);
+ if (!trap.cause)
+ feature |= SBI_HART_HAS_TIME;
+
sbi_hart_set_feature(hartid, feature);
}
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 60d9675..4a3ea24 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -10,14 +10,16 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
static unsigned long time_delta_off;
+static u64 (*get_time_val)(const struct sbi_platform *plat);
#if __riscv_xlen == 32
-u64 get_ticks(void)
+static u64 get_ticks(const struct sbi_platform *plat)
{
u32 lo, hi, tmp;
__asm__ __volatile__("1:\n"
@@ -29,7 +31,7 @@ u64 get_ticks(void)
return ((u64)hi << 32) | lo;
}
#else
-u64 get_ticks(void)
+static u64 get_ticks(const struct sbi_platform *plat)
{
unsigned long n;
@@ -40,12 +42,7 @@ u64 get_ticks(void)
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();
+ return get_time_val(sbi_platform_thishart_ptr());
}
u64 sbi_timer_virt_value(void)
@@ -97,6 +94,8 @@ void sbi_timer_process(void)
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
u64 *time_delta;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ int ret;
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
@@ -111,7 +110,19 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0;
- return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
+ ret = sbi_platform_timer_init(plat, cold_boot);
+ if (ret)
+ return ret;
+
+ if (sbi_hart_has_feature(current_hartid(), SBI_HART_HAS_TIME))
+ get_time_val = get_ticks;
+ else if (sbi_platform_has_timer_value(plat))
+ get_time_val = sbi_platform_timer_value;
+ else
+ /* There is no method to provide timer value */
+ return SBI_ENODEV;
+
+ return 0;
}
void sbi_timer_exit(struct sbi_scratch *scratch)