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/Kconfig b/arch/x86/Kconfig
index 5c23b2c..2fe5b6a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -119,6 +119,27 @@ source "arch/x86/cpu/tangier/Kconfig"
 
 # architecture-specific options below
 
+choice
+	prompt "Select which timer to use early on x86"
+	depends on X86
+	default X86_EARLY_TIMER_TSC
+
+config X86_EARLY_TIMER_TSC
+	bool "TSC"
+	depends on X86_TSC_TIMER
+	help
+	  This selects x86 Time Stamp Counter (TSC) as the early timer.
+	  See CONFIG_TIMER_EARLY for the early timer description.
+
+config X86_EARLY_TIMER_HPET
+	bool "HPET"
+	depends on HPET_TIMER
+	help
+	  This selects High Precision Event Timers as the early timer.
+	  Early HPET base address is specified by CONFIG_HPET_ADDRESS.
+
+endchoice
+
 config AHCI
 	default y
 
diff --git a/arch/x86/dts/hpet.dtsi b/arch/x86/dts/hpet.dtsi
new file mode 100644
index 0000000..a74f739
--- /dev/null
+++ b/arch/x86/dts/hpet.dtsi
@@ -0,0 +1,7 @@
+/ {
+	hpet: 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..26743b7 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -65,6 +65,15 @@ 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
+	default y if X86
+	help
+	  Select this to enable High Precision Event Timers (HPET) on x86.
+	  HPET main counter increments at constant rate and does not need
+	  calibration.
+
 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..b1ce226
--- /dev/null
+++ b/drivers/timer/hpet_timer.c
@@ -0,0 +1,179 @@
+/*
+ * 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 0x0f0
+
+#define ENABLE_CNF 1
+
+#define HPET_MAX_PERIOD 100000000
+
+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 &= ~ENABLE_CNF;
+	writel(config, regs + HPET_CONFIG_REG);
+	writeq(0, regs + HPET_MAIN_COUNT);
+	config |= ENABLE_CNF;
+	writel(config, regs + HPET_CONFIG_REG);
+}
+
+/* Read the main counter, repeat if 32-bit rollover happens. */
+static u64 read_main_counter(void *regs)
+{
+	u64 t, t0;
+
+	t = readq(regs + HPET_MAIN_COUNT);
+	do {
+		t0 = t;
+		t = readq(regs + HPET_MAIN_COUNT);
+	} while ((t >> 32) != (t0 >> 32));
+
+	return t;
+}
+
+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;
+}
+
+#ifdef CONFIG_X86_EARLY_TIMER_HPET
+
+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_EARLY_TIMER_HPET */
+
+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,
+};
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
index 9296de6..bd0e75c 100644
--- a/drivers/timer/tsc_timer.c
+++ b/drivers/timer/tsc_timer.c
@@ -277,6 +277,8 @@ success:
 	return delta / 1000;
 }
 
+#ifdef CONFIG_X86_EARLY_TIMER_TSC
+
 /* Get the speed of the TSC timer in MHz */
 unsigned notrace long get_tbclk_mhz(void)
 {
@@ -322,6 +324,8 @@ void __udelay(unsigned long usec)
 #endif
 }
 
+#endif /* CONFIG_X86_EARLY_TIMER_TSC */
+
 static int tsc_timer_get_count(struct udevice *dev, u64 *count)
 {
 	u64 now_tick = rdtsc();
@@ -365,6 +369,8 @@ static int tsc_timer_probe(struct udevice *dev)
 	return 0;
 }
 
+#ifdef CONFIG_X86_EARLY_TIMER_TSC
+
 unsigned long notrace timer_early_get_rate(void)
 {
 	tsc_timer_ensure_setup();
@@ -377,6 +383,8 @@ u64 notrace timer_early_get_count(void)
 	return rdtsc() - gd->arch.tsc_base;
 }
 
+#endif
+
 static const struct timer_ops tsc_timer_ops = {
 	.get_count = tsc_timer_get_count,
 };
