aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/timer
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/timer')
-rw-r--r--roms/u-boot/drivers/timer/Kconfig237
-rw-r--r--roms/u-boot/drivers/timer/Makefile28
-rw-r--r--roms/u-boot/drivers/timer/ag101p_timer.c117
-rw-r--r--roms/u-boot/drivers/timer/altera_timer.c94
-rw-r--r--roms/u-boot/drivers/timer/andes_plmt_timer.c70
-rw-r--r--roms/u-boot/drivers/timer/arc_timer.c110
-rw-r--r--roms/u-boot/drivers/timer/ast_timer.c92
-rw-r--r--roms/u-boot/drivers/timer/atcpit100_timer.c112
-rw-r--r--roms/u-boot/drivers/timer/atmel_pit_timer.c87
-rw-r--r--roms/u-boot/drivers/timer/cadence-ttc.c117
-rw-r--r--roms/u-boot/drivers/timer/dw-apb-timer.c103
-rw-r--r--roms/u-boot/drivers/timer/imx-gpt-timer.c162
-rw-r--r--roms/u-boot/drivers/timer/mchp-pit64b-timer.c107
-rw-r--r--roms/u-boot/drivers/timer/mpc83xx_timer.c253
-rw-r--r--roms/u-boot/drivers/timer/mtk_timer.c95
-rw-r--r--roms/u-boot/drivers/timer/nomadik-mtu-timer.c113
-rw-r--r--roms/u-boot/drivers/timer/omap-timer.c106
-rw-r--r--roms/u-boot/drivers/timer/ostm_timer.c93
-rw-r--r--roms/u-boot/drivers/timer/riscv_timer.c73
-rw-r--r--roms/u-boot/drivers/timer/rockchip_timer.c174
-rw-r--r--roms/u-boot/drivers/timer/sandbox_timer.c71
-rw-r--r--roms/u-boot/drivers/timer/sifive_clint_timer.c68
-rw-r--r--roms/u-boot/drivers/timer/sti-timer.c85
-rw-r--r--roms/u-boot/drivers/timer/stm32_timer.c138
-rw-r--r--roms/u-boot/drivers/timer/timer-uclass.c177
-rw-r--r--roms/u-boot/drivers/timer/tsc_timer.c494
26 files changed, 3376 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/timer/Kconfig b/roms/u-boot/drivers/timer/Kconfig
new file mode 100644
index 000000000..ee81dfa77
--- /dev/null
+++ b/roms/u-boot/drivers/timer/Kconfig
@@ -0,0 +1,237 @@
+menu "Timer Support"
+
+config TIMER
+ bool "Enable driver model for timer drivers"
+ depends on DM
+ help
+ Enable driver model for timer access. It uses the same API as
+ lib/time.c, but now implemented by the uclass. The first timer
+ will be used. The timer is usually a 32 bits free-running up
+ counter. There may be no real tick, and no timer interrupt.
+
+config SPL_TIMER
+ bool "Enable driver model for timer drivers in SPL"
+ depends on TIMER && SPL
+ help
+ Enable support for timer drivers in SPL. These can be used to get
+ a timer value when in SPL, or perhaps for implementing a delay
+ function. This enables the drivers in drivers/timer as part of an
+ SPL build.
+
+config TPL_TIMER
+ bool "Enable driver model for timer drivers in TPL"
+ depends on TIMER && TPL
+ help
+ Enable support for timer drivers in TPL. These can be used to get
+ a timer value when in TPL, or perhaps for implementing a delay
+ function. This enables the drivers in drivers/timer as part of an
+ TPL build.
+
+config TIMER_EARLY
+ bool "Allow timer to be used early in U-Boot"
+ depends on TIMER
+ # initr_bootstage() requires a timer and is called before initr_dm()
+ # so only the early timer is available
+ default y if X86 && BOOTSTAGE
+ help
+ In some cases the timer must be accessible before driver model is
+ active. Examples include when using CONFIG_TRACE to trace U-Boot's
+ execution before driver model is set up. Enable this option to
+ use an early timer. These functions must be supported by your timer
+ driver: timer_early_get_count() and timer_early_get_rate().
+
+config AG101P_TIMER
+ bool "AG101P timer support"
+ depends on TIMER && NDS32
+ help
+ Select this to enable a timer for AG01P devices.
+
+config ALTERA_TIMER
+ bool "Altera timer support"
+ depends on TIMER
+ help
+ Select this to enable a timer for Altera devices. Please find
+ details on the "Embedded Peripherals IP User Guide" of Altera.
+
+config ANDES_PLMT_TIMER
+ bool
+ depends on RISCV_MMODE || SPL_RISCV_MMODE
+ help
+ The Andes PLMT block holds memory-mapped mtime register
+ associated with timer tick.
+
+config ARC_TIMER
+ bool "ARC timer support"
+ depends on TIMER && ARC && CLK
+ help
+ Select this to enable built-in ARC timers.
+ ARC cores may have up to 2 built-in timers: timer0 and timer1,
+ usually at least one of them exists. Either of them is supported
+ in U-Boot.
+
+config AST_TIMER
+ bool "Aspeed ast2400/ast2500 timer support"
+ depends on TIMER
+ default y if ARCH_ASPEED
+ help
+ Select this to enable timer for Aspeed ast2400/ast2500 devices.
+ This is a simple sys timer driver, it is compatible with lib/time.c,
+ but does not support any interrupts. Even though SoC has 8 hardware
+ counters, they are all treated as a single device by this driver.
+ This is mostly because they all share several registers which
+ makes it difficult to completely separate them.
+
+config ATCPIT100_TIMER
+ bool "ATCPIT100 timer support"
+ depends on TIMER
+ help
+ Select this to enable a ATCPIT100 timer which will be embedded
+ in AE3XX, AE250 boards.
+
+config ATMEL_PIT_TIMER
+ bool "Atmel periodic interval timer support"
+ depends on TIMER
+ help
+ Select this to enable a periodic interval timer for Atmel devices,
+ it is designed to offer maximum accuracy and efficient management,
+ even for systems with long response time.
+
+config CADENCE_TTC_TIMER
+ bool "Cadence TTC (Triple Timer Counter)"
+ depends on TIMER
+ help
+ Enables support for the cadence ttc driver. This driver is present
+ on Xilinx Zynq and ZynqMP SoCs.
+
+config DESIGNWARE_APB_TIMER
+ bool "Designware APB Timer"
+ depends on TIMER
+ help
+ Enables support for the Designware APB Timer driver. This timer is
+ present on Altera SoCFPGA SoCs.
+
+config MPC83XX_TIMER
+ bool "MPC83xx timer support"
+ depends on TIMER
+ help
+ Select this to enable support for the timer found on
+ devices based on the MPC83xx family of SoCs.
+
+config RENESAS_OSTM_TIMER
+ bool "Renesas RZ/A1 R7S72100 OSTM Timer"
+ depends on TIMER
+ help
+ Enables support for the Renesas OSTM Timer driver.
+ This timer is present on Renesas RZ/A1 R7S72100 SoCs.
+
+config X86_TSC_TIMER_EARLY_FREQ
+ int "x86 TSC timer frequency in MHz when used as the early timer"
+ depends on X86_TSC_TIMER
+ default 1000
+ help
+ Sets the estimated CPU frequency in MHz when TSC is used as the
+ early timer and the frequency can neither be calibrated via some
+ hardware ways, nor got from device tree at the time when device
+ tree is not available yet.
+
+config NOMADIK_MTU_TIMER
+ bool "Nomadik MTU Timer"
+ depends on TIMER
+ help
+ Enables support for the Nomadik Multi Timer Unit (MTU),
+ used in ST-Ericsson Ux500 SoCs.
+ The MTU provides 4 decrementing free-running timers.
+ At the moment, only the first timer is used by the driver.
+
+config OMAP_TIMER
+ bool "Omap timer support"
+ depends on TIMER
+ help
+ Select this to enable an timer for Omap devices.
+
+config RISCV_TIMER
+ bool "RISC-V timer support"
+ depends on TIMER && RISCV
+ help
+ Select this to enable support for a generic RISC-V S-Mode timer
+ driver.
+
+config ROCKCHIP_TIMER
+ bool "Rockchip timer support"
+ depends on TIMER
+ help
+ Select this to enable support for the timer found on
+ Rockchip devices.
+
+config SANDBOX_TIMER
+ bool "Sandbox timer support"
+ depends on SANDBOX && TIMER
+ help
+ Select this to enable an emulated timer for sandbox. It gets
+ time from host os.
+
+config STI_TIMER
+ bool "STi timer support"
+ depends on TIMER
+ default y if ARCH_STI
+ help
+ Select this to enable a timer for STi devices.
+
+config STM32_TIMER
+ bool "STM32 timer support"
+ depends on TIMER
+ help
+ Select this to enable support for the timer found on
+ STM32 devices.
+
+config X86_TSC_TIMER
+ bool "x86 Time-Stamp Counter (TSC) timer support"
+ depends on TIMER && X86
+ help
+ Select this to enable Time-Stamp Counter (TSC) timer for x86.
+
+config X86_TSC_READ_BASE
+ bool "Read the TSC timer base on start-up"
+ depends on X86_TSC_TIMER
+ help
+ On x86 platforms the TSC timer tick starts at the value 0 on reset.
+ This it makes no sense to read the timer on boot and use that as the
+ base, since we will miss some time taken to load U-Boot, etc. This
+ delay is controlled by the SoC and we cannot reduce it, but for
+ bootstage we want to record the time since reset as accurately as
+ possible.
+
+ The only exception is when U-Boot is used as a secondary bootloader,
+ where this option should be enabled.
+
+config TPL_X86_TSC_TIMER_NATIVE
+ bool "x86 TSC timer uses native calibration"
+ depends on TPL && X86_TSC_TIMER
+ help
+ Selects native timer calibration for TPL and don't include the other
+ methods in the code. This helps to reduce code size in TPL and works
+ on fairly modern Intel chips. Code-size reductions is about 700
+ bytes.
+
+config MTK_TIMER
+ bool "MediaTek timer support"
+ depends on TIMER
+ help
+ Select this to enable support for the timer found on
+ MediaTek devices.
+
+config MCHP_PIT64B_TIMER
+ bool "Microchip 64-bit periodic interval timer support"
+ depends on TIMER
+ help
+ Select this to enable support for Microchip 64-bit periodic
+ interval timer.
+
+config IMX_GPT_TIMER
+ bool "NXP i.MX GPT timer support"
+ depends on TIMER
+ help
+ Select this to enable support for the timer found on
+ NXP i.MX devices.
+
+endmenu
diff --git a/roms/u-boot/drivers/timer/Makefile b/roms/u-boot/drivers/timer/Makefile
new file mode 100644
index 000000000..e2bd530eb
--- /dev/null
+++ b/roms/u-boot/drivers/timer/Makefile
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+
+obj-y += timer-uclass.o
+obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o
+obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
+obj-$(CONFIG_ANDES_PLMT_TIMER) += andes_plmt_timer.o
+obj-$(CONFIG_ARC_TIMER) += arc_timer.o
+obj-$(CONFIG_AST_TIMER) += ast_timer.o
+obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
+obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o
+obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
+obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
+obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
+obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o
+obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
+obj-$(CONFIG_RENESAS_OSTM_TIMER) += ostm_timer.o
+obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
+obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
+obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
+obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint_timer.o
+obj-$(CONFIG_STI_TIMER) += sti-timer.o
+obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
+obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
+obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
+obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o
+obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o
diff --git a/roms/u-boot/drivers/timer/ag101p_timer.c b/roms/u-boot/drivers/timer/ag101p_timer.c
new file mode 100644
index 000000000..27cf9b024
--- /dev/null
+++ b/roms/u-boot/drivers/timer/ag101p_timer.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Andestech ATFTMR010 timer driver
+ *
+ * (C) Copyright 2016
+ * Rick Chen, NDS32 Software Engineering, rick@andestech.com
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <linux/io.h>
+
+/*
+ * Timer Control Register
+ */
+#define T3_UPDOWN (1 << 11)
+#define T2_UPDOWN (1 << 10)
+#define T1_UPDOWN (1 << 9)
+#define T3_OFENABLE (1 << 8)
+#define T3_CLOCK (1 << 7)
+#define T3_ENABLE (1 << 6)
+#define T2_OFENABLE (1 << 5)
+#define T2_CLOCK (1 << 4)
+#define T2_ENABLE (1 << 3)
+#define T1_OFENABLE (1 << 2)
+#define T1_CLOCK (1 << 1)
+#define T1_ENABLE (1 << 0)
+
+/*
+ * Timer Interrupt State & Mask Registers
+ */
+#define T3_OVERFLOW (1 << 8)
+#define T3_MATCH2 (1 << 7)
+#define T3_MATCH1 (1 << 6)
+#define T2_OVERFLOW (1 << 5)
+#define T2_MATCH2 (1 << 4)
+#define T2_MATCH1 (1 << 3)
+#define T1_OVERFLOW (1 << 2)
+#define T1_MATCH2 (1 << 1)
+#define T1_MATCH1 (1 << 0)
+
+struct atftmr_timer_regs {
+ u32 t1_counter; /* 0x00 */
+ u32 t1_load; /* 0x04 */
+ u32 t1_match1; /* 0x08 */
+ u32 t1_match2; /* 0x0c */
+ u32 t2_counter; /* 0x10 */
+ u32 t2_load; /* 0x14 */
+ u32 t2_match1; /* 0x18 */
+ u32 t2_match2; /* 0x1c */
+ u32 t3_counter; /* 0x20 */
+ u32 t3_load; /* 0x24 */
+ u32 t3_match1; /* 0x28 */
+ u32 t3_match2; /* 0x2c */
+ u32 cr; /* 0x30 */
+ u32 int_state; /* 0x34 */
+ u32 int_mask; /* 0x38 */
+};
+
+struct atftmr_timer_plat {
+ struct atftmr_timer_regs *regs;
+};
+
+static u64 atftmr_timer_get_count(struct udevice *dev)
+{
+ struct atftmr_timer_plat *plat = dev_get_plat(dev);
+ struct atftmr_timer_regs *const regs = plat->regs;
+ u32 val;
+ val = readl(&regs->t3_counter);
+ return timer_conv_64(val);
+}
+
+static int atftmr_timer_probe(struct udevice *dev)
+{
+ struct atftmr_timer_plat *plat = dev_get_plat(dev);
+ struct atftmr_timer_regs *const regs = plat->regs;
+ u32 cr;
+ writel(0, &regs->t3_load);
+ writel(0, &regs->t3_counter);
+ writel(TIMER_LOAD_VAL, &regs->t3_match1);
+ writel(TIMER_LOAD_VAL, &regs->t3_match2);
+ /* disable interrupts */
+ writel(T3_MATCH1|T3_MATCH2|T3_OVERFLOW , &regs->int_mask);
+ cr = readl(&regs->cr);
+ cr |= (T3_ENABLE|T3_UPDOWN);
+ writel(cr, &regs->cr);
+ return 0;
+}
+
+static int atftme_timer_of_to_plat(struct udevice *dev)
+{
+ struct atftmr_timer_plat *plat = dev_get_plat(dev);
+ plat->regs = map_physmem(dev_read_addr(dev),
+ sizeof(struct atftmr_timer_regs),
+ MAP_NOCACHE);
+ return 0;
+}
+
+static const struct timer_ops ag101p_timer_ops = {
+ .get_count = atftmr_timer_get_count,
+};
+
+static const struct udevice_id ag101p_timer_ids[] = {
+ { .compatible = "andestech,attmr010" },
+ {}
+};
+
+U_BOOT_DRIVER(altera_timer) = {
+ .name = "ag101p_timer",
+ .id = UCLASS_TIMER,
+ .of_match = ag101p_timer_ids,
+ .of_to_plat = atftme_timer_of_to_plat,
+ .plat_auto = sizeof(struct atftmr_timer_plat),
+ .probe = atftmr_timer_probe,
+ .ops = &ag101p_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/altera_timer.c b/roms/u-boot/drivers/timer/altera_timer.c
new file mode 100644
index 000000000..040dc65f4
--- /dev/null
+++ b/roms/u-boot/drivers/timer/altera_timer.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
+ * Scott McNutt <smcnutt@psyent.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+/* control register */
+#define ALTERA_TIMER_CONT BIT(1) /* Continuous mode */
+#define ALTERA_TIMER_START BIT(2) /* Start timer */
+#define ALTERA_TIMER_STOP BIT(3) /* Stop timer */
+
+struct altera_timer_regs {
+ u32 status; /* Timer status reg */
+ u32 control; /* Timer control reg */
+ u32 periodl; /* Timeout period low */
+ u32 periodh; /* Timeout period high */
+ u32 snapl; /* Snapshot low */
+ u32 snaph; /* Snapshot high */
+};
+
+struct altera_timer_plat {
+ struct altera_timer_regs *regs;
+};
+
+static u64 altera_timer_get_count(struct udevice *dev)
+{
+ struct altera_timer_plat *plat = dev_get_plat(dev);
+ struct altera_timer_regs *const regs = plat->regs;
+ u32 val;
+
+ /* Trigger update */
+ writel(0x0, &regs->snapl);
+
+ /* Read timer value */
+ val = readl(&regs->snapl) & 0xffff;
+ val |= (readl(&regs->snaph) & 0xffff) << 16;
+ return timer_conv_64(~val);
+}
+
+static int altera_timer_probe(struct udevice *dev)
+{
+ struct altera_timer_plat *plat = dev_get_plat(dev);
+ struct altera_timer_regs *const regs = plat->regs;
+
+ writel(0, &regs->status);
+ writel(0, &regs->control);
+ writel(ALTERA_TIMER_STOP, &regs->control);
+
+ writel(0xffff, &regs->periodl);
+ writel(0xffff, &regs->periodh);
+ writel(ALTERA_TIMER_CONT | ALTERA_TIMER_START, &regs->control);
+
+ return 0;
+}
+
+static int altera_timer_of_to_plat(struct udevice *dev)
+{
+ struct altera_timer_plat *plat = dev_get_plat(dev);
+
+ plat->regs = map_physmem(dev_read_addr(dev),
+ sizeof(struct altera_timer_regs),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static const struct timer_ops altera_timer_ops = {
+ .get_count = altera_timer_get_count,
+};
+
+static const struct udevice_id altera_timer_ids[] = {
+ { .compatible = "altr,timer-1.0" },
+ {}
+};
+
+U_BOOT_DRIVER(altera_timer) = {
+ .name = "altera_timer",
+ .id = UCLASS_TIMER,
+ .of_match = altera_timer_ids,
+ .of_to_plat = altera_timer_of_to_plat,
+ .plat_auto = sizeof(struct altera_timer_plat),
+ .probe = altera_timer_probe,
+ .ops = &altera_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/andes_plmt_timer.c b/roms/u-boot/drivers/timer/andes_plmt_timer.c
new file mode 100644
index 000000000..a3797b22c
--- /dev/null
+++ b/roms/u-boot/drivers/timer/andes_plmt_timer.c
@@ -0,0 +1,70 @@
+// 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
+ * associated with timer tick.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <linux/err.h>
+
+/* mtime register */
+#define MTIME_REG(base) ((ulong)(base))
+
+static u64 notrace andes_plmt_get_count(struct udevice *dev)
+{
+ return readq((void __iomem *)MTIME_REG(dev_get_priv(dev)));
+}
+
+#if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
+/**
+ * timer_early_get_rate() - Get the timer rate before driver model
+ */
+unsigned long notrace timer_early_get_rate(void)
+{
+ return RISCV_MMODE_TIMER_FREQ;
+}
+
+/**
+ * timer_early_get_count() - Get the timer count before driver model
+ *
+ */
+u64 notrace timer_early_get_count(void)
+{
+ return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE));
+}
+#endif
+
+static const struct timer_ops andes_plmt_ops = {
+ .get_count = andes_plmt_get_count,
+};
+
+static int andes_plmt_probe(struct udevice *dev)
+{
+ dev_set_priv(dev, dev_read_addr_ptr(dev));
+ if (!dev_get_priv(dev))
+ return -EINVAL;
+
+ return timer_timebase_fallback(dev);
+}
+
+static const struct udevice_id andes_plmt_ids[] = {
+ { .compatible = "riscv,plmt0" },
+ { }
+};
+
+U_BOOT_DRIVER(andes_plmt) = {
+ .name = "andes_plmt",
+ .id = UCLASS_TIMER,
+ .of_match = andes_plmt_ids,
+ .ops = &andes_plmt_ops,
+ .probe = andes_plmt_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/timer/arc_timer.c b/roms/u-boot/drivers/timer/arc_timer.c
new file mode 100644
index 000000000..497f8a041
--- /dev/null
+++ b/roms/u-boot/drivers/timer/arc_timer.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Synopsys, Inc. All rights reserved.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/arcregs.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define NH_MODE (1 << 1)
+
+/*
+ * ARC timer control registers are mapped to auxiliary address space.
+ * There are special ARC asm command to access that addresses.
+ * Therefore we use built-in functions to read from and write to timer
+ * control register.
+ */
+
+/* Driver private data. Contains timer id. Could be either 0 or 1. */
+struct arc_timer_priv {
+ uint timer_id;
+};
+
+static u64 arc_timer_get_count(struct udevice *dev)
+{
+ u32 val = 0;
+ struct arc_timer_priv *priv = dev_get_priv(dev);
+
+ switch (priv->timer_id) {
+ case 0:
+ val = read_aux_reg(ARC_AUX_TIMER0_CNT);
+ break;
+ case 1:
+ val = read_aux_reg(ARC_AUX_TIMER1_CNT);
+ break;
+ }
+ return timer_conv_64(val);
+}
+
+static int arc_timer_probe(struct udevice *dev)
+{
+ int id;
+ struct arc_timer_priv *priv = dev_get_priv(dev);
+
+ /* Get registers offset and size */
+ id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
+ if (id < 0)
+ return -EINVAL;
+
+ if (id > 1)
+ return -ENXIO;
+
+ priv->timer_id = (uint)id;
+
+ /*
+ * In ARC core there're special registers (Auxiliary or AUX) in its
+ * separate memory space that are used for accessing some hardware
+ * features of the core. They are not mapped in normal memory space
+ * and also always have the same location regardless core configuration.
+ * Thus to simplify understanding of the programming model we chose to
+ * access AUX regs of Timer0 and Timer1 separately instead of using
+ * offsets from some base address.
+ */
+
+ switch (priv->timer_id) {
+ case 0:
+ /* Disable timer if CPU is halted */
+ write_aux_reg(ARC_AUX_TIMER0_CTRL, NH_MODE);
+ /* Set max value for counter/timer */
+ write_aux_reg(ARC_AUX_TIMER0_LIMIT, 0xffffffff);
+ /* Set initial count value and restart counter/timer */
+ write_aux_reg(ARC_AUX_TIMER0_CNT, 0);
+ break;
+ case 1:
+ /* Disable timer if CPU is halted */
+ write_aux_reg(ARC_AUX_TIMER1_CTRL, NH_MODE);
+ /* Set max value for counter/timer */
+ write_aux_reg(ARC_AUX_TIMER1_LIMIT, 0xffffffff);
+ /* Set initial count value and restart counter/timer */
+ write_aux_reg(ARC_AUX_TIMER1_CNT, 0);
+ break;
+ }
+
+ return 0;
+}
+
+
+static const struct timer_ops arc_timer_ops = {
+ .get_count = arc_timer_get_count,
+};
+
+static const struct udevice_id arc_timer_ids[] = {
+ { .compatible = "snps,arc-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(arc_timer) = {
+ .name = "arc_timer",
+ .id = UCLASS_TIMER,
+ .of_match = arc_timer_ids,
+ .probe = arc_timer_probe,
+ .ops = &arc_timer_ops,
+ .priv_auto = sizeof(struct arc_timer_priv),
+};
diff --git a/roms/u-boot/drivers/timer/ast_timer.c b/roms/u-boot/drivers/timer/ast_timer.c
new file mode 100644
index 000000000..78adc96cc
--- /dev/null
+++ b/roms/u-boot/drivers/timer/ast_timer.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Google Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/arch/timer.h>
+#include <linux/err.h>
+
+#define AST_TICK_TIMER 1
+#define AST_TMC_RELOAD_VAL 0xffffffff
+
+struct ast_timer_priv {
+ struct ast_timer *regs;
+ struct ast_timer_counter *tmc;
+};
+
+static struct ast_timer_counter *ast_get_timer_counter(struct ast_timer *timer,
+ int n)
+{
+ if (n > 3)
+ return &timer->timers2[n - 4];
+ else
+ return &timer->timers1[n - 1];
+}
+
+static int ast_timer_probe(struct udevice *dev)
+{
+ struct ast_timer_priv *priv = dev_get_priv(dev);
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ writel(AST_TMC_RELOAD_VAL, &priv->tmc->reload_val);
+
+ /*
+ * Stop the timer. This will also load reload_val into
+ * the status register.
+ */
+ clrbits_le32(&priv->regs->ctrl1,
+ AST_TMC_EN << AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER));
+ /* Start the timer from the fixed 1MHz clock. */
+ setbits_le32(&priv->regs->ctrl1,
+ (AST_TMC_EN | AST_TMC_1MHZ) <<
+ AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER));
+
+ uc_priv->clock_rate = AST_TMC_RATE;
+
+ return 0;
+}
+
+static u64 ast_timer_get_count(struct udevice *dev)
+{
+ struct ast_timer_priv *priv = dev_get_priv(dev);
+
+ return AST_TMC_RELOAD_VAL - readl(&priv->tmc->status);
+}
+
+static int ast_timer_of_to_plat(struct udevice *dev)
+{
+ struct ast_timer_priv *priv = dev_get_priv(dev);
+
+ priv->regs = dev_read_addr_ptr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ priv->tmc = ast_get_timer_counter(priv->regs, AST_TICK_TIMER);
+
+ return 0;
+}
+
+static const struct timer_ops ast_timer_ops = {
+ .get_count = ast_timer_get_count,
+};
+
+static const struct udevice_id ast_timer_ids[] = {
+ { .compatible = "aspeed,ast2500-timer" },
+ { .compatible = "aspeed,ast2400-timer" },
+ { }
+};
+
+U_BOOT_DRIVER(ast_timer) = {
+ .name = "ast_timer",
+ .id = UCLASS_TIMER,
+ .of_match = ast_timer_ids,
+ .probe = ast_timer_probe,
+ .priv_auto = sizeof(struct ast_timer_priv),
+ .of_to_plat = ast_timer_of_to_plat,
+ .ops = &ast_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/atcpit100_timer.c b/roms/u-boot/drivers/timer/atcpit100_timer.c
new file mode 100644
index 000000000..fbc7fac1b
--- /dev/null
+++ b/roms/u-boot/drivers/timer/atcpit100_timer.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Andestech ATCPIT100 timer driver
+ *
+ * (C) Copyright 2016
+ * Rick Chen, NDS32 Software Engineering, rick@andestech.com
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <linux/io.h>
+
+#define REG32_TMR(x) (*(u32 *) ((plat->regs) + (x>>2)))
+
+/*
+ * Definition of register offsets
+ */
+
+/* ID and Revision Register */
+#define ID_REV 0x0
+
+/* Configuration Register */
+#define CFG 0x10
+
+/* Interrupt Enable Register */
+#define INT_EN 0x14
+#define CH_INT_EN(c , i) ((1<<i)<<(4*c))
+
+/* Interrupt Status Register */
+#define INT_STA 0x18
+#define CH_INT_STA(c , i) ((1<<i)<<(4*c))
+
+/* Channel Enable Register */
+#define CH_EN 0x1C
+#define CH_TMR_EN(c , t) ((1<<t)<<(4*c))
+
+/* Ch n Control REgister */
+#define CH_CTL(n) (0x20+0x10*n)
+/* Channel clock source , bit 3 , 0:External clock , 1:APB clock */
+#define APB_CLK (1<<3)
+/* Channel mode , bit 0~2 */
+#define TMR_32 1
+#define TMR_16 2
+#define TMR_8 3
+#define PWM 4
+
+#define CH_REL(n) (0x24+0x10*n)
+#define CH_CNT(n) (0x28+0x10*n)
+
+struct atctmr_timer_regs {
+ u32 id_rev; /* 0x00 */
+ u32 reservd[3]; /* 0x04 ~ 0x0c */
+ u32 cfg; /* 0x10 */
+ u32 int_en; /* 0x14 */
+ u32 int_st; /* 0x18 */
+ u32 ch_en; /* 0x1c */
+ u32 ch0_ctrl; /* 0x20 */
+ u32 ch0_reload; /* 0x24 */
+ u32 ch0_cntr; /* 0x28 */
+ u32 reservd1; /* 0x2c */
+ u32 ch1_ctrl; /* 0x30 */
+ u32 ch1_reload; /* 0x34 */
+ u32 int_mask; /* 0x38 */
+};
+
+struct atcpit_timer_plat {
+ u32 *regs;
+};
+
+static u64 atcpit_timer_get_count(struct udevice *dev)
+{
+ struct atcpit_timer_plat *plat = dev_get_plat(dev);
+ u32 val;
+ val = ~(REG32_TMR(CH_CNT(1))+0xffffffff);
+ return timer_conv_64(val);
+}
+
+static int atcpit_timer_probe(struct udevice *dev)
+{
+ struct atcpit_timer_plat *plat = dev_get_plat(dev);
+ REG32_TMR(CH_REL(1)) = 0xffffffff;
+ REG32_TMR(CH_CTL(1)) = APB_CLK|TMR_32;
+ REG32_TMR(CH_EN) |= CH_TMR_EN(1 , 0);
+ return 0;
+}
+
+static int atcpit_timer_of_to_plat(struct udevice *dev)
+{
+ struct atcpit_timer_plat *plat = dev_get_plat(dev);
+ plat->regs = map_physmem(dev_read_addr(dev), 0x100 , MAP_NOCACHE);
+ return 0;
+}
+
+static const struct timer_ops atcpit_timer_ops = {
+ .get_count = atcpit_timer_get_count,
+};
+
+static const struct udevice_id atcpit_timer_ids[] = {
+ { .compatible = "andestech,atcpit100" },
+ {}
+};
+
+U_BOOT_DRIVER(atcpit100_timer) = {
+ .name = "atcpit100_timer",
+ .id = UCLASS_TIMER,
+ .of_match = atcpit_timer_ids,
+ .of_to_plat = atcpit_timer_of_to_plat,
+ .plat_auto = sizeof(struct atcpit_timer_plat),
+ .probe = atcpit_timer_probe,
+ .ops = &atcpit_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/atmel_pit_timer.c b/roms/u-boot/drivers/timer/atmel_pit_timer.c
new file mode 100644
index 000000000..3178e5888
--- /dev/null
+++ b/roms/u-boot/drivers/timer/atmel_pit_timer.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Microchip Corporation
+ * Wenyou.Yang <wenyou.yang@microchip.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#define AT91_PIT_VALUE 0xfffff
+#define AT91_PIT_PITEN BIT(24) /* Timer Enabled */
+
+struct atmel_pit_regs {
+ u32 mode;
+ u32 status;
+ u32 value;
+ u32 value_image;
+};
+
+struct atmel_pit_plat {
+ struct atmel_pit_regs *regs;
+};
+
+static u64 atmel_pit_get_count(struct udevice *dev)
+{
+ struct atmel_pit_plat *plat = dev_get_plat(dev);
+ struct atmel_pit_regs *const regs = plat->regs;
+ u32 val = readl(&regs->value_image);
+
+ return timer_conv_64(val);
+}
+
+static int atmel_pit_probe(struct udevice *dev)
+{
+ struct atmel_pit_plat *plat = dev_get_plat(dev);
+ struct atmel_pit_regs *const regs = plat->regs;
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct clk clk;
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return -EINVAL;
+
+ clk_rate = clk_get_rate(&clk);
+ if (!clk_rate)
+ return -EINVAL;
+
+ uc_priv->clock_rate = clk_rate / 16;
+
+ writel(AT91_PIT_VALUE | AT91_PIT_PITEN, &regs->mode);
+
+ return 0;
+}
+
+static int atmel_pit_of_to_plat(struct udevice *dev)
+{
+ struct atmel_pit_plat *plat = dev_get_plat(dev);
+
+ plat->regs = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static const struct timer_ops atmel_pit_ops = {
+ .get_count = atmel_pit_get_count,
+};
+
+static const struct udevice_id atmel_pit_ids[] = {
+ { .compatible = "atmel,at91sam9260-pit" },
+ { }
+};
+
+U_BOOT_DRIVER(atmel_pit) = {
+ .name = "atmel_pit",
+ .id = UCLASS_TIMER,
+ .of_match = atmel_pit_ids,
+ .of_to_plat = atmel_pit_of_to_plat,
+ .plat_auto = sizeof(struct atmel_pit_plat),
+ .probe = atmel_pit_probe,
+ .ops = &atmel_pit_ops,
+};
diff --git a/roms/u-boot/drivers/timer/cadence-ttc.c b/roms/u-boot/drivers/timer/cadence-ttc.c
new file mode 100644
index 000000000..2f95d45ec
--- /dev/null
+++ b/roms/u-boot/drivers/timer/cadence-ttc.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Xilinx, Inc. (Michal Simek)
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <timer.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#define CNT_CNTRL_RESET BIT(4)
+
+struct cadence_ttc_regs {
+ u32 clk_cntrl1; /* 0x0 - Clock Control 1 */
+ u32 clk_cntrl2; /* 0x4 - Clock Control 2 */
+ u32 clk_cntrl3; /* 0x8 - Clock Control 3 */
+ u32 counter_cntrl1; /* 0xC - Counter Control 1 */
+ u32 counter_cntrl2; /* 0x10 - Counter Control 2 */
+ u32 counter_cntrl3; /* 0x14 - Counter Control 3 */
+ u32 counter_val1; /* 0x18 - Counter Control 1 */
+ u32 counter_val2; /* 0x1C - Counter Control 2 */
+ u32 counter_val3; /* 0x20 - Counter Control 3 */
+ u32 reserved[15];
+ u32 interrupt_enable1; /* 0x60 - Interrupt Enable 1 */
+ u32 interrupt_enable2; /* 0x64 - Interrupt Enable 2 */
+ u32 interrupt_enable3; /* 0x68 - Interrupt Enable 3 */
+};
+
+struct cadence_ttc_priv {
+ struct cadence_ttc_regs *regs;
+};
+
+#if CONFIG_IS_ENABLED(BOOTSTAGE)
+ulong timer_get_boot_us(void)
+{
+ u64 ticks = 0;
+ u32 rate = 1;
+ u64 us;
+ int ret;
+
+ ret = dm_timer_init();
+ if (!ret) {
+ /* The timer is available */
+ rate = timer_get_rate(gd->timer);
+ timer_get_count(gd->timer, &ticks);
+ } else {
+ return 0;
+ }
+
+ us = (ticks * 1000) / rate;
+ return us;
+}
+#endif
+
+static u64 cadence_ttc_get_count(struct udevice *dev)
+{
+ struct cadence_ttc_priv *priv = dev_get_priv(dev);
+
+ return readl(&priv->regs->counter_val1);
+}
+
+static int cadence_ttc_probe(struct udevice *dev)
+{
+ struct cadence_ttc_priv *priv = dev_get_priv(dev);
+
+ /* Disable interrupts for sure */
+ writel(0, &priv->regs->interrupt_enable1);
+ writel(0, &priv->regs->interrupt_enable2);
+ writel(0, &priv->regs->interrupt_enable3);
+
+ /* Make sure that clocks are configured properly without prescaller */
+ writel(0, &priv->regs->clk_cntrl1);
+ writel(0, &priv->regs->clk_cntrl2);
+ writel(0, &priv->regs->clk_cntrl3);
+
+ /* Reset and enable this counter */
+ writel(CNT_CNTRL_RESET, &priv->regs->counter_cntrl1);
+
+ return 0;
+}
+
+static int cadence_ttc_of_to_plat(struct udevice *dev)
+{
+ struct cadence_ttc_priv *priv = dev_get_priv(dev);
+
+ priv->regs = map_physmem(dev_read_addr(dev),
+ sizeof(struct cadence_ttc_regs), MAP_NOCACHE);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ return 0;
+}
+
+static const struct timer_ops cadence_ttc_ops = {
+ .get_count = cadence_ttc_get_count,
+};
+
+static const struct udevice_id cadence_ttc_ids[] = {
+ { .compatible = "cdns,ttc" },
+ {}
+};
+
+U_BOOT_DRIVER(cadence_ttc) = {
+ .name = "cadence_ttc",
+ .id = UCLASS_TIMER,
+ .of_match = cadence_ttc_ids,
+ .of_to_plat = cadence_ttc_of_to_plat,
+ .priv_auto = sizeof(struct cadence_ttc_priv),
+ .probe = cadence_ttc_probe,
+ .ops = &cadence_ttc_ops,
+};
diff --git a/roms/u-boot/drivers/timer/dw-apb-timer.c b/roms/u-boot/drivers/timer/dw-apb-timer.c
new file mode 100644
index 000000000..9aed5dd21
--- /dev/null
+++ b/roms/u-boot/drivers/timer/dw-apb-timer.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Designware APB Timer driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marex@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <malloc.h>
+#include <reset.h>
+#include <timer.h>
+#include <dm/device_compat.h>
+
+#include <asm/io.h>
+#include <asm/arch/timer.h>
+
+#define DW_APB_LOAD_VAL 0x0
+#define DW_APB_CURR_VAL 0x4
+#define DW_APB_CTRL 0x8
+
+struct dw_apb_timer_priv {
+ fdt_addr_t regs;
+ struct reset_ctl_bulk resets;
+};
+
+static u64 dw_apb_timer_get_count(struct udevice *dev)
+{
+ struct dw_apb_timer_priv *priv = dev_get_priv(dev);
+
+ /*
+ * The DW APB counter counts down, but this function
+ * requires the count to be incrementing. Invert the
+ * result.
+ */
+ return timer_conv_64(~readl(priv->regs + DW_APB_CURR_VAL));
+}
+
+static int dw_apb_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct dw_apb_timer_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ int ret;
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret)
+ dev_warn(dev, "Can't get reset: %d\n", ret);
+ else
+ reset_deassert_bulk(&priv->resets);
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ uc_priv->clock_rate = clk_get_rate(&clk);
+
+ clk_free(&clk);
+
+ /* init timer */
+ writel(0xffffffff, priv->regs + DW_APB_LOAD_VAL);
+ writel(0xffffffff, priv->regs + DW_APB_CURR_VAL);
+ setbits_le32(priv->regs + DW_APB_CTRL, 0x3);
+
+ return 0;
+}
+
+static int dw_apb_timer_of_to_plat(struct udevice *dev)
+{
+ struct dw_apb_timer_priv *priv = dev_get_priv(dev);
+
+ priv->regs = dev_read_addr(dev);
+
+ return 0;
+}
+
+static int dw_apb_timer_remove(struct udevice *dev)
+{
+ struct dw_apb_timer_priv *priv = dev_get_priv(dev);
+
+ return reset_release_bulk(&priv->resets);
+}
+
+static const struct timer_ops dw_apb_timer_ops = {
+ .get_count = dw_apb_timer_get_count,
+};
+
+static const struct udevice_id dw_apb_timer_ids[] = {
+ { .compatible = "snps,dw-apb-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(dw_apb_timer) = {
+ .name = "dw_apb_timer",
+ .id = UCLASS_TIMER,
+ .ops = &dw_apb_timer_ops,
+ .probe = dw_apb_timer_probe,
+ .of_match = dw_apb_timer_ids,
+ .of_to_plat = dw_apb_timer_of_to_plat,
+ .remove = dw_apb_timer_remove,
+ .priv_auto = sizeof(struct dw_apb_timer_priv),
+};
diff --git a/roms/u-boot/drivers/timer/imx-gpt-timer.c b/roms/u-boot/drivers/timer/imx-gpt-timer.c
new file mode 100644
index 000000000..72be29775
--- /dev/null
+++ b/roms/u-boot/drivers/timer/imx-gpt-timer.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021
+ * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <timer.h>
+#include <dm/device_compat.h>
+
+#include <asm/io.h>
+
+#define GPT_CR_EN BIT(0)
+#define GPT_CR_FRR BIT(9)
+#define GPT_CR_EN_24M BIT(10)
+#define GPT_CR_SWR BIT(15)
+
+#define GPT_PR_PRESCALER24M_MASK 0x0000F000
+#define GPT_PR_PRESCALER24M_SHIFT 12
+#define GPT_PR_PRESCALER24M_MAX (GPT_PR_PRESCALER24M_MASK >> GPT_PR_PRESCALER24M_SHIFT)
+#define GPT_PR_PRESCALER_MASK 0x00000FFF
+#define GPT_PR_PRESCALER_SHIFT 0
+#define GPT_PR_PRESCALER_MAX (GPT_PR_PRESCALER_MASK >> GPT_PR_PRESCALER_SHIFT)
+
+#define GPT_CLKSRC_IPG_CLK (1 << 6)
+#define GPT_CLKSRC_IPG_CLK_24M (5 << 6)
+
+/* If CONFIG_SYS_HZ_CLOCK not specified et's default to 3Mhz */
+#ifndef CONFIG_SYS_HZ_CLOCK
+#define CONFIG_SYS_HZ_CLOCK 3000000
+#endif
+
+struct imx_gpt_timer_regs {
+ u32 cr;
+ u32 pr;
+ u32 sr;
+ u32 ir;
+ u32 ocr1;
+ u32 ocr2;
+ u32 ocr3;
+ u32 icr1;
+ u32 icr2;
+ u32 cnt;
+};
+
+struct imx_gpt_timer_priv {
+ struct imx_gpt_timer_regs *base;
+};
+
+static u64 imx_gpt_timer_get_count(struct udevice *dev)
+{
+ struct imx_gpt_timer_priv *priv = dev_get_priv(dev);
+ struct imx_gpt_timer_regs *regs = priv->base;
+
+ return timer_conv_64(readl(&regs->cnt));
+}
+
+static int imx_gpt_setup(struct imx_gpt_timer_regs *regs, u32 rate)
+{
+ u32 prescaler = (rate / CONFIG_SYS_HZ_CLOCK) - 1;
+
+ /* Reset the timer */
+ setbits_le32(&regs->cr, GPT_CR_SWR);
+
+ /* Wait for timer to finish reset */
+ while (readl(&regs->cr) & GPT_CR_SWR)
+ ;
+
+ if (rate == 24000000UL) {
+ /* Set timer frequency if using 24M clock source */
+ if (prescaler > GPT_PR_PRESCALER24M_MAX)
+ return -EINVAL;
+
+ /* Set 24M prescaler */
+ writel((prescaler << GPT_PR_PRESCALER24M_SHIFT), &regs->pr);
+ /* Set Oscillator as clock source, enable 24M input and set gpt
+ * in free-running mode
+ */
+ writel(GPT_CLKSRC_IPG_CLK_24M | GPT_CR_EN_24M | GPT_CR_FRR, &regs->cr);
+ } else {
+ if (prescaler > GPT_PR_PRESCALER_MAX)
+ return -EINVAL;
+
+ /* Set prescaler */
+ writel((prescaler << GPT_PR_PRESCALER_SHIFT), &regs->pr);
+ /* Set Peripheral as clock source and set gpt in free-running
+ * mode
+ */
+ writel(GPT_CLKSRC_IPG_CLK | GPT_CR_FRR, &regs->cr);
+ }
+
+ /* Start timer */
+ setbits_le32(&regs->cr, GPT_CR_EN);
+
+ return 0;
+}
+
+static int imx_gpt_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct imx_gpt_timer_priv *priv = dev_get_priv(dev);
+ struct imx_gpt_timer_regs *regs;
+ struct clk clk;
+ fdt_addr_t addr;
+ u32 clk_rate;
+ int ret;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = (struct imx_gpt_timer_regs *)addr;
+ regs = priv->base;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ /* Get timer clock rate */
+ clk_rate = clk_get_rate(&clk);
+ if (clk_rate <= 0) {
+ dev_err(dev, "Could not get clock rate...\n");
+ return -EINVAL;
+ }
+
+ ret = imx_gpt_setup(regs, clk_rate);
+ if (ret) {
+ dev_err(dev, "Could not setup timer\n");
+ return ret;
+ }
+
+ uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+
+ return 0;
+}
+
+static const struct timer_ops imx_gpt_timer_ops = {
+ .get_count = imx_gpt_timer_get_count,
+};
+
+static const struct udevice_id imx_gpt_timer_ids[] = {
+ { .compatible = "fsl,imxrt-gpt" },
+ {}
+};
+
+U_BOOT_DRIVER(imx_gpt_timer) = {
+ .name = "imx_gpt_timer",
+ .id = UCLASS_TIMER,
+ .of_match = imx_gpt_timer_ids,
+ .priv_auto = sizeof(struct imx_gpt_timer_priv),
+ .probe = imx_gpt_timer_probe,
+ .ops = &imx_gpt_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/mchp-pit64b-timer.c b/roms/u-boot/drivers/timer/mchp-pit64b-timer.c
new file mode 100644
index 000000000..c9806d7ee
--- /dev/null
+++ b/roms/u-boot/drivers/timer/mchp-pit64b-timer.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * 64-bit Periodic Interval Timer driver
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+
+#define MCHP_PIT64B_CR 0x00 /* Control Register */
+#define MCHP_PIT64B_CR_START BIT(0)
+#define MCHP_PIT64B_CR_SWRST BIT(8)
+#define MCHP_PIT64B_MR 0x04 /* Mode Register */
+#define MCHP_PIT64B_MR_CONT BIT(0)
+#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
+#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
+#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
+#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
+
+struct mchp_pit64b_priv {
+ void __iomem *base;
+};
+
+static u64 mchp_pit64b_get_count(struct udevice *dev)
+{
+ struct mchp_pit64b_priv *priv = dev_get_priv(dev);
+
+ u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR);
+ u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR);
+
+ return ((u64)msb << 32) | lsb;
+}
+
+static int mchp_pit64b_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mchp_pit64b_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ ulong rate;
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate) {
+ clk_disable(&clk);
+ return -ENOTSUPP;
+ }
+
+ /* Reset the timer in case it was used by previous bootloaders. */
+ writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR);
+
+ /*
+ * Use highest prescaller (for a peripheral clock running at 200MHz
+ * this will lead to the timer running at 12.5MHz) and continuous mode.
+ */
+ writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR);
+ uc_priv->clock_rate = rate / 16;
+
+ /*
+ * Simulate free running counter by setting max values to period
+ * registers.
+ */
+ writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR);
+ writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR);
+
+ /* Start the timer. */
+ writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR);
+
+ return 0;
+}
+
+static const struct timer_ops mchp_pit64b_ops = {
+ .get_count = mchp_pit64b_get_count,
+};
+
+static const struct udevice_id mchp_pit64b_ids[] = {
+ { .compatible = "microchip,sam9x60-pit64b", },
+ { .compatible = "microchip,sama7g5-pit64b", },
+ { }
+};
+
+U_BOOT_DRIVER(mchp_pit64b) = {
+ .name = "mchp-pit64b",
+ .id = UCLASS_TIMER,
+ .of_match = mchp_pit64b_ids,
+ .priv_auto = sizeof(struct mchp_pit64b_priv),
+ .probe = mchp_pit64b_probe,
+ .ops = &mchp_pit64b_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/timer/mpc83xx_timer.c b/roms/u-boot/drivers/timer/mpc83xx_timer.c
new file mode 100644
index 000000000..952293195
--- /dev/null
+++ b/roms/u-boot/drivers/timer/mpc83xx_timer.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <irq_func.h>
+#include <log.h>
+#include <status_led.h>
+#include <sysinfo.h>
+#include <time.h>
+#include <timer.h>
+#include <watchdog.h>
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <linux/bitops.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_WATCHDOG_FREQ
+#define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2)
+#endif
+
+/**
+ * struct mpc83xx_timer_priv - Private data structure for MPC83xx timer driver
+ * @decrementer_count: Value to which the decrementer register should be re-set
+ * to when a timer interrupt occurs, thus determines the
+ * interrupt frequency (value for 1e6/HZ microseconds)
+ * @timestamp: Counter for the number of timer interrupts that have
+ * occurred (i.e. can be used to trigger events
+ * periodically in the timer interrupt)
+ */
+struct mpc83xx_timer_priv {
+ uint decrementer_count;
+ ulong timestamp;
+};
+
+/*
+ * Bitmask for enabling the time base in the SPCR (System Priority
+ * Configuration Register)
+ */
+static const u32 SPCR_TBEN_MASK = BIT(31 - 9);
+
+/**
+ * get_dec() - Get the value of the decrementer register
+ *
+ * Return: The value of the decrementer register
+ */
+static inline unsigned long get_dec(void)
+{
+ unsigned long val;
+
+ asm volatile ("mfdec %0" : "=r" (val) : );
+
+ return val;
+}
+
+/**
+ * set_dec() - Set the value of the decrementer register
+ * @val: The value of the decrementer register to be set
+ */
+static inline void set_dec(unsigned long val)
+{
+ if (val)
+ asm volatile ("mtdec %0"::"r" (val));
+}
+
+/**
+ * mftbu() - Get value of TBU (upper time base) register
+ *
+ * Return: Value of the TBU register
+ */
+static inline u32 mftbu(void)
+{
+ u32 rval;
+
+ asm volatile("mftbu %0" : "=r" (rval));
+ return rval;
+}
+
+/**
+ * mftb() - Get value of TBL (lower time base) register
+ *
+ * Return: Value of the TBL register
+ */
+static inline u32 mftb(void)
+{
+ u32 rval;
+
+ asm volatile("mftb %0" : "=r" (rval));
+ return rval;
+}
+
+/*
+ * TODO(mario.six@gdsys.cc): This should really be done by timer_init, and the
+ * interrupt init should go into a interrupt driver.
+ */
+int interrupt_init(void)
+{
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ struct udevice *csb;
+ struct udevice *sysinfo;
+ struct udevice *timer;
+ struct mpc83xx_timer_priv *timer_priv;
+ struct clk clock;
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_TIMER, &timer);
+ if (ret) {
+ debug("%s: Could not find timer device (error: %d)",
+ __func__, ret);
+ return ret;
+ }
+
+ timer_priv = dev_get_priv(timer);
+
+ if (sysinfo_get(&sysinfo)) {
+ debug("%s: sysinfo device could not be fetched.\n", __func__);
+ return -ENOENT;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_SIMPLE_BUS, sysinfo,
+ "csb", &csb);
+ if (ret) {
+ debug("%s: Could not retrieve CSB device (error: %d)",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = clk_get_by_index(csb, 0, &clock);
+ if (ret) {
+ debug("%s: Could not retrieve clock (error: %d)",
+ __func__, ret);
+ return ret;
+ }
+
+ timer_priv->decrementer_count = (clk_get_rate(&clock) / 4)
+ / CONFIG_SYS_HZ;
+ /* Enable e300 time base */
+ setbits_be32(&immr->sysconf.spcr, SPCR_TBEN_MASK);
+
+ set_dec(timer_priv->decrementer_count);
+
+ /* Switch on interrupts */
+ set_msr(get_msr() | MSR_EE);
+
+ return 0;
+}
+
+/**
+ * timer_interrupt() - Handler for the timer interrupt
+ * @regs: Array of register values
+ */
+void timer_interrupt(struct pt_regs *regs)
+{
+ struct udevice *timer = gd->timer;
+ struct mpc83xx_timer_priv *priv;
+
+ /*
+ * During initialization, gd->timer might not be set yet, but the timer
+ * interrupt may already be enabled. In this case, wait for the
+ * initialization to complete
+ */
+ if (!timer)
+ return;
+
+ priv = dev_get_priv(timer);
+
+ /* Restore Decrementer Count */
+ set_dec(priv->decrementer_count);
+
+ priv->timestamp++;
+
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
+ if (CONFIG_SYS_WATCHDOG_FREQ && (priv->timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0)
+ WATCHDOG_RESET();
+#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
+
+#ifdef CONFIG_LED_STATUS
+ status_led_tick(priv->timestamp);
+#endif /* CONFIG_LED_STATUS */
+}
+
+void wait_ticks(ulong ticks)
+{
+ ulong end = get_ticks() + ticks;
+
+ while (end > get_ticks())
+ WATCHDOG_RESET();
+}
+
+static u64 mpc83xx_timer_get_count(struct udevice *dev)
+{
+ u32 tbu, tbl;
+
+ /*
+ * To make sure that no tbl overflow occurred between reading tbl and
+ * tbu, read tbu again, and compare it with the previously read tbu
+ * value: If they're different, a tbl overflow has occurred.
+ */
+ do {
+ tbu = mftbu();
+ tbl = mftb();
+ } while (tbu != mftbu());
+
+ return (tbu * 0x10000ULL) + tbl;
+}
+
+static int mpc83xx_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct clk clock;
+ int ret;
+
+ ret = interrupt_init();
+ if (ret) {
+ debug("%s: interrupt_init failed (err = %d)\n",
+ dev->name, ret);
+ return ret;
+ }
+
+ ret = clk_get_by_index(dev, 0, &clock);
+ if (ret) {
+ debug("%s: Could not retrieve clock (err = %d)\n",
+ dev->name, ret);
+ return ret;
+ }
+
+ uc_priv->clock_rate = (clk_get_rate(&clock) + 3L) / 4L;
+
+ return 0;
+}
+
+static const struct timer_ops mpc83xx_timer_ops = {
+ .get_count = mpc83xx_timer_get_count,
+};
+
+static const struct udevice_id mpc83xx_timer_ids[] = {
+ { .compatible = "fsl,mpc83xx-timer" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mpc83xx_timer) = {
+ .name = "mpc83xx_timer",
+ .id = UCLASS_TIMER,
+ .of_match = mpc83xx_timer_ids,
+ .probe = mpc83xx_timer_probe,
+ .ops = &mpc83xx_timer_ops,
+ .priv_auto = sizeof(struct mpc83xx_timer_priv),
+};
diff --git a/roms/u-boot/drivers/timer/mtk_timer.c b/roms/u-boot/drivers/timer/mtk_timer.c
new file mode 100644
index 000000000..f6b97f868
--- /dev/null
+++ b/roms/u-boot/drivers/timer/mtk_timer.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek timer driver
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#define MTK_GPT4_CTRL 0x40
+#define MTK_GPT4_CLK 0x44
+#define MTK_GPT4_CNT 0x48
+
+#define GPT4_ENABLE BIT(0)
+#define GPT4_CLEAR BIT(1)
+#define GPT4_FREERUN GENMASK(5, 4)
+#define GPT4_CLK_SYS 0x0
+#define GPT4_CLK_DIV1 0x0
+
+struct mtk_timer_priv {
+ void __iomem *base;
+};
+
+static u64 mtk_timer_get_count(struct udevice *dev)
+{
+ struct mtk_timer_priv *priv = dev_get_priv(dev);
+ u32 val = readl(priv->base + MTK_GPT4_CNT);
+
+ return timer_conv_64(val);
+}
+
+static int mtk_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mtk_timer_priv *priv = dev_get_priv(dev);
+ struct clk clk, parent;
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base)
+ return -ENOENT;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_index(dev, 1, &parent);
+ if (!ret) {
+ ret = clk_set_parent(&clk, &parent);
+ if (ret)
+ return ret;
+ }
+
+ uc_priv->clock_rate = clk_get_rate(&clk);
+ if (!uc_priv->clock_rate)
+ return -EINVAL;
+
+ /*
+ * Initialize the timer:
+ * 1. set clock source to system clock with clock divider setting to 1
+ * 2. set timer mode to free running
+ * 3. reset timer counter to 0 then enable the timer
+ */
+ writel(GPT4_CLK_SYS | GPT4_CLK_DIV1, priv->base + MTK_GPT4_CLK);
+ writel(GPT4_FREERUN | GPT4_CLEAR | GPT4_ENABLE,
+ priv->base + MTK_GPT4_CTRL);
+
+ return 0;
+}
+
+static const struct timer_ops mtk_timer_ops = {
+ .get_count = mtk_timer_get_count,
+};
+
+static const struct udevice_id mtk_timer_ids[] = {
+ { .compatible = "mediatek,timer" },
+ { .compatible = "mediatek,mt6577-timer" },
+ { }
+};
+
+U_BOOT_DRIVER(mtk_timer) = {
+ .name = "mtk_timer",
+ .id = UCLASS_TIMER,
+ .of_match = mtk_timer_ids,
+ .priv_auto = sizeof(struct mtk_timer_priv),
+ .probe = mtk_timer_probe,
+ .ops = &mtk_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/timer/nomadik-mtu-timer.c b/roms/u-boot/drivers/timer/nomadik-mtu-timer.c
new file mode 100644
index 000000000..417b419d4
--- /dev/null
+++ b/roms/u-boot/drivers/timer/nomadik-mtu-timer.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Stephan Gerhold <stephan@gerhold.net>
+ *
+ * Based on arch/arm/cpu/armv7/u8500/timer.c:
+ * Copyright (C) 2010 Linaro Limited
+ * John Rigby <john.rigby@linaro.org>
+ *
+ * Based on Linux kernel source and internal ST-Ericsson U-Boot source:
+ * Copyright (C) 2009 Alessandro Rubini
+ * Copyright (C) 2010 ST-Ericsson
+ * Copyright (C) 2010 Linus Walleij for ST-Ericsson
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#define MTU_NUM_TIMERS 4
+
+/* The timers */
+struct nomadik_mtu_timer_regs {
+ u32 lr; /* Load register */
+ u32 cv; /* Current value */
+ u32 cr; /* Control register */
+ u32 bglr; /* Background load register */
+};
+
+/* The MTU that contains the timers */
+struct nomadik_mtu_regs {
+ u32 imsc; /* Interrupt mask set/clear */
+ u32 ris; /* Raw interrupt status */
+ u32 mis; /* Masked interrupt status */
+ u32 icr; /* Interrupt clear register */
+
+ struct nomadik_mtu_timer_regs timers[MTU_NUM_TIMERS];
+};
+
+/* Bits for the control register */
+#define MTU_CR_ONESHOT BIT(0) /* if 0 = wraps reloading from BGLR */
+#define MTU_CR_32BITS BIT(1) /* if 0 = 16-bit counter */
+
+#define MTU_CR_PRESCALE_SHIFT 2
+#define MTU_CR_PRESCALE_1 (0 << MTU_CR_PRESCALE_SHIFT)
+#define MTU_CR_PRESCALE_16 (1 << MTU_CR_PRESCALE_SHIFT)
+#define MTU_CR_PRESCALE_256 (2 << MTU_CR_PRESCALE_SHIFT)
+
+#define MTU_CR_PERIODIC BIT(6) /* if 0 = free-running */
+#define MTU_CR_ENABLE BIT(7)
+
+struct nomadik_mtu_priv {
+ struct nomadik_mtu_timer_regs *timer;
+};
+
+static u64 nomadik_mtu_get_count(struct udevice *dev)
+{
+ struct nomadik_mtu_priv *priv = dev_get_priv(dev);
+
+ /* Decrementing counter: invert the value */
+ return timer_conv_64(~readl(&priv->timer->cv));
+}
+
+static int nomadik_mtu_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct nomadik_mtu_priv *priv = dev_get_priv(dev);
+ struct nomadik_mtu_regs *mtu;
+ fdt_addr_t addr;
+ u32 prescale;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ mtu = (struct nomadik_mtu_regs *)addr;
+ priv->timer = mtu->timers; /* Use first timer */
+
+ if (!uc_priv->clock_rate)
+ return -EINVAL;
+
+ /* Use divide-by-16 counter if tick rate is more than 32 MHz */
+ if (uc_priv->clock_rate > 32000000) {
+ uc_priv->clock_rate /= 16;
+ prescale = MTU_CR_PRESCALE_16;
+ } else {
+ prescale = MTU_CR_PRESCALE_1;
+ }
+
+ /* Configure a free-running, auto-wrap counter with selected prescale */
+ writel(MTU_CR_ENABLE | prescale | MTU_CR_32BITS, &priv->timer->cr);
+
+ return 0;
+}
+
+static const struct timer_ops nomadik_mtu_ops = {
+ .get_count = nomadik_mtu_get_count,
+};
+
+static const struct udevice_id nomadik_mtu_ids[] = {
+ { .compatible = "st,nomadik-mtu" },
+ {}
+};
+
+U_BOOT_DRIVER(nomadik_mtu) = {
+ .name = "nomadik_mtu",
+ .id = UCLASS_TIMER,
+ .of_match = nomadik_mtu_ids,
+ .priv_auto = sizeof(struct nomadik_mtu_priv),
+ .probe = nomadik_mtu_probe,
+ .ops = &nomadik_mtu_ops,
+};
diff --git a/roms/u-boot/drivers/timer/omap-timer.c b/roms/u-boot/drivers/timer/omap-timer.c
new file mode 100644
index 000000000..721e385fd
--- /dev/null
+++ b/roms/u-boot/drivers/timer/omap-timer.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI OMAP timer driver
+ *
+ * Copyright (C) 2015, Texas Instruments, Incorporated
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <linux/bitops.h>
+
+/* Timer register bits */
+#define TCLR_START BIT(0) /* Start=1 */
+#define TCLR_AUTO_RELOAD BIT(1) /* Auto reload */
+#define TCLR_PRE_EN BIT(5) /* Pre-scaler enable */
+#define TCLR_PTV_SHIFT (2) /* Pre-scaler shift value */
+
+struct omap_gptimer_regs {
+ unsigned int tidr; /* offset 0x00 */
+ unsigned char res1[12];
+ unsigned int tiocp_cfg; /* offset 0x10 */
+ unsigned char res2[12];
+ unsigned int tier; /* offset 0x20 */
+ unsigned int tistatr; /* offset 0x24 */
+ unsigned int tistat; /* offset 0x28 */
+ unsigned int tisr; /* offset 0x2c */
+ unsigned int tcicr; /* offset 0x30 */
+ unsigned int twer; /* offset 0x34 */
+ unsigned int tclr; /* offset 0x38 */
+ unsigned int tcrr; /* offset 0x3c */
+ unsigned int tldr; /* offset 0x40 */
+ unsigned int ttgr; /* offset 0x44 */
+ unsigned int twpc; /* offset 0x48 */
+ unsigned int tmar; /* offset 0x4c */
+ unsigned int tcar1; /* offset 0x50 */
+ unsigned int tscir; /* offset 0x54 */
+ unsigned int tcar2; /* offset 0x58 */
+};
+
+/* Omap Timer Priv */
+struct omap_timer_priv {
+ struct omap_gptimer_regs *regs;
+};
+
+static u64 omap_timer_get_count(struct udevice *dev)
+{
+ struct omap_timer_priv *priv = dev_get_priv(dev);
+
+ return timer_conv_64(readl(&priv->regs->tcrr));
+}
+
+static int omap_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct omap_timer_priv *priv = dev_get_priv(dev);
+
+ if (!uc_priv->clock_rate)
+ uc_priv->clock_rate = V_SCLK;
+
+ uc_priv->clock_rate /= (2 << CONFIG_SYS_PTV);
+
+ /* start the counter ticking up, reload value on overflow */
+ writel(0, &priv->regs->tldr);
+ writel(0, &priv->regs->tcrr);
+ /* enable timer */
+ writel((CONFIG_SYS_PTV << 2) | TCLR_PRE_EN | TCLR_AUTO_RELOAD |
+ TCLR_START, &priv->regs->tclr);
+
+ return 0;
+}
+
+static int omap_timer_of_to_plat(struct udevice *dev)
+{
+ struct omap_timer_priv *priv = dev_get_priv(dev);
+
+ priv->regs = map_physmem(dev_read_addr(dev),
+ sizeof(struct omap_gptimer_regs), MAP_NOCACHE);
+
+ return 0;
+}
+
+
+static const struct timer_ops omap_timer_ops = {
+ .get_count = omap_timer_get_count,
+};
+
+static const struct udevice_id omap_timer_ids[] = {
+ { .compatible = "ti,am335x-timer" },
+ { .compatible = "ti,am4372-timer" },
+ { .compatible = "ti,omap5430-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(omap_timer) = {
+ .name = "omap_timer",
+ .id = UCLASS_TIMER,
+ .of_match = omap_timer_ids,
+ .of_to_plat = omap_timer_of_to_plat,
+ .priv_auto = sizeof(struct omap_timer_priv),
+ .probe = omap_timer_probe,
+ .ops = &omap_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/ostm_timer.c b/roms/u-boot/drivers/timer/ostm_timer.c
new file mode 100644
index 000000000..24813de26
--- /dev/null
+++ b/roms/u-boot/drivers/timer/ostm_timer.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas RZ/A1 R7S72100 OSTM Timer driver
+ *
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <clk.h>
+#include <timer.h>
+#include <linux/bitops.h>
+
+#define OSTM_CMP 0x00
+#define OSTM_CNT 0x04
+#define OSTM_TE 0x10
+#define OSTM_TS 0x14
+#define OSTM_TT 0x18
+#define OSTM_CTL 0x20
+#define OSTM_CTL_D BIT(1)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct ostm_priv {
+ fdt_addr_t regs;
+};
+
+static u64 ostm_get_count(struct udevice *dev)
+{
+ struct ostm_priv *priv = dev_get_priv(dev);
+
+ return timer_conv_64(readl(priv->regs + OSTM_CNT));
+}
+
+static int ostm_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ostm_priv *priv = dev_get_priv(dev);
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ uc_priv->clock_rate = clk_get_rate(&clk);
+
+ clk_free(&clk);
+#else
+ uc_priv->clock_rate = CONFIG_SYS_CLK_FREQ / 2;
+#endif
+
+ readb(priv->regs + OSTM_CTL);
+ writeb(OSTM_CTL_D, priv->regs + OSTM_CTL);
+
+ setbits_8(priv->regs + OSTM_TT, BIT(0));
+ writel(0xffffffff, priv->regs + OSTM_CMP);
+ setbits_8(priv->regs + OSTM_TS, BIT(0));
+
+ return 0;
+}
+
+static int ostm_of_to_plat(struct udevice *dev)
+{
+ struct ostm_priv *priv = dev_get_priv(dev);
+
+ priv->regs = dev_read_addr(dev);
+
+ return 0;
+}
+
+static const struct timer_ops ostm_ops = {
+ .get_count = ostm_get_count,
+};
+
+static const struct udevice_id ostm_ids[] = {
+ { .compatible = "renesas,ostm" },
+ {}
+};
+
+U_BOOT_DRIVER(ostm_timer) = {
+ .name = "ostm-timer",
+ .id = UCLASS_TIMER,
+ .ops = &ostm_ops,
+ .probe = ostm_probe,
+ .of_match = ostm_ids,
+ .of_to_plat = ostm_of_to_plat,
+ .priv_auto = sizeof(struct ostm_priv),
+};
diff --git a/roms/u-boot/drivers/timer/riscv_timer.c b/roms/u-boot/drivers/timer/riscv_timer.c
new file mode 100644
index 000000000..3627ed79b
--- /dev/null
+++ b/roms/u-boot/drivers/timer/riscv_timer.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
+ * Copyright (C) 2012 Regents of the University of California
+ *
+ * RISC-V architecturally-defined generic timer driver
+ *
+ * This driver provides generic timer support for S-mode U-Boot.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/csr.h>
+
+static u64 notrace riscv_timer_get_count(struct udevice *dev)
+{
+ __maybe_unused u32 hi, lo;
+
+ if (IS_ENABLED(CONFIG_64BIT))
+ return csr_read(CSR_TIME);
+
+ do {
+ hi = csr_read(CSR_TIMEH);
+ lo = csr_read(CSR_TIME);
+ } while (hi != csr_read(CSR_TIMEH));
+
+ return ((u64)hi << 32) | lo;
+}
+
+#if CONFIG_IS_ENABLED(RISCV_SMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
+/**
+ * timer_early_get_rate() - Get the timer rate before driver model
+ */
+unsigned long notrace timer_early_get_rate(void)
+{
+ return RISCV_SMODE_TIMER_FREQ;
+}
+
+/**
+ * timer_early_get_count() - Get the timer count before driver model
+ *
+ */
+u64 notrace timer_early_get_count(void)
+{
+ return riscv_timer_get_count(NULL);
+}
+#endif
+
+static int riscv_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* clock frequency was passed from the cpu driver as driver data */
+ uc_priv->clock_rate = dev->driver_data;
+
+ return 0;
+}
+
+static const struct timer_ops riscv_timer_ops = {
+ .get_count = riscv_timer_get_count,
+};
+
+U_BOOT_DRIVER(riscv_timer) = {
+ .name = "riscv_timer",
+ .id = UCLASS_TIMER,
+ .probe = riscv_timer_probe,
+ .ops = &riscv_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/timer/rockchip_timer.c b/roms/u-boot/drivers/timer/rockchip_timer.c
new file mode 100644
index 000000000..18c61450a
--- /dev/null
+++ b/roms/u-boot/drivers/timer/rockchip_timer.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <dm/ofnode.h>
+#include <mapmem.h>
+#include <asm/arch-rockchip/timer.h>
+#include <dt-structs.h>
+#include <timer.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+struct rockchip_timer_plat {
+ struct dtd_rockchip_rk3368_timer dtd;
+};
+#endif
+
+/* Driver private data. Contains timer id. Could be either 0 or 1. */
+struct rockchip_timer_priv {
+ struct rk_timer *timer;
+};
+
+static inline int64_t rockchip_timer_get_curr_value(struct rk_timer *timer)
+{
+ uint64_t timebase_h, timebase_l;
+ uint64_t cntr;
+
+ timebase_l = readl(&timer->timer_curr_value0);
+ timebase_h = readl(&timer->timer_curr_value1);
+
+ cntr = timebase_h << 32 | timebase_l;
+ return cntr;
+}
+
+#if CONFIG_IS_ENABLED(BOOTSTAGE)
+ulong timer_get_boot_us(void)
+{
+ uint64_t ticks = 0;
+ uint32_t rate;
+ uint64_t us;
+ int ret;
+
+ ret = dm_timer_init();
+
+ if (!ret) {
+ /* The timer is available */
+ rate = timer_get_rate(gd->timer);
+ timer_get_count(gd->timer, &ticks);
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ } else if (ret == -EAGAIN) {
+ /* We have been called so early that the DM is not ready,... */
+ ofnode node = offset_to_ofnode(-1);
+ struct rk_timer *timer = NULL;
+
+ /*
+ * ... so we try to access the raw timer, if it is specified
+ * via the tick-timer property in /chosen.
+ */
+ node = ofnode_get_chosen_node("tick-timer");
+ if (!ofnode_valid(node)) {
+ debug("%s: no /chosen/tick-timer\n", __func__);
+ return 0;
+ }
+
+ timer = (struct rk_timer *)ofnode_get_addr(node);
+
+ /* This timer is down-counting */
+ ticks = ~0uLL - rockchip_timer_get_curr_value(timer);
+ if (ofnode_read_u32(node, "clock-frequency", &rate)) {
+ debug("%s: could not read clock-frequency\n", __func__);
+ return 0;
+ }
+#endif
+ } else {
+ return 0;
+ }
+
+ us = (ticks * 1000) / rate;
+ return us;
+}
+#endif
+
+static u64 rockchip_timer_get_count(struct udevice *dev)
+{
+ struct rockchip_timer_priv *priv = dev_get_priv(dev);
+ uint64_t cntr = rockchip_timer_get_curr_value(priv->timer);
+
+ /* timers are down-counting */
+ return ~0ull - cntr;
+}
+
+static int rockchip_clk_of_to_plat(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct rockchip_timer_priv *priv = dev_get_priv(dev);
+
+ priv->timer = dev_read_addr_ptr(dev);
+ if (!priv->timer)
+ return -ENOENT;
+#endif
+
+ return 0;
+}
+
+static int rockchip_timer_start(struct udevice *dev)
+{
+ struct rockchip_timer_priv *priv = dev_get_priv(dev);
+ const uint64_t reload_val = ~0uLL;
+ const uint32_t reload_val_l = reload_val & 0xffffffff;
+ const uint32_t reload_val_h = reload_val >> 32;
+
+ /* don't reinit, if the timer is already running and set up */
+ if ((readl(&priv->timer->timer_ctrl_reg) & 1) == 1 &&
+ (readl(&priv->timer->timer_load_count0) == reload_val_l) &&
+ (readl(&priv->timer->timer_load_count1) == reload_val_h))
+ return 0;
+
+ /* disable timer and reset all control */
+ writel(0, &priv->timer->timer_ctrl_reg);
+ /* write reload value */
+ writel(reload_val_l, &priv->timer->timer_load_count0);
+ writel(reload_val_h, &priv->timer->timer_load_count1);
+ /* enable timer */
+ writel(1, &priv->timer->timer_ctrl_reg);
+
+ return 0;
+}
+
+static int rockchip_timer_probe(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct rockchip_timer_priv *priv = dev_get_priv(dev);
+ struct rockchip_timer_plat *plat = dev_get_plat(dev);
+
+ priv->timer = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
+ uc_priv->clock_rate = plat->dtd.clock_frequency;
+#endif
+
+ return rockchip_timer_start(dev);
+}
+
+static const struct timer_ops rockchip_timer_ops = {
+ .get_count = rockchip_timer_get_count,
+};
+
+static const struct udevice_id rockchip_timer_ids[] = {
+ { .compatible = "rockchip,rk3188-timer" },
+ { .compatible = "rockchip,rk3288-timer" },
+ { .compatible = "rockchip,rk3368-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(rockchip_rk3368_timer) = {
+ .name = "rockchip_rk3368_timer",
+ .id = UCLASS_TIMER,
+ .of_match = rockchip_timer_ids,
+ .probe = rockchip_timer_probe,
+ .ops = &rockchip_timer_ops,
+ .priv_auto = sizeof(struct rockchip_timer_priv),
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ .plat_auto = sizeof(struct rockchip_timer_plat),
+#endif
+ .of_to_plat = rockchip_clk_of_to_plat,
+};
diff --git a/roms/u-boot/drivers/timer/sandbox_timer.c b/roms/u-boot/drivers/timer/sandbox_timer.c
new file mode 100644
index 000000000..c846bfb9f
--- /dev/null
+++ b/roms/u-boot/drivers/timer/sandbox_timer.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <os.h>
+
+#define SANDBOX_TIMER_RATE 1000000
+
+/* system timer offset in ms */
+static unsigned long sandbox_timer_offset;
+
+void timer_test_add_offset(unsigned long offset)
+{
+ sandbox_timer_offset += offset;
+}
+
+u64 notrace timer_early_get_count(void)
+{
+ return os_get_nsec() / 1000 + sandbox_timer_offset * 1000;
+}
+
+unsigned long notrace timer_early_get_rate(void)
+{
+ return SANDBOX_TIMER_RATE;
+}
+
+static notrace u64 sandbox_timer_get_count(struct udevice *dev)
+{
+ return timer_early_get_count();
+}
+
+static int sandbox_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (CONFIG_IS_ENABLED(CPU) &&
+ dev_read_bool(dev, "sandbox,timebase-frequency-fallback"))
+ return timer_timebase_fallback(dev);
+ else if (!uc_priv->clock_rate)
+ uc_priv->clock_rate = SANDBOX_TIMER_RATE;
+
+ return 0;
+}
+
+static const struct timer_ops sandbox_timer_ops = {
+ .get_count = sandbox_timer_get_count,
+};
+
+static const struct udevice_id sandbox_timer_ids[] = {
+ { .compatible = "sandbox,timer" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_timer) = {
+ .name = "sandbox_timer",
+ .id = UCLASS_TIMER,
+ .of_match = sandbox_timer_ids,
+ .probe = sandbox_timer_probe,
+ .ops = &sandbox_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+/* This is here in case we don't have a device tree */
+U_BOOT_DRVINFO(sandbox_timer_non_fdt) = {
+ .name = "sandbox_timer",
+};
diff --git a/roms/u-boot/drivers/timer/sifive_clint_timer.c b/roms/u-boot/drivers/timer/sifive_clint_timer.c
new file mode 100644
index 000000000..939b99d93
--- /dev/null
+++ b/roms/u-boot/drivers/timer/sifive_clint_timer.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <linux/err.h>
+
+/* mtime register */
+#define MTIME_REG(base) ((ulong)(base) + 0xbff8)
+
+static u64 notrace sifive_clint_get_count(struct udevice *dev)
+{
+ return readq((void __iomem *)MTIME_REG(dev_get_priv(dev)));
+}
+
+#if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
+/**
+ * timer_early_get_rate() - Get the timer rate before driver model
+ */
+unsigned long notrace timer_early_get_rate(void)
+{
+ return RISCV_MMODE_TIMER_FREQ;
+}
+
+/**
+ * timer_early_get_count() - Get the timer count before driver model
+ *
+ */
+u64 notrace timer_early_get_count(void)
+{
+ return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE));
+}
+#endif
+
+static const struct timer_ops sifive_clint_ops = {
+ .get_count = sifive_clint_get_count,
+};
+
+static int sifive_clint_probe(struct udevice *dev)
+{
+ dev_set_priv(dev, dev_read_addr_ptr(dev));
+ if (!dev_get_priv(dev))
+ return -EINVAL;
+
+ return timer_timebase_fallback(dev);
+}
+
+static const struct udevice_id sifive_clint_ids[] = {
+ { .compatible = "riscv,clint0" },
+ { .compatible = "sifive,clint0" },
+ { }
+};
+
+U_BOOT_DRIVER(sifive_clint) = {
+ .name = "sifive_clint",
+ .id = UCLASS_TIMER,
+ .of_match = sifive_clint_ids,
+ .probe = sifive_clint_probe,
+ .ops = &sifive_clint_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/timer/sti-timer.c b/roms/u-boot/drivers/timer/sti-timer.c
new file mode 100644
index 000000000..87444a065
--- /dev/null
+++ b/roms/u-boot/drivers/timer/sti-timer.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <timer.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/arch-armv7/globaltimer.h>
+
+struct sti_timer_priv {
+ struct globaltimer *global_timer;
+};
+
+static u64 sti_timer_get_count(struct udevice *dev)
+{
+ struct sti_timer_priv *priv = dev_get_priv(dev);
+ struct globaltimer *global_timer = priv->global_timer;
+ u32 low, high;
+ u64 timer;
+ u32 old = readl(&global_timer->cnt_h);
+
+ while (1) {
+ low = readl(&global_timer->cnt_l);
+ high = readl(&global_timer->cnt_h);
+ if (old == high)
+ break;
+ else
+ old = high;
+ }
+ timer = high;
+ return (u64)((timer << 32) | low);
+}
+
+static int sti_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct sti_timer_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ int err;
+ ulong ret;
+
+ /* get arm global timer base address */
+ priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev);
+ if (!priv->global_timer)
+ return -ENOENT;
+
+ err = clk_get_by_index(dev, 0, &clk);
+ if (!err) {
+ ret = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ uc_priv->clock_rate = ret;
+ } else {
+ uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+ }
+
+ /* init timer */
+ writel(0x01, &priv->global_timer->ctl);
+
+ return 0;
+}
+
+static const struct timer_ops sti_timer_ops = {
+ .get_count = sti_timer_get_count,
+};
+
+static const struct udevice_id sti_timer_ids[] = {
+ { .compatible = "arm,cortex-a9-global-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(sti_timer) = {
+ .name = "sti_timer",
+ .id = UCLASS_TIMER,
+ .of_match = sti_timer_ids,
+ .priv_auto = sizeof(struct sti_timer_priv),
+ .probe = sti_timer_probe,
+ .ops = &sti_timer_ops,
+};
diff --git a/roms/u-boot/drivers/timer/stm32_timer.c b/roms/u-boot/drivers/timer/stm32_timer.c
new file mode 100644
index 000000000..e34f5202f
--- /dev/null
+++ b/roms/u-boot/drivers/timer/stm32_timer.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#define LOG_CATEGORY UCLASS_TIMER
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <timer.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+
+/* Timer control1 register */
+#define CR1_CEN BIT(0)
+#define CR1_ARPE BIT(7)
+
+/* Event Generation Register register */
+#define EGR_UG BIT(0)
+
+/* Auto reload register for free running config */
+#define GPT_FREE_RUNNING 0xFFFFFFFF
+
+struct stm32_timer_regs {
+ u32 cr1;
+ u32 cr2;
+ u32 smcr;
+ u32 dier;
+ u32 sr;
+ u32 egr;
+ u32 ccmr1;
+ u32 ccmr2;
+ u32 ccer;
+ u32 cnt;
+ u32 psc;
+ u32 arr;
+ u32 reserved;
+ u32 ccr1;
+ u32 ccr2;
+ u32 ccr3;
+ u32 ccr4;
+ u32 reserved1;
+ u32 dcr;
+ u32 dmar;
+ u32 tim2_5_or;
+};
+
+struct stm32_timer_priv {
+ struct stm32_timer_regs *base;
+};
+
+static u64 stm32_timer_get_count(struct udevice *dev)
+{
+ struct stm32_timer_priv *priv = dev_get_priv(dev);
+ struct stm32_timer_regs *regs = priv->base;
+
+ return readl(&regs->cnt);
+}
+
+static int stm32_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct stm32_timer_priv *priv = dev_get_priv(dev);
+ struct stm32_timer_regs *regs;
+ struct clk clk;
+ fdt_addr_t addr;
+ int ret;
+ u32 rate, psc;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = (struct stm32_timer_regs *)addr;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ regs = priv->base;
+
+ /* Stop the timer */
+ clrbits_le32(&regs->cr1, CR1_CEN);
+
+ /* get timer clock */
+ rate = clk_get_rate(&clk);
+
+ /* we set timer prescaler to obtain a 1MHz timer counter frequency */
+ psc = (rate / CONFIG_SYS_HZ_CLOCK) - 1;
+ writel(psc, &regs->psc);
+
+ /* Set timer frequency to 1MHz */
+ uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+
+ /* Configure timer for auto-reload */
+ setbits_le32(&regs->cr1, CR1_ARPE);
+
+ /* load value for auto reload */
+ writel(GPT_FREE_RUNNING, &regs->arr);
+
+ /* start timer */
+ setbits_le32(&regs->cr1, CR1_CEN);
+
+ /* Update generation */
+ setbits_le32(&regs->egr, EGR_UG);
+
+ return 0;
+}
+
+static const struct timer_ops stm32_timer_ops = {
+ .get_count = stm32_timer_get_count,
+};
+
+static const struct udevice_id stm32_timer_ids[] = {
+ { .compatible = "st,stm32-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(stm32_timer) = {
+ .name = "stm32_timer",
+ .id = UCLASS_TIMER,
+ .of_match = stm32_timer_ids,
+ .priv_auto = sizeof(struct stm32_timer_priv),
+ .probe = stm32_timer_probe,
+ .ops = &stm32_timer_ops,
+};
+
diff --git a/roms/u-boot/drivers/timer/timer-uclass.c b/roms/u-boot/drivers/timer/timer-uclass.c
new file mode 100644
index 000000000..73b4a5cd2
--- /dev/null
+++ b/roms/u-boot/drivers/timer/timer-uclass.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <cpu.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/lists.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <init.h>
+#include <timer.h>
+#include <linux/err.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Implement a timer uclass to work with lib/time.c. The timer is usually
+ * a 32/64 bits free-running up counter. The get_rate() method is used to get
+ * the input clock frequency of the timer. The get_count() method is used
+ * to get the current 64 bits count value. If the hardware is counting down,
+ * the value should be inversed inside the method. There may be no real
+ * tick, and no timer interrupt.
+ */
+
+int notrace timer_get_count(struct udevice *dev, u64 *count)
+{
+ const struct timer_ops *ops = device_get_ops(dev);
+
+ if (!ops->get_count)
+ return -ENOSYS;
+
+ *count = ops->get_count(dev);
+ return 0;
+}
+
+unsigned long notrace timer_get_rate(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return uc_priv->clock_rate;
+}
+
+static int timer_pre_probe(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct clk timer_clk;
+ int err;
+ ulong ret;
+
+ /* It is possible that a timer device has a null ofnode */
+ if (!dev_has_ofnode(dev))
+ return 0;
+
+ err = clk_get_by_index(dev, 0, &timer_clk);
+ if (!err) {
+ ret = clk_get_rate(&timer_clk);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ uc_priv->clock_rate = ret;
+ } else {
+ uc_priv->clock_rate =
+ dev_read_u32_default(dev, "clock-frequency", 0);
+ }
+#endif
+
+ return 0;
+}
+
+static int timer_post_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (!uc_priv->clock_rate)
+ return -EINVAL;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(CPU)
+int timer_timebase_fallback(struct udevice *dev)
+{
+ struct udevice *cpu;
+ struct cpu_plat *cpu_plat;
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Did we get our clock rate from the device tree? */
+ if (uc_priv->clock_rate)
+ return 0;
+
+ /* Fall back to timebase-frequency */
+ dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n");
+ cpu = cpu_get_current_dev();
+ if (!cpu)
+ return -ENODEV;
+
+ cpu_plat = dev_get_parent_plat(cpu);
+ if (!cpu_plat)
+ return -ENODEV;
+
+ uc_priv->clock_rate = cpu_plat->timebase_freq;
+ return 0;
+}
+#endif
+
+u64 timer_conv_64(u32 count)
+{
+ /* increment tbh if tbl has rolled over */
+ if (count < gd->timebase_l)
+ gd->timebase_h++;
+ gd->timebase_l = count;
+ return ((u64)gd->timebase_h << 32) | gd->timebase_l;
+}
+
+int notrace dm_timer_init(void)
+{
+ struct udevice *dev = NULL;
+ __maybe_unused ofnode node;
+ int ret;
+
+ if (gd->timer)
+ return 0;
+
+ /*
+ * Directly access gd->dm_root to suppress error messages, if the
+ * virtual root driver does not yet exist.
+ */
+ if (gd->dm_root == NULL)
+ return -EAGAIN;
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ /* Check for a chosen timer to be used for tick */
+ node = ofnode_get_chosen_node("tick-timer");
+
+ if (ofnode_valid(node) &&
+ uclass_get_device_by_ofnode(UCLASS_TIMER, node, &dev)) {
+ /*
+ * If the timer is not marked to be bound before
+ * relocation, bind it anyway.
+ */
+ if (!lists_bind_fdt(dm_root(), node, &dev, false)) {
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+ }
+ }
+#endif
+
+ if (!dev) {
+ /* Fall back to the first available timer */
+ ret = uclass_first_device_err(UCLASS_TIMER, &dev);
+ if (ret)
+ return ret;
+ }
+
+ if (dev) {
+ gd->timer = dev;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+UCLASS_DRIVER(timer) = {
+ .id = UCLASS_TIMER,
+ .name = "timer",
+ .pre_probe = timer_pre_probe,
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_probe = timer_post_probe,
+ .per_device_auto = sizeof(struct timer_dev_priv),
+};
diff --git a/roms/u-boot/drivers/timer/tsc_timer.c b/roms/u-boot/drivers/timer/tsc_timer.c
new file mode 100644
index 000000000..7d19a9962
--- /dev/null
+++ b/roms/u-boot/drivers/timer/tsc_timer.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * TSC calibration codes are adapted from Linux kernel
+ * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <time.h>
+#include <timer.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+#include <asm/msr.h>
+#include <asm/u-boot-x86.h>
+#include <linux/delay.h>
+
+#define MAX_NUM_FREQS 9
+
+#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E
+#define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */
+#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E
+#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */
+#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E
+#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * native_calibrate_tsc
+ * Determine TSC frequency via CPUID, else return 0.
+ */
+static unsigned long native_calibrate_tsc(void)
+{
+ struct cpuid_result tsc_info;
+ unsigned int crystal_freq;
+
+ if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
+ return 0;
+
+ if (cpuid_eax(0) < 0x15)
+ return 0;
+
+ tsc_info = cpuid(0x15);
+
+ if (tsc_info.ebx == 0 || tsc_info.eax == 0)
+ return 0;
+
+ crystal_freq = tsc_info.ecx / 1000;
+ if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) {
+ switch (gd->arch.x86_model) {
+ case INTEL_FAM6_SKYLAKE_MOBILE:
+ case INTEL_FAM6_SKYLAKE_DESKTOP:
+ case INTEL_FAM6_KABYLAKE_MOBILE:
+ case INTEL_FAM6_KABYLAKE_DESKTOP:
+ crystal_freq = 24000; /* 24.0 MHz */
+ break;
+ case INTEL_FAM6_ATOM_GOLDMONT_X:
+ crystal_freq = 25000; /* 25.0 MHz */
+ break;
+ case INTEL_FAM6_ATOM_GOLDMONT:
+ crystal_freq = 19200; /* 19.2 MHz */
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ return (crystal_freq * tsc_info.ebx / tsc_info.eax) / 1000;
+}
+
+static unsigned long cpu_mhz_from_cpuid(void)
+{
+ if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
+ return 0;
+
+ if (cpuid_eax(0) < 0x16)
+ return 0;
+
+ return cpuid_eax(0x16);
+}
+
+/*
+ * According to Intel 64 and IA-32 System Programming Guide,
+ * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
+ * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
+ * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
+ * so we need manually differentiate SoC families. This is what the
+ * field msr_plat does.
+ */
+struct freq_desc {
+ u8 x86_family; /* CPU family */
+ u8 x86_model; /* model */
+ /* 2: use 100MHz, 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS */
+ u8 msr_plat;
+ u32 freqs[MAX_NUM_FREQS];
+};
+
+static struct freq_desc freq_desc_tables[] = {
+ /* PNW */
+ { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200, 0 } },
+ /* CLV+ */
+ { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200, 0 } },
+ /* TNG - Intel Atom processor Z3400 series */
+ { 6, 0x4a, 1, { 0, 100000, 133300, 0, 0, 0, 0, 0, 0 } },
+ /* VLV2 - Intel Atom processor E3000, Z3600, Z3700 series */
+ { 6, 0x37, 1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0, 0 } },
+ /* ANN - Intel Atom processor Z3500 series */
+ { 6, 0x5a, 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0, 0 } },
+ /* AMT - Intel Atom processor X7-Z8000 and X5-Z8000 series */
+ { 6, 0x4c, 1, { 83300, 100000, 133300, 116700,
+ 80000, 93300, 90000, 88900, 87500 } },
+ /* Ivybridge */
+ { 6, 0x3a, 2, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+};
+
+static int match_cpu(u8 family, u8 model)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(freq_desc_tables); i++) {
+ if ((family == freq_desc_tables[i].x86_family) &&
+ (model == freq_desc_tables[i].x86_model))
+ return i;
+ }
+
+ return -1;
+}
+
+/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
+#define id_to_freq(cpu_index, freq_id) \
+ (freq_desc_tables[cpu_index].freqs[freq_id])
+
+/*
+ * TSC on Intel Atom SoCs capable of determining TSC frequency by MSR is
+ * reliable and the frequency is known (provided by HW).
+ *
+ * On these platforms PIT/HPET is generally not available so calibration won't
+ * work at all and there is no other clocksource to act as a watchdog for the
+ * TSC, so we have no other choice than to trust it.
+ *
+ * Returns the TSC frequency in MHz or 0 if HW does not provide it.
+ */
+static unsigned long __maybe_unused cpu_mhz_from_msr(void)
+{
+ u32 lo, hi, ratio, freq_id, freq;
+ unsigned long res;
+ int cpu_index;
+
+ if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
+ return 0;
+
+ cpu_index = match_cpu(gd->arch.x86, gd->arch.x86_model);
+ if (cpu_index < 0)
+ return 0;
+
+ if (freq_desc_tables[cpu_index].msr_plat) {
+ rdmsr(MSR_PLATFORM_INFO, lo, hi);
+ ratio = (lo >> 8) & 0xff;
+ } else {
+ rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+ ratio = (hi >> 8) & 0x1f;
+ }
+ debug("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
+
+ if (freq_desc_tables[cpu_index].msr_plat == 2) {
+ /* TODO: Figure out how best to deal with this */
+ freq = 100000;
+ debug("Using frequency: %u KHz\n", freq);
+ } else {
+ /* Get FSB FREQ ID */
+ rdmsr(MSR_FSB_FREQ, lo, hi);
+ freq_id = lo & 0x7;
+ freq = id_to_freq(cpu_index, freq_id);
+ debug("Resolved frequency ID: %u, frequency: %u KHz\n",
+ freq_id, freq);
+ }
+
+ /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
+ res = freq * ratio / 1000;
+ debug("TSC runs at %lu MHz\n", res);
+
+ return res;
+}
+
+/*
+ * This reads the current MSB of the PIT counter, and
+ * checks if we are running on sufficiently fast and
+ * non-virtualized hardware.
+ *
+ * Our expectations are:
+ *
+ * - the PIT is running at roughly 1.19MHz
+ *
+ * - each IO is going to take about 1us on real hardware,
+ * but we allow it to be much faster (by a factor of 10) or
+ * _slightly_ slower (ie we allow up to a 2us read+counter
+ * update - anything else implies a unacceptably slow CPU
+ * or PIT for the fast calibration to work.
+ *
+ * - with 256 PIT ticks to read the value, we have 214us to
+ * see the same MSB (and overhead like doing a single TSC
+ * read per MSB value etc).
+ *
+ * - We're doing 2 reads per loop (LSB, MSB), and we expect
+ * them each to take about a microsecond on real hardware.
+ * So we expect a count value of around 100. But we'll be
+ * generous, and accept anything over 50.
+ *
+ * - if the PIT is stuck, and we see *many* more reads, we
+ * return early (and the next caller of pit_expect_msb()
+ * then consider it a failure when they don't see the
+ * next expected value).
+ *
+ * These expectations mean that we know that we have seen the
+ * transition from one expected value to another with a fairly
+ * high accuracy, and we didn't miss any events. We can thus
+ * use the TSC value at the transitions to calculate a pretty
+ * good value for the TSC frequencty.
+ */
+static inline int pit_verify_msb(unsigned char val)
+{
+ /* Ignore LSB */
+ inb(0x42);
+ return inb(0x42) == val;
+}
+
+static inline int pit_expect_msb(unsigned char val, u64 *tscp,
+ unsigned long *deltap)
+{
+ int count;
+ u64 tsc = 0, prev_tsc = 0;
+
+ for (count = 0; count < 50000; count++) {
+ if (!pit_verify_msb(val))
+ break;
+ prev_tsc = tsc;
+ tsc = rdtsc();
+ }
+ *deltap = rdtsc() - prev_tsc;
+ *tscp = tsc;
+
+ /*
+ * We require _some_ success, but the quality control
+ * will be based on the error terms on the TSC values.
+ */
+ return count > 5;
+}
+
+/*
+ * How many MSB values do we want to see? We aim for
+ * a maximum error rate of 500ppm (in practice the
+ * real error is much smaller), but refuse to spend
+ * more than 50ms on it.
+ */
+#define MAX_QUICK_PIT_MS 50
+#define MAX_QUICK_PIT_ITERATIONS (MAX_QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256)
+
+static unsigned long __maybe_unused quick_pit_calibrate(void)
+{
+ int i;
+ u64 tsc, delta;
+ unsigned long d1, d2;
+
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ /*
+ * Counter 2, mode 0 (one-shot), binary count
+ *
+ * NOTE! Mode 2 decrements by two (and then the
+ * output is flipped each time, giving the same
+ * final output frequency as a decrement-by-one),
+ * so mode 0 is much better when looking at the
+ * individual counts.
+ */
+ outb(0xb0, 0x43);
+
+ /* Start at 0xffff */
+ outb(0xff, 0x42);
+ outb(0xff, 0x42);
+
+ /*
+ * The PIT starts counting at the next edge, so we
+ * need to delay for a microsecond. The easiest way
+ * to do that is to just read back the 16-bit counter
+ * once from the PIT.
+ */
+ pit_verify_msb(0);
+
+ if (pit_expect_msb(0xff, &tsc, &d1)) {
+ for (i = 1; i <= MAX_QUICK_PIT_ITERATIONS; i++) {
+ if (!pit_expect_msb(0xff-i, &delta, &d2))
+ break;
+
+ /*
+ * Iterate until the error is less than 500 ppm
+ */
+ delta -= tsc;
+ if (d1+d2 >= delta >> 11)
+ continue;
+
+ /*
+ * Check the PIT one more time to verify that
+ * all TSC reads were stable wrt the PIT.
+ *
+ * This also guarantees serialization of the
+ * last cycle read ('d2') in pit_expect_msb.
+ */
+ if (!pit_verify_msb(0xfe - i))
+ break;
+ goto success;
+ }
+ }
+ debug("Fast TSC calibration failed\n");
+ return 0;
+
+success:
+ /*
+ * Ok, if we get here, then we've seen the
+ * MSB of the PIT decrement 'i' times, and the
+ * error has shrunk to less than 500 ppm.
+ *
+ * As a result, we can depend on there not being
+ * any odd delays anywhere, and the TSC reads are
+ * reliable (within the error).
+ *
+ * kHz = ticks / time-in-seconds / 1000;
+ * kHz = (t2 - t1) / (I * 256 / PIT_TICK_RATE) / 1000
+ * kHz = ((t2 - t1) * PIT_TICK_RATE) / (I * 256 * 1000)
+ */
+ delta *= PIT_TICK_RATE;
+ delta /= (i*256*1000);
+ debug("Fast TSC calibration using PIT\n");
+ return delta / 1000;
+}
+
+/* Get the speed of the TSC timer in MHz */
+unsigned notrace long get_tbclk_mhz(void)
+{
+ return get_tbclk() / 1000000;
+}
+
+static ulong get_ms_timer(void)
+{
+ return (get_ticks() * 1000) / get_tbclk();
+}
+
+ulong get_timer(ulong base)
+{
+ return get_ms_timer() - base;
+}
+
+ulong notrace timer_get_us(void)
+{
+ return get_ticks() / get_tbclk_mhz();
+}
+
+ulong timer_get_boot_us(void)
+{
+ return timer_get_us();
+}
+
+void __udelay(unsigned long usec)
+{
+ u64 now = get_ticks();
+ u64 stop;
+
+ stop = now + (u64)usec * get_tbclk_mhz();
+
+ while ((int64_t)(stop - get_ticks()) > 0)
+#if defined(CONFIG_QEMU) && defined(CONFIG_SMP)
+ /*
+ * Add a 'pause' instruction on qemu target,
+ * to give other VCPUs a chance to run.
+ */
+ asm volatile("pause");
+#else
+ ;
+#endif
+}
+
+static u64 tsc_timer_get_count(struct udevice *dev)
+{
+ u64 now_tick = rdtsc();
+
+ return now_tick - gd->arch.tsc_base;
+}
+
+static void tsc_timer_ensure_setup(bool early)
+{
+ if (gd->arch.tsc_inited)
+ return;
+ if (IS_ENABLED(CONFIG_X86_TSC_READ_BASE))
+ gd->arch.tsc_base = rdtsc();
+
+ if (!gd->arch.clock_rate) {
+ unsigned long fast_calibrate;
+
+ fast_calibrate = native_calibrate_tsc();
+ if (fast_calibrate)
+ goto done;
+
+ /* Reduce code size by dropping other methods */
+ if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
+ panic("no timer");
+
+ fast_calibrate = cpu_mhz_from_cpuid();
+ if (fast_calibrate)
+ goto done;
+
+ fast_calibrate = cpu_mhz_from_msr();
+ if (fast_calibrate)
+ goto done;
+
+ fast_calibrate = quick_pit_calibrate();
+ if (fast_calibrate)
+ goto done;
+
+ if (early)
+ fast_calibrate = CONFIG_X86_TSC_TIMER_EARLY_FREQ;
+ else
+ return;
+
+done:
+ gd->arch.clock_rate = fast_calibrate * 1000000;
+ }
+ gd->arch.tsc_inited = true;
+}
+
+static int tsc_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Try hardware calibration first */
+ tsc_timer_ensure_setup(false);
+ if (!gd->arch.clock_rate) {
+ /*
+ * Use the clock frequency specified in the
+ * device tree as last resort
+ */
+ if (!uc_priv->clock_rate)
+ panic("TSC frequency is ZERO");
+ } else {
+ uc_priv->clock_rate = gd->arch.clock_rate;
+ }
+
+ return 0;
+}
+
+unsigned long notrace timer_early_get_rate(void)
+{
+ /*
+ * When TSC timer is used as the early timer, be warned that the timer
+ * clock rate can only be calibrated via some hardware ways. Specifying
+ * it in the device tree won't work for the early timer.
+ */
+ tsc_timer_ensure_setup(true);
+
+ return gd->arch.clock_rate;
+}
+
+u64 notrace timer_early_get_count(void)
+{
+ tsc_timer_ensure_setup(true);
+
+ return rdtsc() - gd->arch.tsc_base;
+}
+
+static const struct timer_ops tsc_timer_ops = {
+ .get_count = tsc_timer_get_count,
+};
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct udevice_id tsc_timer_ids[] = {
+ { .compatible = "x86,tsc-timer", },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(x86_tsc_timer) = {
+ .name = "x86_tsc_timer",
+ .id = UCLASS_TIMER,
+ .of_match = of_match_ptr(tsc_timer_ids),
+ .probe = tsc_timer_probe,
+ .ops = &tsc_timer_ops,
+};