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.h>
15 #include <arch/ops.h>
16
17 #include <platform.h>
18 #include <platform/timer.h>
19
20 #define LOCAL_TRACE 0
21
22 static platform_timer_callback timer_cb;
23 static void *timer_arg;
24
platform_set_oneshot_timer(platform_timer_callback callback,void * arg,lk_time_t interval)25 status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) {
26 LTRACEF("cb %p, arg %p, interval %u\n", callback, arg, interval);
27
28 // disable timer
29 riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
30
31 timer_cb = callback;
32 timer_arg = arg;
33
34 // enable the timer
35 riscv_csr_set(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
36
37 // convert interval to ticks
38 uint64_t ticks = riscv_get_time() + ((interval * ARCH_RISCV_MTIME_RATE) / 1000u);
39 #if RISCV_M_MODE
40 extern void clint_set_timer(uint64_t ticks);
41 clint_set_timer(ticks);
42 #elif RISCV_S_MODE
43 sbi_set_timer(ticks);
44 #endif
45
46 return NO_ERROR;
47 }
48
49
current_time_hires(void)50 lk_bigtime_t current_time_hires(void) {
51 #if ARCH_RISCV_MTIME_RATE < 10000000
52 return current_time() * 1000llu; // hack to deal with slow clocks
53 #else
54 return riscv_get_time() / (ARCH_RISCV_MTIME_RATE / 1000000u);
55 #endif
56 }
57
current_time(void)58 lk_time_t current_time(void) {
59 return riscv_get_time() / (ARCH_RISCV_MTIME_RATE / 1000u);
60 }
61
platform_stop_timer(void)62 void platform_stop_timer(void) {
63 riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
64 }
65
riscv_timer_exception(void)66 enum handler_return riscv_timer_exception(void) {
67 LTRACEF("tick\n");
68
69 riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
70
71 enum handler_return ret = INT_NO_RESCHEDULE;
72 if (timer_cb) {
73 ret = timer_cb(timer_arg, current_time());
74 }
75
76 return ret;
77 }
78