diff --git a/arch/Kconfig b/arch/Kconfig
index e599e7a..37dabae 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -104,7 +104,7 @@ config X86
 	select DM_PCI
 	select PCI
 	select TIMER
-	select X86_TSC_TIMER
+	imply X86_TSC_TIMER
 	imply BLK
 	imply DM_ETH
 	imply DM_GPIO
diff --git a/arch/x86/dts/hpet.dtsi b/arch/x86/dts/hpet.dtsi
new file mode 100644
index 0000000..037dc7e
--- /dev/null
+++ b/arch/x86/dts/hpet.dtsi
@@ -0,0 +1,7 @@
+/ {
+	hpet0: hpet@fed00000 {
+		compatible = "hpet-x86";
+		u-boot,dm-pre-reloc;
+		reg = <0xfed00000 0x1000>;
+	};
+};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 2c96896..72ae6c5 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -65,6 +65,12 @@ config X86_TSC_TIMER
 	help
 	  Select this to enable Time-Stamp Counter (TSC) timer for x86.
 
+config HPET_TIMER
+	bool "High Precision Event Timers (HPET) support"
+	depends on TIMER && X86
+	help
+	  Select this to enable High Precision Event Timers (HPET) for x86.
+
 config OMAP_TIMER
 	bool "Omap timer support"
 	depends on TIMER
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index a6e7832..557fecc 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -8,6 +8,7 @@ obj-y += timer-uclass.o
 obj-$(CONFIG_ALTERA_TIMER)	+= altera_timer.o
 obj-$(CONFIG_SANDBOX_TIMER)	+= sandbox_timer.o
 obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
+obj-$(CONFIG_HPET_TIMER)	+= hpet_timer.o
 obj-$(CONFIG_OMAP_TIMER)	+= omap-timer.o
 obj-$(CONFIG_AST_TIMER)	+= ast_timer.o
 obj-$(CONFIG_STI_TIMER)		+= sti-timer.o
diff --git a/drivers/timer/hpet_timer.c b/drivers/timer/hpet_timer.c
new file mode 100644
index 0000000..0bef859
--- /dev/null
+++ b/drivers/timer/hpet_timer.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <timer.h>
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/u-boot-x86.h>
+
+#define HPET_PERIOD_REG 0x004
+#define HPET_CONFIG_REG 0x010
+#define HPET_MAIN_COUNT_L 0x0f0
+#define HPET_MAIN_COUNT_H 0x0f4
+
+#define HPET_MAX_PERIOD 100000000
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct hpet_timer_priv {
+	void *regs;
+};
+
+/*
+ * Returns HPET clock frequency in HZ
+ * (rounding to the nearest integer),
+ * or 0 if HPET is not available.
+ */
+static inline u32 get_clock_frequency(void *regs)
+{
+	u64 d = 1000000000000000ull;
+	u32 period;
+
+	period = readl(regs + HPET_PERIOD_REG);
+	if (period == 0)
+		return 0;
+	if (period > HPET_MAX_PERIOD)
+		return 0;
+
+	d += period / 2;
+
+	return d / period;
+}
+
+/*
+ * Reset and start the main counter.
+ */
+static void start_main_counter(void *regs)
+{
+	u32 config;
+
+	config = readl(regs + HPET_CONFIG_REG);
+	config &= ~1;
+	writel(config, regs + HPET_CONFIG_REG);
+	writel(0, regs + HPET_MAIN_COUNT_L);
+	writel(0, regs + HPET_MAIN_COUNT_H);
+	config |= 1;
+	writel(config, regs + HPET_CONFIG_REG);
+}
+
+/*
+ * Read the main counter as two 32-bit registers,
+ * repeat if rollover happens.
+ */
+static u64 read_main_counter(void *regs)
+{
+	u64 now_tick;
+	u32 tl, th, th0;
+
+	th = readl(regs + HPET_MAIN_COUNT_H);
+	do {
+		th0 = th;
+		tl = readl(regs + HPET_MAIN_COUNT_L);
+		th = readl(regs + HPET_MAIN_COUNT_H);
+	} while (th != th0);
+
+	now_tick = th;
+	now_tick <<= 32;
+	now_tick |= tl;
+
+	return now_tick;
+}
+
+static int hpet_timer_get_count(struct udevice *dev, u64 *count)
+{
+	struct hpet_timer_priv *priv = dev_get_priv(dev);
+
+	*count = read_main_counter(priv->regs);
+
+	return 0;
+}
+
+static int hpet_timer_probe(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct hpet_timer_priv *priv = dev_get_priv(dev);
+	u32 rate;
+
+	rate = get_clock_frequency(priv->regs);
+	if (rate == 0)
+		return -ENODEV;
+
+	start_main_counter(priv->regs);
+
+	uc_priv->clock_rate = rate;
+
+	return 0;
+}
+
+#ifndef CONFIG_X86_TSC_TIMER
+
+static void *early_regs = (void *) CONFIG_HPET_ADDRESS;
+
+unsigned long notrace timer_early_get_rate(void)
+{
+	return get_clock_frequency(early_regs);
+}
+
+u64 notrace timer_early_get_count(void)
+{
+	return read_main_counter(early_regs);
+}
+
+int timer_init(void)
+{
+	if (get_clock_frequency(early_regs) == 0)
+		return -ENODEV;
+
+	start_main_counter(early_regs);
+
+	return 0;
+}
+
+ulong timer_get_boot_us(void)
+{
+	u32 period;
+	u64 d;
+
+	period = readl(early_regs + HPET_PERIOD_REG);
+	if (period == 0)
+		return 0;
+	if (period > HPET_MAX_PERIOD)
+		return 0;
+
+	d = read_main_counter(early_regs);
+
+	/*
+	 * Multiplication overflow
+	 * at 2^64 femtoseconds
+	 * (more than 5 hours)
+	 */
+
+	d *= period;
+
+	return d / 1000000000;
+}
+
+#endif /* CONFIG_X86_TSC_TIMER */
+
+static int hpet_timer_ofdata_to_platdata(struct udevice *dev)
+{
+	struct hpet_timer_priv *priv = dev_get_priv(dev);
+	priv->regs = map_physmem(devfdt_get_addr(dev), 0x1000, MAP_NOCACHE);
+
+	return 0;
+}
+
+static const struct timer_ops hpet_timer_ops = {
+	.get_count = hpet_timer_get_count,
+};
+
+static const struct udevice_id hpet_timer_ids[] = {
+	{ .compatible = "hpet-x86", },
+	{ .compatible = "intel,ce4100-hpet", },
+	{ }
+};
+
+U_BOOT_DRIVER(hpet_timer) = {
+	.name	= "hpet_timer",
+	.id	= UCLASS_TIMER,
+	.of_match = hpet_timer_ids,
+	.ofdata_to_platdata = hpet_timer_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct hpet_timer_priv),
+	.probe = hpet_timer_probe,
+	.ops	= &hpet_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
