On 16 January 2017 at 06:49, Vlad Zakharov <vladislav.zakha...@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 <vzak...@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 <s...@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@0 { > + compatible = "snps,arc-timer"; > + clocks = <&core_clk>; > + reg = <0>; > +}; > + > +timer@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot