[U-Boot] [PATCH 1/2] drivers: timer: Introduce ARC timer driver
Simon Glass
sjg at chromium.org
Wed Nov 2 21:14:07 CET 2016
Hi Vlad,
On 2 November 2016 at 09:44, 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 | 7 ++
> drivers/timer/Makefile | 1 +
> drivers/timer/arc_timer.c | 97 ++++++++++++++++++++++++++++
> 5 files changed, 133 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>
Looks good. Nits below.
>
> 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..e25c6ae
> --- /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.
You might consider adding a #define to a file in
include/dt-bindings/timer or similar for the 0 and 1. Then you can use
it in the source code. Up to you though.
> +- clock-frequency : The frequency of the clock that drives the counter, in Hz.
> +
> +Examples:
> +
> +timer at 0 {
> + compatible = "snps,arc-timer";
> + clock-frequency = <100000000>;
> + reg = <0>;
> +};
> +
> +timer at 1 {
> + compatible = "snps,arc-timer";
> + clock-frequency = <100000000>;
> + reg = <1>;
> +};
> +
> +NOTE: if you specify both timers, frequencies should always be the same as both timers
> +are driven by core clock.
> diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
> index cb18f12..721007d 100644
> --- a/drivers/timer/Kconfig
> +++ b/drivers/timer/Kconfig
> @@ -46,4 +46,11 @@ config OMAP_TIMER
> help
> Select this to enable an timer for Omap devices.
>
> +config ARC_TIMER
> + bool "ARC timer support"
> + depends on TIMER
> + depends on ARC
> + help
> + Select this to enable built-in ARC timers.
Good to include a bit more info like the capabilities of the timers
> +
> 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..727f2df
> --- /dev/null
> +++ b/drivers/timer/arc_timer.c
> @@ -0,0 +1,97 @@
> +/*
> + * 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>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/*
> + * 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 AUX register number. */
> +struct arc_timer_priv {
> + uint32_t timer_id;
uint would do. It doesn't need to be 32 bits.
> +};
> +
> +static int arc_timer_get_count(struct udevice *dev, u64 *count)
> +{
> + struct arc_timer_priv *priv = dev_get_priv(dev);
blank line here
> + switch (priv->timer_id) {
> + case 0:
Here is where you could use the defines.
> + *count = read_aux_reg(ARC_AUX_TIMER0_CNT);
> + break;
> + case 1:
> + *count = read_aux_reg(ARC_AUX_TIMER1_CNT);
> + break;
> + }
blank line before 'return'
> + return 0;
> +}
> +
> +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, "reg", -1);
> + if (id < 0)
> + return -EINVAL;
> + if (id > 1)
Could use the define here
> + return -ENXIO;
> +
> + priv->timer_id = (uint32_t)id;
> +
> +#define NH_MODE (1 << 1)
This should really go to the top of the file.
> +
> + switch (priv->timer_id) {
> + case 0:
Could use the define here
> + /* 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,
> + .flags = DM_FLAG_PRE_RELOC,
> +};
> --
> 2.7.4
>
Regards,
Simon
More information about the U-Boot
mailing list