Commit 94db5ad4 authored by Dave Jones's avatar Dave Jones Committed by Dave Jones

[CPUFREQ] Clean up longhaul MSR usage using bitfields.

parent 8e94d032
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <asm/timex.h> #include <asm/timex.h>
#include <asm/io.h> #include <asm/io.h>
#include "longhaul.h"
#define DEBUG #define DEBUG
#ifdef DEBUG #ifdef DEBUG
...@@ -248,7 +250,7 @@ static int clock_ratio[32]; ...@@ -248,7 +250,7 @@ static int clock_ratio[32];
static int eblcr_table[32]; static int eblcr_table[32];
static int voltage_table[32]; static int voltage_table[32];
static unsigned int highest_speed, lowest_speed; /* kHz */ static unsigned int highest_speed, lowest_speed; /* kHz */
static int longhaul; /* version. */ static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table; static struct cpufreq_frequency_table *longhaul_table;
...@@ -273,7 +275,7 @@ static int longhaul_get_cpu_mult (void) ...@@ -273,7 +275,7 @@ static int longhaul_get_cpu_mult (void)
rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
if (longhaul==3) { if (longhaul_version==3) {
if (lo & (1<<27)) if (lo & (1<<27))
invalue+=16; invalue+=16;
} }
...@@ -290,11 +292,10 @@ static int longhaul_get_cpu_mult (void) ...@@ -290,11 +292,10 @@ static int longhaul_get_cpu_mult (void)
static void longhaul_setstate (unsigned int clock_ratio_index) static void longhaul_setstate (unsigned int clock_ratio_index)
{ {
unsigned long lo, hi;
unsigned int bits;
int vidindex, i; int vidindex, i;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
union msr_longhaul longhaul;
if (clock_ratio[clock_ratio_index] == -1) if (clock_ratio[clock_ratio_index] == -1)
return; return;
...@@ -311,36 +312,35 @@ static void longhaul_setstate (unsigned int clock_ratio_index) ...@@ -311,36 +312,35 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
dprintk (KERN_INFO PFX "FSB:%d Mult(x10):%d\n", dprintk (KERN_INFO PFX "FSB:%d Mult(x10):%d\n",
fsb * 100, clock_ratio[clock_ratio_index]); fsb * 100, clock_ratio[clock_ratio_index]);
bits = clock_ratio_index;
/* "bits" contains the bitpattern of the new multiplier. /* "bits" contains the bitpattern of the new multiplier.
we now need to transform it to the desired format. */ we now need to transform it to the desired format. */
switch (longhaul) { switch (longhaul_version) {
case 1: case 1:
rdmsr (MSR_VIA_BCR2, lo, hi); // rdmsr (MSR_VIA_BCR2, lo, hi);
/* Enable software clock multiplier */ /* Enable software clock multiplier */
lo |= (1<<19); // lo |= (1<<19);
/* desired multiplier */ /* desired multiplier */
lo &= ~(1<<23|1<<24|1<<25|1<<26); // lo &= ~(1<<23|1<<24|1<<25|1<<26);
lo |= (bits<<23); // lo |= (bits<<23);
wrmsr (MSR_VIA_BCR2, lo, hi); // wrmsr (MSR_VIA_BCR2, lo, hi);
__hlt(); __hlt();
/* Disable software clock multiplier */ /* Disable software clock multiplier */
rdmsr (MSR_VIA_BCR2, lo, hi); // rdmsr (MSR_VIA_BCR2, lo, hi);
lo &= ~(1<<19); // lo &= ~(1<<19);
wrmsr (MSR_VIA_BCR2, lo, hi); // wrmsr (MSR_VIA_BCR2, lo, hi);
break; break;
case 2: case 2:
rdmsr (MSR_VIA_LONGHAUL, lo, hi); rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
lo &= 0xfff0bf0f; /* reset [19:16,14](bus ratio) and [7:4](rev key) to 0 */ longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
lo |= (bits<<16); longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
lo |= (1<<8); /* EnableSoftBusRatio */ longhaul.bits.EnableSoftBusRatio = 1;
/* We must program the revision key only with values we /* We must program the revision key only with values we
* know about, not blindly copy it from 0:3 */ * know about, not blindly copy it from 0:3 */
lo |= 1; longhaul.bits.RevisionKey = 1;
if (can_scale_voltage) { if (can_scale_voltage) {
/* PB: TODO fix this up */ /* PB: TODO fix this up */
...@@ -357,40 +357,39 @@ static void longhaul_setstate (unsigned int clock_ratio_index) ...@@ -357,40 +357,39 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
dprintk (KERN_INFO PFX "Desired vid index=%d\n", i); dprintk (KERN_INFO PFX "Desired vid index=%d\n", i);
#if 0 #if 0
lo &= 0xfe0fffff;/* reset [24:20](voltage) to 0 */ longhaul.bits.SoftVID = i;
lo |= (i<<20); /* set voltage */ longhaul.bits.EnableSoftVID = 1;
lo |= (1<<9); /* EnableSoftVID */
#endif #endif
} }
/* FIXME: Do voltage and freq seperatly like we do in powernow-k7 */
bad_voltage: bad_voltage:
wrmsr (MSR_VIA_LONGHAUL, lo, hi); wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
__hlt(); __hlt();
rdmsr (MSR_VIA_LONGHAUL, lo, hi); rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
lo &= ~(1<<8); longhaul.bits.EnableSoftBusRatio = 0;
if (can_scale_voltage) if (can_scale_voltage)
lo &= ~(1<<9); longhaul.bits.EnableSoftVID = 0;
lo |= 1; /* Revision Key */ longhaul.bits.RevisionKey = 1;
wrmsr (MSR_VIA_LONGHAUL, lo, hi); wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
break; break;
case 3: case 3:
rdmsr (MSR_VIA_LONGHAUL, lo, hi); rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
lo &= 0xfff0bf0f; /* reset longhaul[19:16,14] to 0 */ longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
lo |= (bits<<16); longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
lo |= (1<<8); /* EnableSoftBusRatio */ longhaul.bits.EnableSoftBusRatio = 1;
/* We must program the revision key only with values we /* We must program the revision key only with values we
* know about, not blindly copy it from 0:3 */ * know about, not blindly copy it from 0:3 */
lo |= 3; /* SoftVID & SoftBSEL */ longhaul.bits.RevisionKey = 3; /* SoftVID & SoftBSEL */
wrmsr (MSR_VIA_LONGHAUL, lo, hi); wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
__hlt(); __hlt();
rdmsr (MSR_VIA_LONGHAUL, lo, hi); rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
lo &= ~(1<<8); longhaul.bits.EnableSoftBusRatio = 0;
lo |= 3; longhaul.bits.RevisionKey = 3;
wrmsr (MSR_VIA_LONGHAUL, lo, hi); wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
break; break;
} }
...@@ -400,14 +399,15 @@ static void longhaul_setstate (unsigned int clock_ratio_index) ...@@ -400,14 +399,15 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
static int __init longhaul_get_ranges (void) static int __init longhaul_get_ranges (void)
{ {
unsigned long lo, hi, invalue; unsigned long invalue;
unsigned int minmult=0, maxmult=0; unsigned int minmult=0, maxmult=0;
unsigned int multipliers[32]= { unsigned int multipliers[32]= {
50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
-1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
unsigned int j, k = 0; unsigned int j, k = 0;
union msr_longhaul longhaul;
switch (longhaul) { switch (longhaul_version) {
case 1: case 1:
/* Ugh, Longhaul v1 didn't have the min/max MSRs. /* Ugh, Longhaul v1 didn't have the min/max MSRs.
Assume min=3.0x & max = whatever we booted at. */ Assume min=3.0x & max = whatever we booted at. */
...@@ -416,17 +416,17 @@ static int __init longhaul_get_ranges (void) ...@@ -416,17 +416,17 @@ static int __init longhaul_get_ranges (void)
break; break;
case 2 ... 3: case 2 ... 3:
rdmsr (MSR_VIA_LONGHAUL, lo, hi); rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
invalue = (hi & (1<<0|1<<1|1<<2|1<<3)); invalue = longhaul.bits.MaxMHzBR;
if (hi & (1<<11)) if (longhaul.bits.MaxMHzBR4)
invalue += 16; invalue += 16;
maxmult=multipliers[invalue]; maxmult=multipliers[invalue];
#if 0 /* This is MaxMhz @ Min Voltage. Ignore for now */ #if 0
invalue = (hi & (1<<16|1<<17|1<<18|1<<19)) >> 16; invalue = longhaul.bits.MinMHzBR;
if (hi & (1<<27)) if (longhaul.bits.MinMHzBR4);
invalue += 16; invalue += 16;
minmult = multipliers[invalue]; minmult = multipliers[invalue];
#else #else
minmult = 30; /* as per spec */ minmult = 30; /* as per spec */
...@@ -460,18 +460,23 @@ static int __init longhaul_get_ranges (void) ...@@ -460,18 +460,23 @@ static int __init longhaul_get_ranges (void)
kfree (longhaul_table); kfree (longhaul_table);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned long hi) static void __init longhaul_setup_voltagescaling(void)
{ {
int revkey; union msr_longhaul longhaul;
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
if (!(longhaul.bits.RevisionID & 1))
return;
minvid = (hi & (1<<20|1<<21|1<<22|1<<23|1<<24)) >> 20; /* 56:52 */ minvid = longhaul.bits.MinimumVID;
maxvid = (hi & (1<<4|1<<5|1<<6|1<<7|1<<8)) >> 4; /* 40:36 */ maxvid = longhaul.bits.MaximumVID;
vrmrev = (lo & (1<<15))>>15; vrmrev = longhaul.bits.VRMRev;
if (minvid == 0 || maxvid == 0) { if (minvid == 0 || maxvid == 0) {
printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
...@@ -499,14 +504,14 @@ static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned lon ...@@ -499,14 +504,14 @@ static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned lon
/* Current voltage isn't readable at first, so we need to /* Current voltage isn't readable at first, so we need to
set it to a known value. The spec says to use maxvid */ set it to a known value. The spec says to use maxvid */
revkey = (lo & 0xf)<<4; /* Rev key. */ longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */
lo |= revkey; /* Reinsert key FIXME: This is bad. */ longhaul.bits.EnableSoftVID = 1;
lo &= 0xfe0fff0f; /* Mask unneeded bits */ longhaul.bits.SoftVID = maxvid;
lo |= (1<<9); /* EnableSoftVID */ wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
lo |= maxvid << 20;
wrmsr (MSR_VIA_LONGHAUL, lo, hi);
minvid = voltage_table[minvid]; minvid = voltage_table[minvid];
maxvid = voltage_table[maxvid]; maxvid = voltage_table[maxvid];
dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n", dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales); maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);
...@@ -524,8 +529,8 @@ static int longhaul_target (struct cpufreq_policy *policy, ...@@ -524,8 +529,8 @@ static int longhaul_target (struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int table_index = 0; unsigned int table_index = 0;
unsigned int new_clock_ratio = 0; unsigned int new_clock_ratio = 0;
if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index)) if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
return -EINVAL; return -EINVAL;
...@@ -544,7 +549,7 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy) ...@@ -544,7 +549,7 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy)
switch (c->x86_model) { switch (c->x86_model) {
case 6: /* VIA C3 Samuel C5A */ case 6: /* VIA C3 Samuel C5A */
longhaul=1; longhaul_version=1;
memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));
memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
break; break;
...@@ -552,12 +557,12 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy) ...@@ -552,12 +557,12 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy)
case 7: /* C5B / C5C */ case 7: /* C5B / C5C */
switch (c->x86_mask) { switch (c->x86_mask) {
case 0: case 0:
longhaul=1; longhaul_version=1;
memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));
memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr)); memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));
break; break;
case 1 ... 15: case 1 ... 15:
longhaul=2; longhaul_version=2;
memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio)); memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio));
memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr)); memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));
break; break;
...@@ -566,21 +571,18 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy) ...@@ -566,21 +571,18 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy)
case 8: /* C5M/C5N */ case 8: /* C5M/C5N */
return -ENODEV; // Waiting on updated docs from VIA before this is usable return -ENODEV; // Waiting on updated docs from VIA before this is usable
longhaul=3; longhaul_version=3;
numscales=32; numscales=32;
memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio)); memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio));
memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr)); memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr));
break; break;
} }
printk (KERN_INFO PFX "VIA CPU detected. Longhaul version %d supported\n", longhaul); printk (KERN_INFO PFX "VIA CPU detected. Longhaul version %d supported\n",
longhaul_version);
if (longhaul==2 || longhaul==3) { if ((longhaul_version==2 || longhaul_version==3) && (dont_scale_voltage==0))
unsigned long lo, hi; longhaul_setup_voltagescaling();
rdmsr (MSR_VIA_LONGHAUL, lo, hi);
if ((lo & (1<<0)) && (dont_scale_voltage==0))
longhaul_setup_voltagescaling (lo, hi);
}
ret = longhaul_get_ranges(); ret = longhaul_get_ranges();
if (ret != 0) if (ret != 0)
......
/*
* longhaul.h
* (C) 2003 Dave Jones.
*
* Licensed under the terms of the GNU GPL License version 2.
*
* VIA-specific information
*/
union msr_longhaul {
struct {
unsigned RevisionID:4, // 3:0
RevisionKey:4, // 7:4
EnableSoftBusRatio:1, // 8
EnableSoftVID:1, // 9
EnableSoftBSEL:1, // 10
Reserved:3, // 11:13
SoftBusRatio4:1, // 14
VRMRev:1, // 15
SoftBusRatio:4, // 19:16
SoftVID:5, // 24:20
Reserved2:3, // 27:25
SoftBSEL:2, // 29:28
Reserved3:2, // 31:30
MaxMHzBR:4, // 35:32
MaximumVID:5, // 40:36
MaxMHzFSB:2, // 42:41
MaxMHzBR4:1, // 43
Reserved4:4, // 47:44
MinMHzBR:4, // 51:48
MinimumVID:5, // 56:52
MinMHzFSB:2, // 58:57
MinMHzBR4:1, // 59
Reserved5:4; // 63:60
} bits;
unsigned long long val;
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment