1 /*
2  * Copyright (c) 2018 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <lk/reg.h>
9 #include <lk/debug.h>
10 #include <lk/trace.h>
11 #include <lk/err.h>
12 #include <lk/trace.h>
13 
14 #include <arch/riscv/feature.h>
15 
16 #include <arch/riscv.h>
17 #include <arch/ops.h>
18 
19 #include <platform.h>
20 #include <platform/timer.h>
21 
22 #define LOCAL_TRACE 0
23 
24 static platform_timer_callback timer_cb;
25 static void *timer_arg;
26 
platform_set_oneshot_timer(platform_timer_callback callback,void * arg,lk_time_t interval)27 status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) {
28     LTRACEF("cb %p, arg %p, interval %u\n", callback, arg, interval);
29 
30     // disable timer
31     riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
32 
33     timer_cb = callback;
34     timer_arg = arg;
35 
36     // enable the timer
37     riscv_csr_set(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
38 
39     // convert interval to ticks
40     uint64_t ticks = riscv_get_time() + ((interval * ARCH_RISCV_MTIME_RATE) / 1000u);
41 #if RISCV_M_MODE
42     clint_set_timer(ticks);
43 #elif RISCV_S_MODE
44     if (riscv_feature_test(RISCV_FEAT_SSTC)) {
45 #if __riscv_xlen == 64
46         riscv_csr_write(RISCV_CSR_STIMECMP, ticks);
47 #else
48         riscv_csr_write(RISCV_CSR_STIMECMPH, ticks >> 32);
49         riscv_csr_write(RISCV_CSR_STIMECMP, ticks);
50 #endif
51     } else {
52         sbi_set_timer(ticks);
53     }
54 #endif
55 
56     return NO_ERROR;
57 }
58 
59 
current_time_hires(void)60 lk_bigtime_t current_time_hires(void) {
61 #if ARCH_RISCV_MTIME_RATE < 10000000
62     return current_time() * 1000llu; // hack to deal with slow clocks
63 #else
64     return riscv_get_time() / (ARCH_RISCV_MTIME_RATE / 1000000u);
65 #endif
66 }
67 
current_time(void)68 lk_time_t current_time(void) {
69     return riscv_get_time() / (ARCH_RISCV_MTIME_RATE / 1000u);
70 }
71 
platform_stop_timer(void)72 void platform_stop_timer(void) {
73     riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
74 }
75 
riscv_timer_exception(void)76 enum handler_return riscv_timer_exception(void) {
77     LTRACEF("tick\n");
78 
79     riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
80 
81     enum handler_return ret = INT_NO_RESCHEDULE;
82     if (timer_cb) {
83         ret = timer_cb(timer_arg, current_time());
84     }
85 
86     return ret;
87 }
88