RISC-V: Add mechanism to provide custom IPI operations
[linux-2.6-microblaze.git] / arch / riscv / kernel / clint.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019 Christoph Hellwig.
4  */
5
6 #include <linux/io.h>
7 #include <linux/of_address.h>
8 #include <linux/smp.h>
9 #include <linux/types.h>
10 #include <asm/clint.h>
11 #include <asm/csr.h>
12 #include <asm/timex.h>
13
14 /*
15  * This is the layout used by the SiFive clint, which is also shared by the qemu
16  * virt platform, and the Kendryte KD210 at least.
17  */
18 #define CLINT_IPI_OFF           0
19 #define CLINT_TIME_CMP_OFF      0x4000
20 #define CLINT_TIME_VAL_OFF      0xbff8
21
22 u32 __iomem *clint_ipi_base;
23
24 static void clint_send_ipi(const struct cpumask *target)
25 {
26         unsigned int cpu;
27
28         for_each_cpu(cpu, target)
29                 writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu));
30 }
31
32 static void clint_clear_ipi(void)
33 {
34         writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id()));
35 }
36
37 static struct riscv_ipi_ops clint_ipi_ops = {
38         .ipi_inject = clint_send_ipi,
39         .ipi_clear = clint_clear_ipi,
40 };
41
42 void clint_init_boot_cpu(void)
43 {
44         struct device_node *np;
45         void __iomem *base;
46
47         np = of_find_compatible_node(NULL, NULL, "riscv,clint0");
48         if (!np) {
49                 panic("clint not found");
50                 return;
51         }
52
53         base = of_iomap(np, 0);
54         if (!base)
55                 panic("could not map CLINT");
56
57         clint_ipi_base = base + CLINT_IPI_OFF;
58         riscv_time_cmp = base + CLINT_TIME_CMP_OFF;
59         riscv_time_val = base + CLINT_TIME_VAL_OFF;
60
61         clint_clear_ipi();
62         riscv_set_ipi_ops(&clint_ipi_ops);
63 }