2008-08-05 06:22:33

by Crane Cai

[permalink] [raw]
Subject: [PATCH] X86 Architecture: HPET Rework for SB700A12

x86: HPET rework for SB700

SB700 supports the features to reduce EMI on system clocks. When this feature
is enabled in software, the HPET timer base frequency may change and its new
value needs to be reported to the OS or may need to be adjusted as it will
differ from the default value reported by hardware power up value. This
software routine accomplish this task to ensure that the system timer is
adjusted accordingly by the OS to it accurate.

Signed-off-by: XiaoGang Zheng <[email protected]>
Signed-off-by: Crane Cai <[email protected]>

----------------------------

diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 4353cf5..74a3eb7 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -17,6 +17,7 @@
#include <asm/io_apic.h>
#include <asm/apic.h>
#include <asm/iommu.h>
+#include <asm/hpet.h>

static void __init fix_hypertransport_config(int num, int slot, int func)
{
@@ -95,6 +96,16 @@ static void __init nvidia_bugs(int num, int slot, int func)

}

+static void __init amd_sb700_hpet(int num, int slot, int func)
+{
+ int rev;
+ rev = read_pci_config_byte(num, slot, func, 0x08);
+ if (rev <= 0x3a && rev >= 0x30) {
+ hpet_rework = 1;
+ printk(KERN_INFO "SB700 rev 0x3a under detected!\n");
+ }
+}
+
#define QFLAG_APPLY_ONCE 0x1
#define QFLAG_APPLIED 0x2
#define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
@@ -114,6 +125,8 @@ static struct chipset early_qrk[] __initdata = {
PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+ PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, amd_sb700_hpet },
{}
};

diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index ad2b15a..d940cca 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -23,6 +23,9 @@
* HPET address is set in acpi/boot.c, when an ACPI entry exists
*/
unsigned long hpet_address;
+
+int hpet_rework __initdata = 0;
+
static void __iomem *hpet_virt_address;

unsigned long hpet_readl(unsigned long a)
@@ -369,6 +372,12 @@ int __init hpet_enable(void)
* Read the period and check for a sane value:
*/
hpet_period = hpet_readl(HPET_PERIOD);
+
+ if (hpet_rework) {
+ int timeout = 1000;
+ while (0xffffffff == hpet_readl(HPET_CFG) && timeout-- != 0)
+ ;
+ }
if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
goto out_nohpet;

diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h
index 82f1ac6..2536c21 100644
--- a/include/asm-x86/hpet.h
+++ b/include/asm-x86/hpet.h
@@ -55,6 +55,8 @@
*/
#define HPET_MIN_PERIOD 100000UL

+extern int hpet_rework;
+
/* hpet memory map physical address */
extern unsigned long hpet_address;
extern unsigned long force_hpet_address;