[PATCH 4/6] riscv: Rework Sifive CLINT as UCLASS_TIMER driver

Sean Anderson seanga2 at gmail.com
Wed Jul 22 17:51:08 CEST 2020


This converts the clint driver from the riscv-specific interface to be a
DM-based UCLASS_TIMER driver. We also need to re-add the initialization for
IPI back into the SPL code. This was previously implicitly done when the
timer was initialized. In addition, the SiFive DDR driver previously
implicitly depended on the CLINT to select REGMAP.

Unlike Andes's PLMT/PLIC (which AFAIK never have anything pass it a dtb),
the SiFive CLINT is part of the device tree passed in by qemu. This device
tree doesn't have a clocks or clock-frequency property on clint, so we need
to fall back on the timebase-frequency property. Perhaps in the future we
can get a clock-frequency property added to the qemu dtb.

Signed-off-by: Sean Anderson <seanga2 at gmail.com>
f

---
This patch builds but has only been tested on the K210 and QEMU. It has NOT
been tested on a HiFive.

 arch/riscv/Kconfig            |  4 --
 arch/riscv/lib/sifive_clint.c | 87 +++++++++++++++++++++++------------
 common/spl/spl_opensbi.c      |  5 ++
 drivers/ram/sifive/Kconfig    |  2 +
 4 files changed, 64 insertions(+), 34 deletions(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 502f27b92d..f2641ffc53 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.
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
index b9a2c649cc..3345a17ad2 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,35 +24,19 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int riscv_get_time(u64 *time)
-{
-	/* ensure timer register base has a sane value */
-	riscv_init_ipi();
-
-	*time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
-
-	return 0;
-}
-
-int riscv_set_timecmp(int hart, u64 cmp)
-{
-	/* ensure timer register base has a sane value */
-	riscv_init_ipi();
-
-	writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
-
-	return 0;
-}
-
 int riscv_init_ipi(void)
 {
-	if (!gd->arch.clint) {
-		long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
+	int ret;
+	struct udevice *dev;
 
-		if (IS_ERR(ret))
-			return PTR_ERR(ret);
-		gd->arch.clint = ret;
-	}
+	ret = uclass_get_device_by_driver(UCLASS_TIMER,
+					  DM_GET_DRIVER(sifive_clint), &dev);
+	if (ret)
+		return ret;
+
+	gd->arch.clint = dev_read_addr_ptr(dev);
+	if (!gd->arch.clint)
+		return -EINVAL;
 
 	return 0;
 }
@@ -78,14 +62,57 @@ int riscv_get_ipi(int hart, int *pending)
 	return 0;
 }
 
+static int sifive_clint_get_count(struct udevice *dev, u64 *count)
+{
+	*count = readq((void __iomem *)MTIME_REG(dev->priv));
+
+	return 0;
+}
+
+static const struct timer_ops sifive_clint_ops = {
+	.get_count = sifive_clint_get_count,
+};
+
+static int sifive_clint_probe(struct udevice *dev)
+{
+	int ret;
+	ofnode cpu;
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	u32 rate;
+
+	dev->priv = dev_read_addr_ptr(dev);
+	if (!dev->priv)
+		return -EINVAL;
+
+	/* Did we get our clock rate from the device tree? */
+	if (uc_priv->clock_rate)
+		return 0;
+
+	/* Fall back to timebase-frequency */
+	cpu = ofnode_path("/cpus");
+	if (!ofnode_valid(cpu))
+		return -EINVAL;
+
+	ret = ofnode_read_u32(cpu, "timebase-frequency", &rate);
+	if (ret)
+		return ret;
+
+	log_warning("missing clocks or clock-frequency property, falling back on timebase-frequency\n");
+	uc_priv->clock_rate = rate;
+
+	return 0;
+}
+
 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/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c
index 14f335f75f..3440bc0294 100644
--- a/common/spl/spl_opensbi.c
+++ b/common/spl/spl_opensbi.c
@@ -79,6 +79,11 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image)
 	invalidate_icache_all();
 
 #ifdef CONFIG_SPL_SMP
+	/* Initialize the IPI before we use it */
+	ret = riscv_init_ipi();
+	if (ret)
+		hang();
+
 	/*
 	 * Start OpenSBI on all secondary harts and wait for acknowledgment.
 	 *
diff --git a/drivers/ram/sifive/Kconfig b/drivers/ram/sifive/Kconfig
index 6aca22ab2a..31ad0a7e45 100644
--- a/drivers/ram/sifive/Kconfig
+++ b/drivers/ram/sifive/Kconfig
@@ -9,5 +9,7 @@ config SIFIVE_FU540_DDR
 	bool "SiFive FU540 DDR driver"
 	depends on RAM_SIFIVE
 	default y if TARGET_SIFIVE_FU540
+	select REGMAP
+	select SPL_REGMAP if SPL
 	help
 	  This enables DDR support for the platforms based on SiFive FU540 SoC.
-- 
2.27.0



More information about the U-Boot mailing list