summaryrefslogtreecommitdiff
path: root/arch/riscv
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-10-05 20:05:46 +0300
committerTom Rini <trini@konsulko.com>2020-10-05 21:10:59 +0300
commitb7e7831e5d5be047f421ddc1f308afc22764a893 (patch)
tree7d5f27c82b260278ed0b3ea96bce592b0505b898 /arch/riscv
parent050acee119b3757fee3bd128f55d720fdd9bb890 (diff)
parentcaebff09efe8c061b4d99b82262c67fb2db9bbcf (diff)
downloadu-boot-b7e7831e5d5be047f421ddc1f308afc22764a893.tar.xz
Merge branch 'next'
Bring in the assorted changes that have been staged in the 'next' branch prior to release. Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'arch/riscv')
-rw-r--r--arch/riscv/Kconfig16
-rw-r--r--arch/riscv/cpu/ax25/Kconfig2
-rw-r--r--arch/riscv/cpu/cpu.c20
-rw-r--r--arch/riscv/cpu/fu540/Kconfig2
-rw-r--r--arch/riscv/cpu/generic/Kconfig2
-rw-r--r--arch/riscv/cpu/start.S58
-rw-r--r--arch/riscv/dts/fu540-c000-u-boot.dtsi8
-rw-r--r--arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi4
-rw-r--r--arch/riscv/dts/k210.dtsi7
-rw-r--r--arch/riscv/include/asm/global_data.h3
-rw-r--r--arch/riscv/include/asm/smp.h7
-rw-r--r--arch/riscv/include/asm/syscon.h4
-rw-r--r--arch/riscv/lib/Makefile1
-rw-r--r--arch/riscv/lib/andes_plic.c58
-rw-r--r--arch/riscv/lib/andes_plmt.c44
-rw-r--r--arch/riscv/lib/fdt_fixup.c2
-rw-r--r--arch/riscv/lib/interrupts.c3
-rw-r--r--arch/riscv/lib/rdtime.c38
-rw-r--r--arch/riscv/lib/sifive_clint.c62
-rw-r--r--arch/riscv/lib/smp.c16
20 files changed, 189 insertions, 168 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 009a545fcf..aaa3b833a5 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -155,10 +155,6 @@ config 64BIT
config SIFIVE_CLINT
bool
depends on RISCV_MMODE || SPL_RISCV_MMODE
- select REGMAP
- select SYSCON
- select SPL_REGMAP if SPL
- select SPL_SYSCON if SPL
help
The SiFive CLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
@@ -177,22 +173,10 @@ config ANDES_PLIC
config ANDES_PLMT
bool
depends on RISCV_MMODE || SPL_RISCV_MMODE
- select REGMAP
- select SYSCON
- select SPL_REGMAP if SPL
- select SPL_SYSCON if SPL
help
The Andes PLMT block holds memory-mapped mtime register
associated with timer tick.
-config RISCV_RDTIME
- bool
- default y if RISCV_SMODE || SPL_RISCV_SMODE
- help
- The provides the riscv_get_time() API that is implemented using the
- standard rdtime instruction. This is the case for S-mode U-Boot, and
- is useful for processors that support rdtime in M-mode too.
-
config SYS_MALLOC_F_LEN
default 0x1000
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index 8d8d71dcbf..5cb5bb51eb 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -3,7 +3,7 @@ config RISCV_NDS
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
- imply RISCV_TIMER
+ imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply ANDES_PLIC if (RISCV_MMODE || SPL_RISCV_MMODE)
imply ANDES_PLMT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply SPL_CPU_SUPPORT
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index bfa2d4a426..85592f5bee 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -72,6 +72,17 @@ static int riscv_cpu_probe(void)
return 0;
}
+/*
+ * This is called on secondary harts just after the IPI is init'd. Currently
+ * there's nothing to do, since we just need to clear any existing IPIs, and
+ * that is handled by the sending of an ipi itself.
+ */
+#if CONFIG_IS_ENABLED(SMP)
+static void dummy_pending_ipi_clear(ulong hart, ulong arg0, ulong arg1)
+{
+}
+#endif
+
int arch_cpu_init_dm(void)
{
int ret;
@@ -111,6 +122,15 @@ int arch_cpu_init_dm(void)
ret = riscv_init_ipi();
if (ret)
return ret;
+
+ /*
+ * Clear all pending IPIs on secondary harts. We don't do anything on
+ * the boot hart, since we never send an IPI to ourselves, and no
+ * interrupts are enabled
+ */
+ ret = smp_call_function((ulong)dummy_pending_ipi_clear, 0, 0, 0);
+ if (ret)
+ return ret;
#endif
return 0;
diff --git a/arch/riscv/cpu/fu540/Kconfig b/arch/riscv/cpu/fu540/Kconfig
index 53e19635c8..ac3f183342 100644
--- a/arch/riscv/cpu/fu540/Kconfig
+++ b/arch/riscv/cpu/fu540/Kconfig
@@ -10,7 +10,7 @@ config SIFIVE_FU540
select SPL_RAM if SPL
imply CPU
imply CPU_RISCV
- imply RISCV_TIMER
+ imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply CMD_CPU
imply SPL_CPU_SUPPORT
diff --git a/arch/riscv/cpu/generic/Kconfig b/arch/riscv/cpu/generic/Kconfig
index b2cb155d6d..f4c2e2643c 100644
--- a/arch/riscv/cpu/generic/Kconfig
+++ b/arch/riscv/cpu/generic/Kconfig
@@ -7,7 +7,7 @@ config GENERIC_RISCV
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
- imply RISCV_TIMER
+ imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply CMD_CPU
imply SPL_CPU_SUPPORT
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index bf9fdf369b..bbc737ed9a 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -43,14 +43,32 @@ _start:
csrr a0, CSR_MHARTID
#endif
- /* save hart id and dtb pointer */
+ /*
+ * Save hart id and dtb pointer. The thread pointer register is not
+ * modified by C code. It is used by secondary_hart_loop.
+ */
mv tp, a0
mv s1, a1
+ /*
+ * Set the global data pointer to a known value in case we get a very
+ * early trap. The global data pointer will be set its actual value only
+ * after it has been initialized.
+ */
+ mv gp, zero
+
+ /*
+ * Set the trap handler. This must happen after initializing gp because
+ * the handler may use it.
+ */
la t0, trap_entry
csrw MODE_PREFIX(tvec), t0
- /* mask all interrupts */
+ /*
+ * Mask all interrupts. Interrupts are disabled globally (in m/sstatus)
+ * for U-Boot, but we will need to read m/sip to determine if we get an
+ * IPI
+ */
csrw MODE_PREFIX(ie), zero
#if CONFIG_IS_ENABLED(SMP)
@@ -65,8 +83,6 @@ _start:
#else
li t0, SIE_SSIE
#endif
- /* Clear any pending IPIs */
- csrc MODE_PREFIX(ip), t0
csrs MODE_PREFIX(ie), t0
#endif
@@ -87,10 +103,10 @@ call_board_init_f_0:
jal board_init_f_alloc_reserve
/*
- * Set global data pointer here for all harts, uninitialized at this
- * point.
+ * Save global data pointer for later. We don't set it here because it
+ * is not initialized yet.
*/
- mv gp, a0
+ mv s0, a0
/* setup stack */
#if CONFIG_IS_ENABLED(SMP)
@@ -111,6 +127,14 @@ call_board_init_f_0:
amoswap.w s2, t1, 0(t0)
bnez s2, wait_for_gd_init
#else
+ /*
+ * FIXME: gp is set before it is initialized. If an XIP U-Boot ever
+ * encounters a pending IPI on boot it is liable to jump to whatever
+ * memory happens to be in ipi_data.addr on boot. It may also run into
+ * problems if it encounters an exception too early (because printf/puts
+ * accesses gd).
+ */
+ mv gp, s0
bnez tp, secondary_hart_loop
#endif
@@ -127,16 +151,21 @@ call_board_init_f_0:
#ifndef CONFIG_XIP
la t0, available_harts_lock
- fence rw, w
- amoswap.w zero, zero, 0(t0)
+ amoswap.w.rl zero, zero, 0(t0)
wait_for_gd_init:
la t0, available_harts_lock
li t1, 1
-1: amoswap.w t1, t1, 0(t0)
- fence r, rw
+1: amoswap.w.aq t1, t1, 0(t0)
bnez t1, 1b
+ /*
+ * Set the global data pointer only when gd_t has been initialized.
+ * This was already set by arch_setup_gd on the boot hart, but all other
+ * harts' global data pointers gets set here.
+ */
+ mv gp, s0
+
/* register available harts in the available_harts mask */
li t1, 1
sll t1, t1, tp
@@ -144,8 +173,7 @@ wait_for_gd_init:
or t2, t2, t1
SREG t2, GD_AVAILABLE_HARTS(gp)
- fence rw, w
- amoswap.w zero, zero, 0(t0)
+ amoswap.w.rl zero, zero, 0(t0)
/*
* Continue on hart lottery winner, others branch to
@@ -395,6 +423,10 @@ secondary_hart_relocate:
mv gp, a2
#endif
+/*
+ * Interrupts are disabled globally, but they can still be read from m/sip. The
+ * wfi function will wake us up if we get an IPI, even if we do not trap.
+ */
secondary_hart_loop:
wfi
diff --git a/arch/riscv/dts/fu540-c000-u-boot.dtsi b/arch/riscv/dts/fu540-c000-u-boot.dtsi
index 5302677ee4..a06e1b11c6 100644
--- a/arch/riscv/dts/fu540-c000-u-boot.dtsi
+++ b/arch/riscv/dts/fu540-c000-u-boot.dtsi
@@ -55,9 +55,13 @@
reg = <0x0 0x10070000 0x0 0x1000>;
fuse-count = <0x1000>;
};
- clint@2000000 {
+ clint: clint@2000000 {
compatible = "riscv,clint0";
- interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 &cpu1_intc 3 &cpu1_intc 7 &cpu2_intc 3 &cpu2_intc 7 &cpu3_intc 3 &cpu3_intc 7 &cpu4_intc 3 &cpu4_intc 7>;
+ interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7
+ &cpu1_intc 3 &cpu1_intc 7
+ &cpu2_intc 3 &cpu2_intc 7
+ &cpu3_intc 3 &cpu3_intc 7
+ &cpu4_intc 3 &cpu4_intc 7>;
reg = <0x0 0x2000000 0x0 0xc0000>;
u-boot,dm-spl;
};
diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
index 5d0c928b29..1996149c95 100644
--- a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
+++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
@@ -34,6 +34,10 @@
};
+&clint {
+ clocks = <&rtcclk>;
+};
+
&qspi0 {
u-boot,dm-spl;
diff --git a/arch/riscv/dts/k210.dtsi b/arch/riscv/dts/k210.dtsi
index 2546c7d4e0..84cff51c36 100644
--- a/arch/riscv/dts/k210.dtsi
+++ b/arch/riscv/dts/k210.dtsi
@@ -17,6 +17,8 @@
compatible = "kendryte,k210";
aliases {
+ cpu0 = &cpu0;
+ cpu1 = &cpu1;
dma0 = &dmac0;
gpio0 = &gpio0;
gpio1 = &gpio1_0;
@@ -126,14 +128,13 @@
read-only;
};
- clint0: interrupt-controller@2000000 {
+ clint0: clint@2000000 {
#interrupt-cells = <1>;
compatible = "kendryte,k210-clint", "riscv,clint0";
reg = <0x2000000 0xC000>;
- interrupt-controller;
interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>,
<&cpu1_intc 3>, <&cpu1_intc 7>;
- clocks = <&sysclk K210_CLK_CPU>;
+ clocks = <&sysclk K210_CLK_CLINT>;
};
plic0: interrupt-controller@C000000 {
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index b711fcc44d..d3a0b1d221 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -24,9 +24,6 @@ struct arch_global_data {
#ifdef CONFIG_ANDES_PLIC
void __iomem *plic; /* plic base address */
#endif
-#ifdef CONFIG_ANDES_PLMT
- void __iomem *plmt; /* plmt base address */
-#endif
#if CONFIG_IS_ENABLED(SMP)
struct ipi_data ipi[CONFIG_NR_CPUS];
#endif
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 1b428856b2..2dae0800ce 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -18,14 +18,21 @@
* IPI data structure. The hart ID is inserted by the hart handling the IPI and
* calling the function.
*
+ * @valid is used to determine whether a sent IPI originated from U-Boot. It is
+ * initialized to zero by board_init_f_alloc_reserve. When U-Boot sends its
+ * first IPI, it is set to 1. This prevents already-pending IPIs not sent by
+ * U-Boot from being taken.
+ *
* @addr: Address of function
* @arg0: First argument of function
* @arg1: Second argument of function
+ * @valid: Whether this IPI is valid
*/
struct ipi_data {
ulong addr;
ulong arg0;
ulong arg1;
+ unsigned int valid;
};
/**
diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
index 26a008ca59..c3629e4b53 100644
--- a/arch/riscv/include/asm/syscon.h
+++ b/arch/riscv/include/asm/syscon.h
@@ -7,13 +7,13 @@
#define _ASM_SYSCON_H
/*
- * System controllers in a RISC-V system
+ * System controllers in a RISC-V system. These should only be used for
+ * identifying IPI controllers. Other devices should use DM to probe.
*/
enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */
- RISCV_SYSCON_PLMT, /* Platform Level Machine Timer (PLMT) */
};
#endif /* _ASM_SYSCON_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 6c503ff2b2..10ac5b06d3 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-$(CONFIG_ANDES_PLIC) += andes_plic.o
obj-$(CONFIG_ANDES_PLMT) += andes_plmt.o
else
-obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SBI) += sbi.o
obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
endif
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
index c2a8fe4d9e..267d6a191b 100644
--- a/arch/riscv/lib/andes_plic.c
+++ b/arch/riscv/lib/andes_plic.c
@@ -41,53 +41,45 @@ static int enable_ipi(int hart)
return 0;
}
-static int init_plic(void)
+int riscv_init_ipi(void)
{
- struct udevice *dev;
- ofnode node;
int ret;
+ long *base = syscon_get_first_range(RISCV_SYSCON_PLIC);
+ ofnode node;
+ struct udevice *dev;
u32 reg;
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ gd->arch.plic = base;
+
ret = uclass_find_first_device(UCLASS_CPU, &dev);
if (ret)
return ret;
+ else if (!dev)
+ return -ENODEV;
- if (dev) {
- ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
- const char *device_type;
-
- device_type = ofnode_read_string(node, "device_type");
- if (!device_type)
- continue;
+ ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
+ const char *device_type;
- if (strcmp(device_type, "cpu"))
- continue;
+ device_type = ofnode_read_string(node, "device_type");
+ if (!device_type)
+ continue;
- /* skip if hart is marked as not available */
- if (!ofnode_is_available(node))
- continue;
+ if (strcmp(device_type, "cpu"))
+ continue;
- /* read hart ID of CPU */
- ret = ofnode_read_u32(node, "reg", &reg);
- if (ret == 0)
- enable_ipi(reg);
- }
+ /* skip if hart is marked as not available */
+ if (!ofnode_is_available(node))
+ continue;
- return 0;
+ /* read hart ID of CPU */
+ ret = ofnode_read_u32(node, "reg", &reg);
+ if (ret == 0)
+ enable_ipi(reg);
}
- return -ENODEV;
-}
-
-int riscv_init_ipi(void)
-{
- long *ret = syscon_get_first_range(RISCV_SYSCON_PLIC);
-
- if (IS_ERR(ret))
- return PTR_ERR(ret);
- gd->arch.plic = ret;
-
- return init_plic();
+ return 0;
}
int riscv_send_ipi(int hart)
diff --git a/arch/riscv/lib/andes_plmt.c b/arch/riscv/lib/andes_plmt.c
index a7e90ca992..a28c14c1eb 100644
--- a/arch/riscv/lib/andes_plmt.c
+++ b/arch/riscv/lib/andes_plmt.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019, Rick Chen <rick@andestech.com>
+ * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
*
* U-Boot syscon driver for Andes's Platform Level Machine Timer (PLMT).
* The PLMT block holds memory-mapped mtime register
@@ -9,46 +10,43 @@
#include <common.h>
#include <dm.h>
-#include <regmap.h>
-#include <syscon.h>
+#include <timer.h>
#include <asm/io.h>
-#include <asm/syscon.h>
#include <linux/err.h>
/* mtime register */
#define MTIME_REG(base) ((ulong)(base))
-DECLARE_GLOBAL_DATA_PTR;
-
-#define PLMT_BASE_GET(void) \
- do { \
- long *ret; \
- \
- if (!gd->arch.plmt) { \
- ret = syscon_get_first_range(RISCV_SYSCON_PLMT); \
- if (IS_ERR(ret)) \
- return PTR_ERR(ret); \
- gd->arch.plmt = ret; \
- } \
- } while (0)
-
-int riscv_get_time(u64 *time)
+static int andes_plmt_get_count(struct udevice *dev, u64 *count)
{
- PLMT_BASE_GET();
-
- *time = readq((void __iomem *)MTIME_REG(gd->arch.plmt));
+ *count = readq((void __iomem *)MTIME_REG(dev->priv));
return 0;
}
+static const struct timer_ops andes_plmt_ops = {
+ .get_count = andes_plmt_get_count,
+};
+
+static int andes_plmt_probe(struct udevice *dev)
+{
+ dev->priv = dev_read_addr_ptr(dev);
+ if (!dev->priv)
+ return -EINVAL;
+
+ return timer_timebase_fallback(dev);
+}
+
static const struct udevice_id andes_plmt_ids[] = {
- { .compatible = "riscv,plmt0", .data = RISCV_SYSCON_PLMT },
+ { .compatible = "riscv,plmt0" },
{ }
};
U_BOOT_DRIVER(andes_plmt) = {
.name = "andes_plmt",
- .id = UCLASS_SYSCON,
+ .id = UCLASS_TIMER,
.of_match = andes_plmt_ids,
+ .ops = &andes_plmt_ops,
+ .probe = andes_plmt_probe,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/arch/riscv/lib/fdt_fixup.c b/arch/riscv/lib/fdt_fixup.c
index 5b2420243f..d02062fd5b 100644
--- a/arch/riscv/lib/fdt_fixup.c
+++ b/arch/riscv/lib/fdt_fixup.c
@@ -75,7 +75,7 @@ int riscv_fdt_copy_resv_mem_node(const void *src, void *dst)
pmp_mem.start = addr;
pmp_mem.end = addr + size - 1;
err = fdtdec_add_reserved_memory(dst, basename, &pmp_mem,
- &phandle);
+ &phandle, false);
if (err < 0 && err != -FDT_ERR_EXISTS) {
log_err("failed to add reserved memory: %d\n", err);
return err;
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index 8ff40f0f36..35de98e8ce 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -78,7 +78,8 @@ static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
printf("EPC: " REG_FMT " RA: " REG_FMT " TVAL: " REG_FMT "\n",
epc, regs->ra, tval);
- if (gd->flags & GD_FLG_RELOC)
+ /* Print relocation adjustments, but only if gd is initialized */
+ if (gd && gd->flags & GD_FLG_RELOC)
printf("EPC: " REG_FMT " RA: " REG_FMT " reloc adjusted\n\n",
epc - gd->reloc_off, regs->ra - gd->reloc_off);
diff --git a/arch/riscv/lib/rdtime.c b/arch/riscv/lib/rdtime.c
deleted file mode 100644
index e128d7fce6..0000000000
--- a/arch/riscv/lib/rdtime.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
- * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
- *
- * The riscv_get_time() API implementation that is using the
- * standard rdtime instruction.
- */
-
-#include <common.h>
-
-/* Implement the API required by RISC-V timer driver */
-int riscv_get_time(u64 *time)
-{
-#ifdef CONFIG_64BIT
- u64 n;
-
- __asm__ __volatile__ (
- "rdtime %0"
- : "=r" (n));
-
- *time = n;
-#else
- u32 lo, hi, tmp;
-
- __asm__ __volatile__ (
- "1:\n"
- "rdtimeh %0\n"
- "rdtime %1\n"
- "rdtimeh %2\n"
- "bne %0, %2, 1b"
- : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
-
- *time = ((u64)hi << 32) | lo;
-#endif
-
- return 0;
-}
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
index b9a2c649cc..c9704c596f 100644
--- a/arch/riscv/lib/sifive_clint.c
+++ b/arch/riscv/lib/sifive_clint.c
@@ -8,9 +8,9 @@
*/
#include <common.h>
+#include <clk.h>
#include <dm.h>
-#include <regmap.h>
-#include <syscon.h>
+#include <timer.h>
#include <asm/io.h>
#include <asm/syscon.h>
#include <linux/err.h>
@@ -24,68 +24,74 @@
DECLARE_GLOBAL_DATA_PTR;
-int riscv_get_time(u64 *time)
+int riscv_init_ipi(void)
{
- /* ensure timer register base has a sane value */
- riscv_init_ipi();
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_driver(UCLASS_TIMER,
+ DM_GET_DRIVER(sifive_clint), &dev);
+ if (ret)
+ return ret;
- *time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
+ gd->arch.clint = dev_read_addr_ptr(dev);
+ if (!gd->arch.clint)
+ return -EINVAL;
return 0;
}
-int riscv_set_timecmp(int hart, u64 cmp)
+int riscv_send_ipi(int hart)
{
- /* ensure timer register base has a sane value */
- riscv_init_ipi();
-
- writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
+ writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
-int riscv_init_ipi(void)
+int riscv_clear_ipi(int hart)
{
- if (!gd->arch.clint) {
- long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
-
- if (IS_ERR(ret))
- return PTR_ERR(ret);
- gd->arch.clint = ret;
- }
+ writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
-int riscv_send_ipi(int hart)
+int riscv_get_ipi(int hart, int *pending)
{
- writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+ *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
-int riscv_clear_ipi(int hart)
+static int sifive_clint_get_count(struct udevice *dev, u64 *count)
{
- writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+ *count = readq((void __iomem *)MTIME_REG(dev->priv));
return 0;
}
-int riscv_get_ipi(int hart, int *pending)
+static const struct timer_ops sifive_clint_ops = {
+ .get_count = sifive_clint_get_count,
+};
+
+static int sifive_clint_probe(struct udevice *dev)
{
- *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
+ dev->priv = dev_read_addr_ptr(dev);
+ if (!dev->priv)
+ return -EINVAL;
- return 0;
+ return timer_timebase_fallback(dev);
}
static const struct udevice_id sifive_clint_ids[] = {
- { .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
+ { .compatible = "riscv,clint0" },
{ }
};
U_BOOT_DRIVER(sifive_clint) = {
.name = "sifive_clint",
- .id = UCLASS_SYSCON,
+ .id = UCLASS_TIMER,
.of_match = sifive_clint_ids,
+ .probe = sifive_clint_probe,
+ .ops = &sifive_clint_ops,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
index ac22136314..8f33ce1fe3 100644
--- a/arch/riscv/lib/smp.c
+++ b/arch/riscv/lib/smp.c
@@ -54,6 +54,14 @@ static int send_ipi_many(struct ipi_data *ipi, int wait)
gd->arch.ipi[reg].arg0 = ipi->arg0;
gd->arch.ipi[reg].arg1 = ipi->arg1;
+ /*
+ * Ensure valid only becomes set when the IPI parameters are
+ * set. An IPI may already be pending on other harts, so we
+ * need a way to signal that the IPI device has been
+ * initialized, and that it is ok to call the function.
+ */
+ __smp_store_release(&gd->arch.ipi[reg].valid, 1);
+
ret = riscv_send_ipi(reg);
if (ret) {
pr_err("Cannot send IPI to hart %d\n", reg);
@@ -81,7 +89,13 @@ void handle_ipi(ulong hart)
if (hart >= CONFIG_NR_CPUS)
return;
- __smp_mb();
+ /*
+ * If valid is not set, then U-Boot has not requested the IPI. The
+ * IPI device may not be initialized, so all we can do is wait for
+ * U-Boot to initialize it and send an IPI
+ */
+ if (!__smp_load_acquire(&gd->arch.ipi[hart].valid))
+ return;
smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
invalidate_icache_all();