riscv: Rework Andes PLMT as a UCLASS_TIMER driver
authorSean Anderson <seanga2@gmail.com>
Mon, 28 Sep 2020 14:52:24 +0000 (10:52 -0400)
committerAndes <uboot@andestech.com>
Wed, 30 Sep 2020 00:54:45 +0000 (08:54 +0800)
This converts the PLMT driver from the riscv-specific timer interface to be
a DM-based UCLASS_TIMER driver.

The clock-frequency/clocks properties are preferred over timebase-frequency
for two reasons. First, properties which affect a device should be located
near its binding in the device tree. Using timebase-frequency only really
makes sense when the cpu itself is the timer device. This is the case when
we read the time from a CSR, but not when there is a separate device.
Second, it lets the device use the clock subsystem which adds flexibility.
If the device is configured for a different clock speed, the timer can
adjust itself.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Rick Chen <rick@andestech.com>
arch/riscv/Kconfig
arch/riscv/include/asm/global_data.h
arch/riscv/include/asm/syscon.h
arch/riscv/lib/andes_plmt.c

index 21e6690..d9155b9 100644 (file)
@@ -177,10 +177,6 @@ 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.
index b711fcc..d3a0b1d 100644 (file)
@@ -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
index 26a008c..c3629e4 100644 (file)
@@ -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 */
index a7e90ca..a28c14c 100644 (file)
@@ -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
 
 #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,
 };