From ca71c0031b8c26fa202d4fb18811112d3f86794e Mon Sep 17 00:00:00 2001
From: Andi Kleen <ak@muc.de>
Date: Tue, 19 Oct 2004 18:11:14 -0700
Subject: [PATCH] [PATCH] x86_64: intialize hpet char driver

Initialize HPET char driver

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 arch/x86_64/Kconfig       |  3 ++-
 arch/x86_64/kernel/time.c | 50 +++++++++++++++++++++++++++++++++++++++
 include/asm-x86_64/hpet.h |  3 +++
 3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index cb3fc95258e4..d660dcfe31e5 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -72,7 +72,8 @@ config HPET_TIMER
 	  If unsure, say Y.
 
 config HPET_EMULATE_RTC
-	def_bool HPET_TIMER && RTC=y
+	bool "Provide RTC interrupt"
+	depends on HPET_TIMER && RTC=y
 
 config GENERIC_ISA_DMA
 	bool
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 289b81dae486..d7b6d48cfb78 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -34,6 +34,7 @@
 #include <asm/hpet.h>
 #include <asm/sections.h>
 #include <linux/cpufreq.h>
+#include <linux/hpet.h>
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/apic.h>
 #endif
@@ -726,6 +727,55 @@ static unsigned int __init pit_calibrate_tsc(void)
 	return (end - start) / 50;
 }
 
+#ifdef	CONFIG_HPET
+static __init int late_hpet_init(void)
+{
+	struct hpet_data	hd;
+	unsigned int 		ntimer;
+
+	if (!vxtime.hpet_address)
+          return -1;
+
+	memset(&hd, 0, sizeof (hd));
+
+	ntimer = hpet_readl(HPET_ID);
+	ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+	ntimer++;
+
+	/*
+	 * Register with driver.
+	 * Timer0 and Timer1 is used by platform.
+	 */
+	hd.hd_address = (void *)fix_to_virt(FIX_HPET_BASE);
+	hd.hd_nirqs = ntimer;
+	hd.hd_flags = HPET_DATA_PLATFORM;
+	hpet_reserve_timer(&hd, 0);
+#ifdef	CONFIG_HPET_EMULATE_RTC
+	hpet_reserve_timer(&hd, 1);
+#endif
+	hd.hd_irq[0] = HPET_LEGACY_8254;
+	hd.hd_irq[1] = HPET_LEGACY_RTC;
+	if (ntimer > 2) {
+		struct hpet		*hpet;
+		struct hpet_timer	*timer;
+		int			i;
+
+		hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);
+
+		for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer;
+		     timer++, i++)
+			hd.hd_irq[i] = (timer->hpet_config &
+					Tn_INT_ROUTE_CNF_MASK) >>
+				Tn_INT_ROUTE_CNF_SHIFT;
+
+	}
+
+	hpet_alloc(&hd);
+	return 0;
+}
+fs_initcall(late_hpet_init);
+#endif
+
 static int hpet_init(void)
 {
 	unsigned int cfg, id;
diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h
index 08ee1e7ce3a4..1facdec69cfb 100644
--- a/include/asm-x86_64/hpet.h
+++ b/include/asm-x86_64/hpet.h
@@ -28,12 +28,15 @@
 #define HPET_ID_LEGSUP	0x00008000
 #define HPET_ID_NUMBER	0x00001f00
 #define HPET_ID_REV	0x000000ff
+#define	HPET_ID_NUMBER_SHIFT	8
 
 #define HPET_ID_VENDOR_SHIFT	16
 #define HPET_ID_VENDOR_8086	0x8086
 
 #define HPET_CFG_ENABLE	0x001
 #define HPET_CFG_LEGACY	0x002
+#define	HPET_LEGACY_8254	2
+#define	HPET_LEGACY_RTC		8
 
 #define HPET_TN_ENABLE		0x004
 #define HPET_TN_PERIODIC	0x008
-- 
2.30.9