1 /*
2  * Copyright (c) 2019 Elliot Berman
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 
9 #pragma once
10 
11 #include <config.h>
12 
13 #include <lk/reg.h>
14 #include <arch/arch_ops.h>
15 
16 #if RISCV_M_MODE
17 
18 // platform must define these
19 #ifndef ARCH_RISCV_CLINT_BASE
20 #error Platform must define ARCH_RISCV_CLINT_BASE
21 #endif
22 #ifndef ARCH_RISCV_MTIME_RATE
23 #error Platform must define ARCH_RISCV_MTIME_RATE
24 #endif
25 
26 #define CLINT_MSIP(h)   (ARCH_RISCV_CLINT_BASE + (4 * (h)))
27 #define CLINT_MTIMECMP(h)   (ARCH_RISCV_CLINT_BASE + 0x4000 + (8 * (h)))
28 #define CLINT_MTIME (ARCH_RISCV_CLINT_BASE + 0xbff8)
29 
clint_ipi_send(unsigned long target_hart)30 static inline void clint_ipi_send(unsigned long target_hart) {
31     if (target_hart >= SMP_MAX_CPUS)
32         return;
33 
34     *REG32(CLINT_MSIP(target_hart)) = 1;
35 }
36 
clint_ipi_clear(unsigned long target_hart)37 static inline void clint_ipi_clear(unsigned long target_hart) {
38     if (target_hart >= SMP_MAX_CPUS)
39         return;
40 
41     *REG32(CLINT_MSIP(target_hart)) = 0;
42 }
43 
clint_set_timer(uint64_t ticks)44 static inline void clint_set_timer(uint64_t ticks) {
45     *REG64(CLINT_MTIMECMP(riscv_current_hart())) = ticks;
46 }
47 
48 
riscv_get_time(void)49 static inline uint64_t riscv_get_time(void) {
50     return *REG64(CLINT_MTIME);
51 }
52 
clint_send_ipis(const unsigned long * hart_mask)53 static inline void clint_send_ipis(const unsigned long *hart_mask) {
54     unsigned long cur_hart = riscv_current_hart(), h, m = *hart_mask;
55     for (h = 0; h < SMP_MAX_CPUS && m; h++, m >>= 1) {
56         if ((m & 1) && (h != cur_hart)) {
57             clint_ipi_send(h);
58         }
59     }
60 
61     if (*hart_mask & (1 << riscv_current_hart())) {
62         clint_ipi_send(cur_hart);
63     }
64 }
65 
66 #endif
67