diff options
Diffstat (limited to 'drivers/timer')
-rw-r--r-- | drivers/timer/Kconfig | 25 | ||||
-rw-r--r-- | drivers/timer/Makefile | 3 | ||||
-rw-r--r-- | drivers/timer/rockchip_timer.c | 107 | ||||
-rw-r--r-- | drivers/timer/timer-uclass.c | 8 |
4 files changed, 140 insertions, 3 deletions
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index c6663033311..13f122350b2 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -9,6 +9,24 @@ config 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 @@ -85,4 +103,11 @@ config AE3XX_TIMER help Select this to enable a timer for AE3XX devices. +config ROCKCHIP_TIMER + bool "Rockchip timer support" + depends on TIMER + help + Select this to enable support for the timer found on + Rockchip devices. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index ced7bd66bd3..fa7ce7c8358 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -4,7 +4,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_TIMER) += timer-uclass.o +obj-y += timer-uclass.o obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o @@ -14,3 +14,4 @@ obj-$(CONFIG_STI_TIMER) += sti-timer.o obj-$(CONFIG_ARC_TIMER) += arc_timer.o obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o obj-$(CONFIG_AE3XX_TIMER) += ae3xx_timer.o +obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o diff --git a/drivers/timer/rockchip_timer.c b/drivers/timer/rockchip_timer.c new file mode 100644 index 00000000000..0848033c662 --- /dev/null +++ b/drivers/timer/rockchip_timer.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <mapmem.h> +#include <asm/arch/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 int rockchip_timer_get_count(struct udevice *dev, u64 *count) +{ + struct rockchip_timer_priv *priv = dev_get_priv(dev); + uint64_t timebase_h, timebase_l; + uint64_t cntr; + + timebase_l = readl(&priv->timer->timer_curr_value0); + timebase_h = readl(&priv->timer->timer_curr_value1); + + /* timers are down-counting */ + cntr = timebase_h << 32 | timebase_l; + *count = ~0ull - cntr; + return 0; +} + +static int rockchip_clk_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rockchip_timer_priv *priv = dev_get_priv(dev); + + priv->timer = (struct rk_timer *)devfdt_get_addr(dev); +#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; + + /* 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_platdata(dev); + + priv->timer = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]); + 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,rk3368-timer" }, + {} +}; + +U_BOOT_DRIVER(arc_timer) = { + .name = "rockchip_rk3368_timer", + .id = UCLASS_TIMER, + .of_match = rockchip_timer_ids, + .probe = rockchip_timer_probe, + .ops = &rockchip_timer_ops, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct rockchip_timer_priv), +#if CONFIG_IS_ENABLED(OF_PLATDATA) + .platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat), +#endif + .ofdata_to_platdata = rockchip_clk_ofdata_to_platdata, +}; diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index ec10b282882..a84755f4c5a 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -42,6 +42,7 @@ unsigned long notrace timer_get_rate(struct udevice *dev) 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; @@ -56,6 +57,7 @@ static int timer_pre_probe(struct udevice *dev) } else uc_priv->clock_rate = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "clock-frequency", 0); +#endif return 0; } @@ -81,16 +83,18 @@ u64 timer_conv_64(u32 count) int notrace dm_timer_init(void) { - const void *blob = gd->fdt_blob; + __maybe_unused const void *blob = gd->fdt_blob; struct udevice *dev = NULL; - int node; + int node = -ENOENT; int ret; if (gd->timer) return 0; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) /* Check for a chosen timer to be used for tick */ node = fdtdec_get_chosen_node(blob, "tick-timer"); +#endif if (node < 0) { /* No chosen timer, trying first available timer */ ret = uclass_first_device_err(UCLASS_TIMER, &dev); |