aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafał Bilski <rafalbilski@interia.pl>2006-08-15 19:07:33 -0400
committerDave Jones <davej@redhat.com>2006-09-05 17:28:42 -0400
commitdb44aaf3a2f599163c53ce96658aca688b3466f0 (patch)
treead6bbd01851d911e0641256f5d10531504a85ee4
parent23e735bc7b0e1d614656881794257b4224efda3a (diff)
[CPUFREQ] Longhaul - Add voltage scaling to driver
Rename option "dont_scale_voltage" to "scale_voltage" because don't will be default. Use "pos" for calculating voltage. In this way driver don't need to know mV value or low level value. Simply min U is one pos and max U is second pos. All pos between these two are used. Assume that min U is for min f and max U for max f. For frequency between min and max calculate pos based on difference between current frequency and min f. Values in mobile VRM table changed to values from C3-M datasheet. Signed-off-by: Rafał Bilski <rafalbilski@interia.pl> Signed-off-by: Dave Jones <davej@redhat.com>
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c97
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.h48
2 files changed, 94 insertions, 51 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 43bbf948d45d..f5cc9f5c9bab 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -53,19 +53,26 @@
53#define CPU_NEHEMIAH 5 53#define CPU_NEHEMIAH 5
54 54
55static int cpu_model; 55static int cpu_model;
56static unsigned int numscales=16, numvscales; 56static unsigned int numscales=16;
57static unsigned int fsb; 57static unsigned int fsb;
58static int minvid, maxvid; 58
59static struct mV_pos *vrm_mV_table;
60static unsigned char *mV_vrm_table;
61struct f_msr {
62 unsigned char vrm;
63};
64static struct f_msr f_msr_table[32];
65
66static unsigned int highest_speed, lowest_speed; /* kHz */
59static unsigned int minmult, maxmult; 67static unsigned int minmult, maxmult;
60static int can_scale_voltage; 68static int can_scale_voltage;
61static int vrmrev;
62static struct acpi_processor *pr = NULL; 69static struct acpi_processor *pr = NULL;
63static struct acpi_processor_cx *cx = NULL; 70static struct acpi_processor_cx *cx = NULL;
64static int port22_en = 0; 71static int port22_en;
65 72
66/* Module parameters */ 73/* Module parameters */
67static int dont_scale_voltage; 74static int scale_voltage;
68static int ignore_latency = 0; 75static int ignore_latency;
69 76
70#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) 77#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
71 78
@@ -73,7 +80,6 @@ static int ignore_latency = 0;
73/* Clock ratios multiplied by 10 */ 80/* Clock ratios multiplied by 10 */
74static int clock_ratio[32]; 81static int clock_ratio[32];
75static int eblcr_table[32]; 82static int eblcr_table[32];
76static int voltage_table[32];
77static unsigned int highest_speed, lowest_speed; /* kHz */ 83static unsigned int highest_speed, lowest_speed; /* kHz */
78static int longhaul_version; 84static int longhaul_version;
79static struct cpufreq_frequency_table *longhaul_table; 85static struct cpufreq_frequency_table *longhaul_table;
@@ -163,6 +169,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
163 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; 169 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
164 longhaul.bits.EnableSoftBusRatio = 1; 170 longhaul.bits.EnableSoftBusRatio = 1;
165 171
172 if (can_scale_voltage) {
173 longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
174 longhaul.bits.EnableSoftVID = 1;
175 }
176
166 /* Sync to timer tick */ 177 /* Sync to timer tick */
167 safe_halt(); 178 safe_halt();
168 /* Change frequency on next halt or sleep */ 179 /* Change frequency on next halt or sleep */
@@ -454,53 +465,57 @@ static int __init longhaul_get_ranges(void)
454static void __init longhaul_setup_voltagescaling(void) 465static void __init longhaul_setup_voltagescaling(void)
455{ 466{
456 union msr_longhaul longhaul; 467 union msr_longhaul longhaul;
468 struct mV_pos minvid, maxvid;
469 unsigned int j, speed, pos, kHz_step, numvscales;
457 470
458 rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); 471 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
459 472 if (!(longhaul.bits.RevisionID & 1)) {
460 if (!(longhaul.bits.RevisionID & 1)) 473 printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");
461 return; 474 return;
475 }
476
477 if (!longhaul.bits.VRMRev) {
478 printk (KERN_INFO PFX "VRM 8.5\n");
479 vrm_mV_table = &vrm85_mV[0];
480 mV_vrm_table = &mV_vrm85[0];
481 } else {
482 printk (KERN_INFO PFX "Mobile VRM\n");
483 vrm_mV_table = &mobilevrm_mV[0];
484 mV_vrm_table = &mV_mobilevrm[0];
485 }
462 486
463 minvid = longhaul.bits.MinimumVID; 487 minvid = vrm_mV_table[longhaul.bits.MinimumVID];
464 maxvid = longhaul.bits.MaximumVID; 488 maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
465 vrmrev = longhaul.bits.VRMRev; 489 numvscales = maxvid.pos - minvid.pos + 1;
490 kHz_step = (highest_speed - lowest_speed) / numvscales;
466 491
467 if (minvid == 0 || maxvid == 0) { 492 if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
468 printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " 493 printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
469 "Voltage scaling disabled.\n", 494 "Voltage scaling disabled.\n",
470 minvid/1000, minvid%1000, maxvid/1000, maxvid%1000); 495 minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
471 return; 496 return;
472 } 497 }
473 498
474 if (minvid == maxvid) { 499 if (minvid.mV == maxvid.mV) {
475 printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are " 500 printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
476 "both %d.%03d. Voltage scaling disabled\n", 501 "both %d.%03d. Voltage scaling disabled\n",
477 maxvid/1000, maxvid%1000); 502 maxvid.mV/1000, maxvid.mV%1000);
478 return; 503 return;
479 } 504 }
480 505
481 if (vrmrev==0) { 506 printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n",
482 dprintk ("VRM 8.5\n"); 507 maxvid.mV/1000, maxvid.mV%1000,
483 memcpy (voltage_table, vrm85scales, sizeof(voltage_table)); 508 minvid.mV/1000, minvid.mV%1000,
484 numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25; 509 numvscales);
485 } else { 510
486 dprintk ("Mobile VRM\n"); 511 j = 0;
487 memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table)); 512 while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
488 numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5; 513 speed = longhaul_table[j].frequency;
514 pos = (speed - lowest_speed) / kHz_step + minvid.pos;
515 f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
516 j++;
489 } 517 }
490 518
491 /* Current voltage isn't readable at first, so we need to
492 set it to a known value. The spec says to use maxvid */
493 longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */
494 longhaul.bits.EnableSoftVID = 1;
495 longhaul.bits.SoftVID = maxvid;
496 wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
497
498 minvid = voltage_table[minvid];
499 maxvid = voltage_table[maxvid];
500
501 dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
502 maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);
503
504 can_scale_voltage = 1; 519 can_scale_voltage = 1;
505} 520}
506 521
@@ -685,7 +700,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
685 return ret; 700 return ret;
686 701
687 if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && 702 if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&
688 (dont_scale_voltage==0)) 703 (scale_voltage != 0))
689 longhaul_setup_voltagescaling(); 704 longhaul_setup_voltagescaling();
690 705
691 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 706 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
@@ -773,8 +788,8 @@ static void __exit longhaul_exit(void)
773 kfree(longhaul_table); 788 kfree(longhaul_table);
774} 789}
775 790
776module_param (dont_scale_voltage, int, 0644); 791module_param (scale_voltage, int, 0644);
777MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor"); 792MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
778module_param(ignore_latency, int, 0644); 793module_param(ignore_latency, int, 0644);
779MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test"); 794MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test");
780 795
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/i386/kernel/cpu/cpufreq/longhaul.h
index d3a95d77ee85..bc4682aad69b 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.h
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.h
@@ -450,17 +450,45 @@ static int __initdata nehemiah_c_eblcr[32] = {
450 * Voltage scales. Div/Mod by 1000 to get actual voltage. 450 * Voltage scales. Div/Mod by 1000 to get actual voltage.
451 * Which scale to use depends on the VRM type in use. 451 * Which scale to use depends on the VRM type in use.
452 */ 452 */
453static int __initdata vrm85scales[32] = { 453
454 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, 454struct mV_pos {
455 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300, 455 unsigned short mV;
456 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725, 456 unsigned short pos;
457 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325, 457};
458
459static struct mV_pos __initdata vrm85_mV[32] = {
460 {1250, 8}, {1200, 6}, {1150, 4}, {1100, 2},
461 {1050, 0}, {1800, 30}, {1750, 28}, {1700, 26},
462 {1650, 24}, {1600, 22}, {1550, 20}, {1500, 18},
463 {1450, 16}, {1400, 14}, {1350, 12}, {1300, 10},
464 {1275, 9}, {1225, 7}, {1175, 5}, {1125, 3},
465 {1075, 1}, {1825, 31}, {1775, 29}, {1725, 27},
466 {1675, 25}, {1625, 23}, {1575, 21}, {1525, 19},
467 {1475, 17}, {1425, 15}, {1375, 13}, {1325, 11}
468};
469
470static unsigned char __initdata mV_vrm85[32] = {
471 0x04, 0x14, 0x03, 0x13, 0x02, 0x12, 0x01, 0x11,
472 0x00, 0x10, 0x0f, 0x1f, 0x0e, 0x1e, 0x0d, 0x1d,
473 0x0c, 0x1c, 0x0b, 0x1b, 0x0a, 0x1a, 0x09, 0x19,
474 0x08, 0x18, 0x07, 0x17, 0x06, 0x16, 0x05, 0x15
475};
476
477static struct mV_pos __initdata mobilevrm_mV[32] = {
478 {1750, 31}, {1700, 30}, {1650, 29}, {1600, 28},
479 {1550, 27}, {1500, 26}, {1450, 25}, {1400, 24},
480 {1350, 23}, {1300, 22}, {1250, 21}, {1200, 20},
481 {1150, 19}, {1100, 18}, {1050, 17}, {1000, 16},
482 {975, 15}, {950, 14}, {925, 13}, {900, 12},
483 {875, 11}, {850, 10}, {825, 9}, {800, 8},
484 {775, 7}, {750, 6}, {725, 5}, {700, 4},
485 {675, 3}, {650, 2}, {625, 1}, {600, 0}
458}; 486};
459 487
460static int __initdata mobilevrmscales[32] = { 488static unsigned char __initdata mV_mobilevrm[32] = {
461 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 489 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
462 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1, 490 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
463 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 491 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
464 1075, 1050, 1025, 1000, 975, 950, 925, -1, 492 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
465}; 493};
466 494