* split model_centaur into model_c3 and model_c7
* simplify and improve cpuid table
* add speedstep support for VIA C7 based CPUs

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>

Index: src/cpu/via/model_c7/Config.lb
===================================================================
--- src/cpu/via/model_c7/Config.lb	(revision 0)
+++ src/cpu/via/model_c7/Config.lb	(revision 76)
@@ -0,0 +1,9 @@
+dir /cpu/x86/tsc
+dir /cpu/x86/mtrr
+dir /cpu/x86/fpu
+dir /cpu/x86/mmx
+dir /cpu/x86/sse
+dir /cpu/x86/lapic
+dir /cpu/x86/cache
+dir /cpu/intel/microcode
+driver model_c7_init.o
Index: src/cpu/via/model_c7/model_c7_init.c
===================================================================
--- src/cpu/via/model_c7/model_c7_init.c	(revision 0)
+++ src/cpu/via/model_c7/model_c7_init.c	(revision 87)
@@ -0,0 +1,227 @@
+/*
+ * This file is part of the coreboot project.
+ * 
+ * (C) 2007-2008 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <device/device.h>
+#include <console/console.h>
+#include <delay.h>
+#include <stdlib.h>
+
+#include <cpu/cpu.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+
+#define MSR_IA32_PERF_STATUS	0x00000198
+#define MSR_IA32_PERF_CTL	0x00000199
+#define MSR_IA32_MISC_ENABLE	0x000001a0
+
+static int c7a_speed_translation[] = {
+//      LFM     HFM             
+	0x0409, 0x0f13,		// 400MHz, 844mV --> 1500MHz, 1.004V    C7-M
+	0x0409, 0x1018,		// 400MHz, 844mV --> 1600MHz, 1.084V
+	0x0409, 0x0c18,		// 533MHz, 844mV --> 1600MHz, 1.084V
+	0x0409, 0x121c,		// 400MHz, 844mV --> 1800MHz, 1.148V
+	0x0409, 0x0e1c,		// 533MHz, 844mV --> 1860MHz, 1.148V
+	0x0409, 0x141f,		// 400MHz, 844mV --> 2000MHz, 1.196V
+	0x0409, 0x0f1f,		// 533MHz, 844mV --> 2000MHz, 1.196V
+	0x0406, 0x0a06,		// 400MHz, 796mV --> 1000MHz, 796mV     C7-M ULV
+	0x0406, 0x0a09,		// 400MHz, 796mV --> 1000MHz, 844mV
+	0x0406, 0x0c09,		// 400MHz, 796mV --> 1200MHz, 844mV
+	0x0406, 0x0f10,		// 400MHz, 796mV --> 1500MHz, 956mV
+};
+
+static int c7d_speed_translation[] = {
+//      LFM     HFM             
+	0x0409, 0x1018,		// 400MHz, 844mV --> 1600MHz, 1.084V    C7-M
+	0x0409, 0x121f,		// 400MHz, 844mV --> 1800MHz, 1.196V
+	0x0809, 0x121f,		// 800MHz, 844mV --> 1800MHz, 1.196V
+	0x0409, 0x141f,		// 400MHz, 844mV --> 2000MHz, 1.196V
+	0x0809, 0x141f,		// 800MHz, 844mV --> 2000MHz, 1.196V
+	0x0406, 0x0806,		// 400MHz, 796mV --> 800MHz, 796mV      C7-M ULV
+	0x0406, 0x0a06,		// 400MHz, 796mV --> 1000MHz, 796mV
+	0x0406, 0x0c09,		// 400MHz, 796mV --> 1200MHz, 844mV
+	0x0806, 0x0c09,		// 800MHz, 796mV --> 1200MHz, 844mV
+	0x0406, 0x0f10,		// 400MHz, 796mV --> 1500MHz, 956mV
+	0x0806, 0x1010,		// 800MHz, 796mV --> 1600MHz, 956mV
+};
+
+static void set_c7_speed(int model) {
+	int cnt, current, new, i;
+	msr_t msr;
+	printk_debug("Enabling improved C7 clock and voltage.\n");
+
+	// Enable Speedstep
+	msr = rdmsr(MSR_IA32_MISC_ENABLE);
+	msr.lo |= (1 << 16);
+	wrmsr(MSR_IA32_MISC_ENABLE, msr);
+
+	msr = rdmsr(MSR_IA32_PERF_STATUS);
+
+	printk_info("Voltage: %dmV (min %dmV; max %dmV)\n",
+		    ((int)(msr.lo & 0xff) * 16 + 700),
+		    ((int)((msr.hi >> 16) & 0xff) * 16 + 700),
+		    ((int)(msr.hi & 0xff) * 16 + 700));
+
+	printk_info("CPU multiplier: %dx (min %dx; max %dx)\n",
+		    (int)((msr.lo >> 8) & 0xff),
+		    (int)((msr.hi >> 24) & 0xff), (int)((msr.hi >> 8) & 0xff));
+
+	printk_debug(" msr.lo = %x\n", msr.lo);
+
+	/* Wait while CPU is busy */
+	cnt = 0;
+	while (msr.lo & ((1 << 16) | (1 << 17))) {
+		udelay(16);
+		msr = rdmsr(MSR_IA32_PERF_STATUS);
+		cnt++;
+		if (cnt > 128) {
+			printk_warning("Could not update multiplier and voltage.\n");
+			return;
+		}
+	}
+
+	current = msr.lo & 0xffff;
+
+	// Start out with no change.
+	new = current;
+	switch (model) {
+	case 10:		// model A
+		for (i = 0; i < ARRAY_SIZE(c7a_speed_translation); i += 2) {
+			if ((c7a_speed_translation[i] == current) &&
+			    ((c7a_speed_translation[i + 1] & 0xff00) ==
+			     (msr.hi & 0xff00))) {
+				new = c7a_speed_translation[i + 1];
+			}
+		}
+		break;
+	case 13:		// model D
+		for (i = 0; i < ARRAY_SIZE(c7d_speed_translation); i += 2) {
+			if ((c7d_speed_translation[i] == current) &&
+			    ((c7d_speed_translation[i + 1] & 0xff00) ==
+			     (msr.hi & 0xff00))) {
+				new = c7d_speed_translation[i + 1];
+			}
+		}
+		break;
+	default:
+		print_info("CPU type not known, multiplier unchanged.\n");
+	}
+
+	msr.lo = new;
+	msr.hi = 0;
+	printk_debug(" new msr.lo = %x\n", msr.lo);
+
+	wrmsr(MSR_IA32_PERF_CTL, msr);
+
+	/* Wait until the power transition ends */
+	cnt = 0;
+	do {
+		udelay(16);
+		msr = rdmsr(MSR_IA32_PERF_STATUS);
+		cnt++;
+		if (cnt > 128) {
+			printk_warning("Error while updating multiplier and voltage\n");
+			break;
+		}
+	} while (msr.lo & ((1 << 16) | (1 << 17)));
+
+	printk_info("Current voltage: %dmV\n", ((int)(msr.lo & 0xff) * 16 + 700));
+	printk_info("Current CPU multiplier: %dx\n", (int)((msr.lo >> 8) & 0xff));
+}
+
+static void model_c7_init(device_t dev)
+{
+	u8 brand;
+	struct cpuinfo_x86 c;
+	msr_t msr;
+
+	get_fms(&c, dev->device);
+
+	printk_info("Detected VIA ");
+
+	switch (c.x86_model) {
+	case 10:
+		msr = rdmsr(0x1153);
+		brand = (((msr.lo >> 2) ^ msr.lo) >> 18) & 3;
+		printk_info("Model A ");
+		break;
+	case 13:
+		msr = rdmsr(0x1154);
+		brand = (((msr.lo >> 4) ^ (msr.lo >> 2))) & 0x000000ff;
+		printk_info("Model D ");
+		break;
+	default:
+		printk_info("Model Unknown ");
+		brand = 0xff;
+	}
+
+	switch (brand) {
+	case 0:
+		printk_info("C7-M\n");
+		break;
+	case 1:
+		printk_info("C7\n");
+		break;
+	case 2:
+		printk_info("Eden\n");
+		break;
+	case 3:
+		printk_info("C7-D\n");
+		break;
+	default:
+		printk_info("%02x (please report)\n", brand);
+	}
+
+	/* Gear up */
+	set_c7_speed(c.x86_model);
+
+	/* Turn on cache */
+	x86_enable_cache();
+
+	/* Set up Memory Type Range Registers */
+	x86_setup_mtrrs(36);
+	x86_mtrr_check();
+
+	/* Enable the local cpu apics */
+	setup_lapic();
+};
+
+static struct device_operations cpu_dev_ops = {
+	.init = model_c7_init,
+};
+
+/* Look in arch/i386/lib/cpu.c:cpu_initialize. If there is no CPU with an exact
+ * ID, the cpu mask (stepping) is masked out and the check is repeated. This
+ * allows us to keep the table significantly smaller.
+ */
+
+static struct cpu_device_id cpu_table[] = {
+	{X86_VENDOR_CENTAUR, 0x06A0},	// VIA C7 Esther
+	{X86_VENDOR_CENTAUR, 0x06D0},	// VIA C7-M
+	{0, 0},
+};
+
+static const struct cpu_driver driver __cpu_driver = {
+	.ops = &cpu_dev_ops,
+	.id_table = cpu_table,
+};
Index: src/cpu/via/model_c3/Config.lb
===================================================================
--- src/cpu/via/model_c3/Config.lb	(revision 0)
+++ src/cpu/via/model_c3/Config.lb	(revision 76)
@@ -0,0 +1,9 @@
+dir /cpu/x86/tsc
+dir /cpu/x86/mtrr
+dir /cpu/x86/fpu
+dir /cpu/x86/mmx
+dir /cpu/x86/sse
+dir /cpu/x86/lapic
+dir /cpu/x86/cache
+dir /cpu/intel/microcode
+driver model_c3_init.o
Index: src/cpu/via/model_c3/model_c3_init.c
===================================================================
--- src/cpu/via/model_c3/model_c3_init.c	(revision 0)
+++ src/cpu/via/model_c3/model_c3_init.c	(revision 76)
@@ -0,0 +1,39 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/intel/microcode.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+
+static void model_c3_init(device_t dev)
+{
+	/* Turn on caching if we haven't already */
+	x86_enable_cache();
+	x86_setup_mtrrs(36);
+	x86_mtrr_check();
+
+	/* Enable the local cpu apics */
+	setup_lapic();
+};
+
+static struct device_operations cpu_dev_ops = {
+	.init     = model_c3_init,
+};
+
+static struct cpu_device_id cpu_table[] = {
+	{ X86_VENDOR_CENTAUR, 0x0670 },		// VIA C3 Samual 2 + Ezra
+	{ X86_VENDOR_CENTAUR, 0x0680 },		// VIA C3 Ezra-T
+	{ X86_VENDOR_CENTAUR, 0x0690 },		// VIA C3 Nehemiah
+	{ 0, 0 },
+};
+
+static const struct cpu_driver driver __cpu_driver = {
+	.ops      = &cpu_dev_ops,
+	.id_table = cpu_table,
+};
Index: src/cpu/via/model_centaur/Config.lb
===================================================================
--- src/cpu/via/model_centaur/Config.lb	(revision 60)
+++ src/cpu/via/model_centaur/Config.lb	(working copy)
@@ -1,8 +0,0 @@
-dir /cpu/x86/tsc
-dir /cpu/x86/mtrr
-dir /cpu/x86/fpu
-dir /cpu/x86/mmx
-dir /cpu/x86/sse
-dir /cpu/x86/lapic
-dir /cpu/x86/cache
-driver model_centaur_init.o
Index: src/cpu/via/model_centaur/model_centaur_init.c
===================================================================
--- src/cpu/via/model_centaur/model_centaur_init.c	(revision 60)
+++ src/cpu/via/model_centaur/model_centaur_init.c	(working copy)
@@ -1,66 +0,0 @@
-#include <console/console.h>
-#include <device/device.h>
-#include <device/device.h>
-#include <device/pci.h>
-#include <string.h>
-#include <cpu/cpu.h>
-#include <cpu/x86/mtrr.h>
-#include <cpu/x86/msr.h>
-#include <cpu/x86/lapic.h>
-#include <cpu/x86/cache.h>
-#include <cpu/x86/mtrr.h>
-
-static void model_centaur_init(device_t dev)
-{
-	/* Turn on caching if we haven't already */
-	x86_enable_cache();
-	x86_setup_mtrrs(36);
-	x86_mtrr_check();
-
-	/* Enable the local cpu apics */
-	setup_lapic();
-};
-
-static struct device_operations cpu_dev_ops = {
-	.init     = model_centaur_init,
-};
-
-#warning "FIXME - need correct cpu id here for VIA C3"
-static struct cpu_device_id cpu_table[] = {
-	{ X86_VENDOR_CENTAUR, 0x0670 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0671 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0672 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0673 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0674 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0675 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0676 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0677 },		// VIA C3 Samual 2
-	{ X86_VENDOR_CENTAUR, 0x0678 },		// VIA C3 Ezra
-	{ X86_VENDOR_CENTAUR, 0x0680 },		// VIA C3 Ezra-T
-	{ X86_VENDOR_CENTAUR, 0x0691 },		// VIA C3 Nehemiah
-	{ X86_VENDOR_CENTAUR, 0x0692 },		// VIA C3 Nehemiah
-	{ X86_VENDOR_CENTAUR, 0x0693 }, 	// VIA C3 Nehemiah  
-	{ X86_VENDOR_CENTAUR, 0x0694 },		// VIA C3 Nehemiah
-	{ X86_VENDOR_CENTAUR, 0x0695 }, 	// VIA C3 Nehemiah  
-	{ X86_VENDOR_CENTAUR, 0x0696 }, 	// VIA C3 Nehemiah  
-	{ X86_VENDOR_CENTAUR, 0x0697 }, 	// VIA C3 Nehemiah  
-	{ X86_VENDOR_CENTAUR, 0x0698 },		// VIA C3 Nehemiah
-	{ X86_VENDOR_CENTAUR, 0x0699 },		// VIA C3 Nehemiah
-	{ X86_VENDOR_CENTAUR, 0x069A },		// VIA C3 Nehemiah
-	/* Some of these may not actually exist */
-	{ X86_VENDOR_CENTAUR, 0x06A0 },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06A8 },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06A9 },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06AA },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06AB },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06AC },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06AD },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06AE },		// VIA C7 Esther
-	{ X86_VENDOR_CENTAUR, 0x06AF },		// VIA C7 Esther
-	{ 0, 0 },
-};
-
-static const struct cpu_driver driver __cpu_driver = {
-	.ops      = &cpu_dev_ops,
-	.id_table = cpu_table,
-};
Index: src/mainboard/via/epia-m/Config.lb
===================================================================
--- src/mainboard/via/epia-m/Config.lb	(revision 60)
+++ src/mainboard/via/epia-m/Config.lb	(working copy)
@@ -134,7 +134,7 @@
 chip northbridge/via/vt8623
 
 	device apic_cluster 0 on
-		chip cpu/via/model_centaur
+		chip cpu/via/model_c3
 			device apic 0 on  end 
 		end
 	end
Index: src/mainboard/via/epia/Config.lb
===================================================================
--- src/mainboard/via/epia/Config.lb	(revision 60)
+++ src/mainboard/via/epia/Config.lb	(working copy)
@@ -184,7 +184,7 @@
 	end
 
         device apic_cluster 0 on
-                chip cpu/via/model_centaur 
+                chip cpu/via/model_c3
                         device apic 0 on end
                 end
         end
