riscv: provide native clint access for M-mode

RISC-V has the concept of a cpu level interrupt controller.  The
interface for it is split between a standardized part that is exposed
as bits in the mstatus/sstatus register and the mie/mip/sie/sip
CRS.  But the bit to actually trigger IPIs is not standardized and
just mentioned as implementable using MMIO.

Add support for IPIs using MMIO using the SiFive clint layout (which
is also shared by Ariane, Kendryte and the Qemu virt platform).
Additionally the MMIO block also supports the time value and timer
compare registers, so they are also set up using the same OF node.
Support for other layouts should also be relatively easy to add in the
future.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Anup Patel <anup@brainfault.org>
[paul.walmsley@sifive.com: update include guard format; fix checkpatch
 issues; minor commit message cleanup]
Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
This commit is contained in:
Christoph Hellwig
2019-10-28 13:10:38 +01:00
committed by Paul Walmsley
parent 4f9bbcefa1
commit fcdc653751
7 changed files with 105 additions and 3 deletions

44
arch/riscv/kernel/clint.c Normal file
View File

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 Christoph Hellwig.
*/
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/types.h>
#include <asm/clint.h>
#include <asm/csr.h>
#include <asm/timex.h>
#include <asm/smp.h>
/*
* This is the layout used by the SiFive clint, which is also shared by the qemu
* virt platform, and the Kendryte KD210 at least.
*/
#define CLINT_IPI_OFF 0
#define CLINT_TIME_CMP_OFF 0x4000
#define CLINT_TIME_VAL_OFF 0xbff8
u32 __iomem *clint_ipi_base;
void clint_init_boot_cpu(void)
{
struct device_node *np;
void __iomem *base;
np = of_find_compatible_node(NULL, NULL, "riscv,clint0");
if (!np) {
panic("clint not found");
return;
}
base = of_iomap(np, 0);
if (!base)
panic("could not map CLINT");
clint_ipi_base = base + CLINT_IPI_OFF;
riscv_time_cmp = base + CLINT_TIME_CMP_OFF;
riscv_time_val = base + CLINT_TIME_VAL_OFF;
clint_clear_ipi(boot_cpu_hartid);
}