#define CPU_EZRA 3
#define CPU_EZRA_T 4
#define CPU_NEHEMIAH 5
+#define CPU_NEHEMIAH_C 6
/* Flags */
#define USE_ACPI_C3 (1 << 1)
#define USE_NORTHBRIDGE (1 << 2)
+#define USE_VT8235 (1 << 3)
static int cpu_model;
static unsigned int numscales=16;
#define ROUNDING 0xf
-static int _guess(int guess, int mult)
-{
- int target;
-
- target = ((mult/10)*guess);
- if (mult%10 != 0)
- target += (guess/2);
- target += ROUNDING/2;
- target &= ~ROUNDING;
- return target;
-}
-
-
static int guess_fsb(int mult)
{
- int speed = (cpu_khz/1000);
+ int speed = cpu_khz / 1000;
int i;
- int speeds[] = { 66, 100, 133, 200 };
-
- speed += ROUNDING/2;
- speed &= ~ROUNDING;
-
- for (i=0; i<4; i++) {
- if (_guess(speeds[i], mult) == speed)
- return speeds[i];
+ int speeds[] = { 666, 1000, 1333, 2000 };
+ int f_max, f_min;
+
+ for (i = 0; i < 4; i++) {
+ f_max = ((speeds[i] * mult) + 50) / 100;
+ f_max += (ROUNDING / 2);
+ f_min = f_max - ROUNDING;
+ if ((speed <= f_max) && (speed >= f_min))
+ return speeds[i] / 10;
}
return 0;
}
static int __init longhaul_get_ranges(void)
{
- unsigned long invalue;
- unsigned int ezra_t_multipliers[32]= {
- 90, 30, 40, 100, 55, 35, 45, 95,
- 50, 70, 80, 60, 120, 75, 85, 65,
- -1, 110, 120, -1, 135, 115, 125, 105,
- 130, 150, 160, 140, -1, 155, -1, 145 };
unsigned int j, k = 0;
- union msr_longhaul longhaul;
- int mult = 0;
+ int mult;
- switch (longhaul_version) {
- case TYPE_LONGHAUL_V1:
- case TYPE_LONGHAUL_V2:
- /* Ugh, Longhaul v1 didn't have the min/max MSRs.
- Assume min=3.0x & max = whatever we booted at. */
+ /* Get current frequency */
+ mult = longhaul_get_cpu_mult();
+ if (mult == -1) {
+ printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n");
+ return -EINVAL;
+ }
+ fsb = guess_fsb(mult);
+ if (fsb == 0) {
+ printk(KERN_INFO PFX "Invalid (reserved) FSB!\n");
+ return -EINVAL;
+ }
+ /* Get max multiplier - as we always did.
+ * Longhaul MSR is usefull only when voltage scaling is enabled.
+ * C3 is booting at max anyway. */
+ maxmult = mult;
+ /* Get min multiplier */
+ switch (cpu_model) {
+ case CPU_NEHEMIAH:
+ minmult = 50;
+ break;
+ case CPU_NEHEMIAH_C:
+ minmult = 40;
+ break;
+ default:
minmult = 30;
- maxmult = mult = longhaul_get_cpu_mult();
break;
-
- case TYPE_POWERSAVER:
- /* Ezra-T */
- if (cpu_model==CPU_EZRA_T) {
- minmult = 30;
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
- invalue = longhaul.bits.MaxMHzBR;
- if (longhaul.bits.MaxMHzBR4)
- invalue += 16;
- maxmult = mult = ezra_t_multipliers[invalue];
- break;
- }
-
- /* Nehemiah */
- if (cpu_model==CPU_NEHEMIAH) {
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-
- /*
- * TODO: This code works, but raises a lot of questions.
- * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.
- * We get around this by using a hardcoded multiplier of 4.0x
- * for the minimimum speed, and the speed we booted up at for the max.
- * This is done in longhaul_get_cpu_mult() by reading the EBLCR register.
- * - According to some VIA documentation EBLCR is only
- * in pre-Nehemiah C3s. How this still works is a mystery.
- * We're possibly using something undocumented and unsupported,
- * But it works, so we don't grumble.
- */
- minmult=40;
- maxmult = mult = longhaul_get_cpu_mult();
- break;
- }
}
- fsb = guess_fsb(mult);
dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
minmult/10, minmult%10, maxmult/10, maxmult%10);
- if (fsb == 0) {
- printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
- return -EINVAL;
- }
-
highest_speed = calc_speed(maxmult);
lowest_speed = calc_speed(minmult);
dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb,
if (dev != NULL) {
/* Enable access to port 0x22 */
pci_read_config_byte(dev, reg, &pci_cmd);
- if ( !(pci_cmd & 1<<7) ) {
+ if (!(pci_cmd & 1<<7)) {
pci_cmd |= 1<<7;
pci_write_config_byte(dev, reg, pci_cmd);
+ pci_read_config_byte(dev, reg, &pci_cmd);
+ if (!(pci_cmd & 1<<7)) {
+ printk(KERN_ERR PFX
+ "Can't enable access to port 0x22.\n");
+ return 0;
+ }
}
return 1;
}
return 0;
}
+static int longhaul_setup_vt8235(void)
+{
+ struct pci_dev *dev;
+ u8 pci_cmd;
+
+ /* Find VT8235 southbridge */
+ dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
+ if (dev != NULL) {
+ /* Set transition time to max */
+ pci_read_config_byte(dev, 0xec, &pci_cmd);
+ pci_cmd &= ~(1 << 2);
+ pci_write_config_byte(dev, 0xec, pci_cmd);
+ pci_read_config_byte(dev, 0xe4, &pci_cmd);
+ pci_cmd &= ~(1 << 7);
+ pci_write_config_byte(dev, 0xe4, pci_cmd);
+ pci_read_config_byte(dev, 0xe5, &pci_cmd);
+ pci_cmd |= 1 << 7;
+ pci_write_config_byte(dev, 0xe5, pci_cmd);
+ return 1;
+ }
+ return 0;
+}
+
static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
char *cpuname=NULL;
int ret;
+ int vt8235_present;
/* Check what we have on this motherboard */
switch (c->x86_model) {
break;
case 9:
- cpu_model = CPU_NEHEMIAH;
longhaul_version = TYPE_POWERSAVER;
- numscales=32;
+ numscales = 32;
+ memcpy(clock_ratio,
+ nehemiah_clock_ratio,
+ sizeof(nehemiah_clock_ratio));
+ memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
switch (c->x86_mask) {
case 0 ... 1:
+ cpu_model = CPU_NEHEMIAH;
cpuname = "C3 'Nehemiah A' [C5N]";
- memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio));
- memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr));
break;
case 2 ... 4:
+ cpu_model = CPU_NEHEMIAH;
cpuname = "C3 'Nehemiah B' [C5N]";
- memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio));
- memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr));
break;
case 5 ... 15:
+ cpu_model = CPU_NEHEMIAH_C;
cpuname = "C3 'Nehemiah C' [C5N]";
- memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio));
- memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr));
break;
}
break;
break;
};
+ /* Doesn't hurt */
+ vt8235_present = longhaul_setup_vt8235();
+
/* Find ACPI data for processor */
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
- &longhaul_walk_callback, NULL, (void *)&pr);
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, &longhaul_walk_callback,
+ NULL, (void *)&pr);
/* Check ACPI support for C3 state */
- if ((pr != NULL) && (longhaul_version == TYPE_POWERSAVER)) {
+ if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {
cx = &pr->power.states[ACPI_STATE_C3];
if (cx->address > 0 && cx->latency <= 1000) {
longhaul_flags |= USE_ACPI_C3;
longhaul_flags |= USE_NORTHBRIDGE;
goto print_support_type;
}
-
- /* No ACPI C3 or we can't use it */
+ /* Use VT8235 southbridge if present */
+ if (longhaul_version == TYPE_POWERSAVER && vt8235_present) {
+ longhaul_flags |= USE_VT8235;
+ goto print_support_type;
+ }
/* Check ACPI support for bus master arbiter disable */
if ((pr == NULL) || !(pr->flags.bm_control)) {
printk(KERN_ERR PFX
}
print_support_type:
- if (!(longhaul_flags & USE_NORTHBRIDGE)) {
- printk (KERN_INFO PFX "Using ACPI support.\n");
- } else {
+ if (longhaul_flags & USE_NORTHBRIDGE)
printk (KERN_INFO PFX "Using northbridge support.\n");
- }
+ else if (longhaul_flags & USE_VT8235)
+ printk (KERN_INFO PFX "Using VT8235 support.\n");
+ else
+ printk (KERN_INFO PFX "Using ACPI support.\n");
ret = longhaul_get_ranges();
if (ret != 0)
return ret;
- if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&
- (scale_voltage != 0))
+ if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
longhaul_setup_voltagescaling();
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;