[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