diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
index cf999b0280d672c79a08f4bc2a5f2c6254fd7ff2..54a9b00d4c24cb3c0bc83d2a62631b8ad54ed28e 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 0000000000000000000000000000000000000000..5493b21d271bc6cca403d38ab5fb5b0dcee1466a
--- /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 72c14168d6f4564bf6b68a1768251edf24bf479f..e03852396b7ccb4d5302484fc256d006c1bccfae 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -65,4 +65,13 @@ config STI_TIMER
 	help
 	  Select this to enable a timer for STi 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 ae94be86c06a6163c4a9374171798c58917e45e7..bfe65fcb48315e2102f6673e6f576577b8ada15d 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
 obj-$(CONFIG_OMAP_TIMER)	+= omap-timer.o
 obj-$(CONFIG_AST_TIMER)	+= ast_timer.o
 obj-$(CONFIG_STI_TIMER)		+= sti-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 0000000000000000000000000000000000000000..e94e4a4bca7e606d6cac8e646ebe17dbfe428e21
--- /dev/null
+++ b/drivers/timer/arc_timer.c
@@ -0,0 +1,113 @@
+/*
+ * 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/arcregs.h>
+#include <asm/io.h>
+
+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);
+
+	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;
+	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;
+
+	/*
+	 * In ARC core there're special registers (Auxiliary or AUX) in its
+	 * separate memory space that are used for accessing some hardware
+	 * features of the core. They are not mapped in normal memory space
+	 * and also always have the same location regardless core configuration.
+	 * Thus to simplify understanding of the programming model we chose to
+	 * access AUX regs of Timer0 and Timer1 separately instead of using
+	 * offsets from some base address.
+	 */
+
+	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);
+		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),
+};