[U-Boot] [PATCH 1/3] drivers: timer: Introduce ARC timer driver
Simon Glass
sjg at chromium.org
Sat Jan 21 04:51:06 CET 2017
On 16 January 2017 at 06:49, Vlad Zakharov
<Vladislav.Zakharov at synopsys.com> wrote:
> This commit introduces timer driver for ARC.
>
> ARC timers are configured via ARC AUX registers so we use special
> functions to access timer control registers.
>
> This driver allows utilization of either timer0 or timer1
> depending on which one is available in real hardware. Essentially
> only existing timers should be mentioned in board's Device Tree
> description.
>
> Signed-off-by: Vlad Zakharov <vzakhar at synopsys.com>
> ---
> arch/arc/include/asm/arcregs.h | 4 ++
> doc/device-tree-bindings/timer/arc_timer.txt | 24 +++++++
> drivers/timer/Kconfig | 9 +++
> drivers/timer/Makefile | 1 +
> drivers/timer/arc_timer.c | 103 +++++++++++++++++++++++++++
> 5 files changed, 141 insertions(+)
> create mode 100644 doc/device-tree-bindings/timer/arc_timer.txt
> create mode 100644 drivers/timer/arc_timer.c
Reviewed-by: Simon Glass <sjg at chromium.org>
>
> diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
> index cf999b0..54a9b00 100644
> --- a/arch/arc/include/asm/arcregs.h
> +++ b/arch/arc/include/asm/arcregs.h
> @@ -33,6 +33,10 @@
> #define ARC_AUX_TIMER0_CTRL 0x22 /* Timer 0 control */
> #define ARC_AUX_TIMER0_LIMIT 0x23 /* Timer 0 limit */
>
> +#define ARC_AUX_TIMER1_CNT 0x100 /* Timer 1 count */
> +#define ARC_AUX_TIMER1_CTRL 0x101 /* Timer 1 control */
> +#define ARC_AUX_TIMER1_LIMIT 0x102 /* Timer 1 limit */
> +
> #define ARC_AUX_INTR_VEC_BASE 0x25
>
> /* Data cache related auxiliary registers */
> diff --git a/doc/device-tree-bindings/timer/arc_timer.txt b/doc/device-tree-bindings/timer/arc_timer.txt
> new file mode 100644
> index 0000000..441f2f3
> --- /dev/null
> +++ b/doc/device-tree-bindings/timer/arc_timer.txt
> @@ -0,0 +1,24 @@
> +ARC Timer
> +
> +Required properties:
> +
> +- compatible : should be "snps,arc-timer".
> +- reg : Specifies timer ID, could be either 0 or 1.
> +- clocks : Specifies clocks that drives the counter.
> +
> +Examples:
> +
> +timer at 0 {
> + compatible = "snps,arc-timer";
> + clocks = <&core_clk>;
> + reg = <0>;
> +};
> +
> +timer at 1 {
> + compatible = "snps,arc-timer";
> + clocks = <&core_clk>;
> + reg = <1>;
> +};
> +
> +NOTE: if you specify both timers, clocks always should be the same
> +as each timer is driven by the same core clock.
> diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
> index cb18f12..a6c77ea 100644
> --- a/drivers/timer/Kconfig
> +++ b/drivers/timer/Kconfig
> @@ -46,4 +46,13 @@ config OMAP_TIMER
> help
> Select this to enable an timer for Omap devices.
>
> +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.
> +
> endmenu
> diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
> index f351fbb..e9624dd 100644
> --- a/drivers/timer/Makefile
> +++ b/drivers/timer/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
> obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
> obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
> obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
> +obj-$(CONFIG_ARC_TIMER) += arc_timer.o
> diff --git a/drivers/timer/arc_timer.c b/drivers/timer/arc_timer.c
> new file mode 100644
> index 0000000..07274f2
> --- /dev/null
> +++ b/drivers/timer/arc_timer.c
> @@ -0,0 +1,103 @@
> +/*
> + * Copyright (C) 2016 Synopsys, Inc. All rights reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <timer.h>
> +#include <asm/io.h>
> +#include <asm/arcregs.h>
put this line before the previous one.
> +
> +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 int arc_timer_get_count(struct udevice *dev, u64 *count)
> +{
> + u32 val = 0;
> + struct arc_timer_priv *priv = dev_get_priv(dev);
Add blank line
> + 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;
> + }
> + *count = timer_conv_64(val);
> +
> + return 0;
> +}
> +
> +static int arc_timer_probe(struct udevice *dev)
> +{
> + int id;
> +
Drop bank line
> + struct arc_timer_priv *priv = dev_get_priv(dev);
> +
> + /* Get registers offset and size */
> + id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
> + if (id < 0)
> + return -EINVAL;
> +
> + if (id > 1)
> + return -ENXIO;
> +
> + priv->timer_id = (uint)id;
> +
> + 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);
You are writing the same values in each case. Can you set a value to
either ARC_AUX_TIMER0 or ARC_AUX_TIMER1 and then just have the code
once?
> + 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,
> + .flags = DM_FLAG_PRE_RELOC,
> + .priv_auto_alloc_size = sizeof(struct arc_timer_priv),
> +};
> --
> 2.7.4
>
Regards,
Simon
More information about the U-Boot
mailing list