
Hi Vlad,
On 2 November 2016 at 09:44, Vlad Zakharov Vladislav.Zakharov@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@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@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@0 {
compatible = "snps,arc-timer";
clock-frequency = <100000000>;
reg = <0>;
+};
+timer@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