diff options
Diffstat (limited to 'drivers/timer')
| -rw-r--r-- | drivers/timer/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/timer/Makefile | 1 | ||||
| -rw-r--r-- | drivers/timer/mchp-pit64b-timer.c | 109 | ||||
| -rw-r--r-- | drivers/timer/riscv_timer.c | 39 | ||||
| -rw-r--r-- | drivers/timer/sandbox_timer.c | 4 | ||||
| -rw-r--r-- | drivers/timer/timer-uclass.c | 31 |
6 files changed, 173 insertions, 22 deletions
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 637024445c1..f8fa4aa71f4 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -146,8 +146,8 @@ config RISCV_TIMER bool "RISC-V timer support" depends on TIMER && RISCV help - Select this to enable support for the timer as defined - by the RISC-V privileged architecture spec. + Select this to enable support for a generic RISC-V S-Mode timer + driver. config ROCKCHIP_TIMER bool "Rockchip timer support" @@ -213,4 +213,11 @@ config MTK_TIMER 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. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index c22ffebcdec..3a4d74b996b 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -22,3 +22,4 @@ 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 diff --git a/drivers/timer/mchp-pit64b-timer.c b/drivers/timer/mchp-pit64b-timer.c new file mode 100644 index 00000000000..ead8c9b84ad --- /dev/null +++ b/drivers/timer/mchp-pit64b-timer.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * 64-bit Periodic Interval Timer driver + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea <[email protected]> + */ + +#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 int mchp_pit64b_get_count(struct udevice *dev, u64 *count) +{ + 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); + + *count = ((u64)msb << 32) | lsb; + + return 0; +} + +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_alloc_size = sizeof(struct mchp_pit64b_priv), + .probe = mchp_pit64b_probe, + .ops = &mchp_pit64b_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c index 9f9f070e0b3..449fcfcfd59 100644 --- a/drivers/timer/riscv_timer.c +++ b/drivers/timer/riscv_timer.c @@ -1,36 +1,37 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * Copyright (C) 2020, Sean Anderson <[email protected]> * Copyright (C) 2018, Bin Meng <[email protected]> + * Copyright (C) 2018, Anup Patel <[email protected]> + * Copyright (C) 2012 Regents of the University of California * - * RISC-V privileged architecture defined generic timer driver + * RISC-V architecturally-defined generic timer driver * - * This driver relies on RISC-V platform codes to provide the essential API - * riscv_get_time() which is supposed to return the timer counter as defined - * by the RISC-V privileged architecture spec. - * - * This driver can be used in both M-mode and S-mode U-Boot. + * 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/io.h> - -/** - * riscv_get_time() - get the timer counter - * - * Platform codes should provide this API in order to make this driver function. - * - * @time: the 64-bit timer count as defined by the RISC-V privileged - * architecture spec. - * @return: 0 on success, -ve on error. - */ -extern int riscv_get_time(u64 *time); +#include <asm/csr.h> static int riscv_timer_get_count(struct udevice *dev, u64 *count) { - return riscv_get_time(count); + if (IS_ENABLED(CONFIG_64BIT)) { + *count = csr_read(CSR_TIME); + } else { + u32 hi, lo; + + do { + hi = csr_read(CSR_TIMEH); + lo = csr_read(CSR_TIME); + } while (hi != csr_read(CSR_TIMEH)); + + *count = ((u64)hi << 32) | lo; + } + + return 0; } static int riscv_timer_probe(struct udevice *dev) diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c index 5228486082c..6a503c2f153 100644 --- a/drivers/timer/sandbox_timer.c +++ b/drivers/timer/sandbox_timer.c @@ -40,7 +40,9 @@ static int sandbox_timer_probe(struct udevice *dev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); - if (!uc_priv->clock_rate) + if (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; diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index 14dde950a18..e9802c8b43e 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -4,6 +4,7 @@ */ #include <common.h> +#include <cpu.h> #include <dm.h> #include <init.h> #include <dm/lists.h> @@ -79,6 +80,36 @@ static int timer_post_probe(struct udevice *dev) return 0; } +/* + * TODO: should be CONFIG_IS_ENABLED(CPU), but the SPL config has _SUPPORT on + * the end... + */ +#if defined(CONFIG_CPU) || defined(CONFIG_SPL_CPU_SUPPORT) +int timer_timebase_fallback(struct udevice *dev) +{ + struct udevice *cpu; + struct cpu_platdata *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_platdata(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 */ |
