diff options
author | Rafał Bilski <rafalbilski@interia.pl> | 2006-08-15 19:07:33 -0400 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-09-05 17:28:42 -0400 |
commit | db44aaf3a2f599163c53ce96658aca688b3466f0 (patch) | |
tree | ad6bbd01851d911e0641256f5d10531504a85ee4 /arch/i386/kernel/cpu | |
parent | 23e735bc7b0e1d614656881794257b4224efda3a (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>
Diffstat (limited to 'arch/i386/kernel/cpu')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 97 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.h | 48 |
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 | ||
55 | static int cpu_model; | 55 | static int cpu_model; |
56 | static unsigned int numscales=16, numvscales; | 56 | static unsigned int numscales=16; |
57 | static unsigned int fsb; | 57 | static unsigned int fsb; |
58 | static int minvid, maxvid; | 58 | |
59 | static struct mV_pos *vrm_mV_table; | ||
60 | static unsigned char *mV_vrm_table; | ||
61 | struct f_msr { | ||
62 | unsigned char vrm; | ||
63 | }; | ||
64 | static struct f_msr f_msr_table[32]; | ||
65 | |||
66 | static unsigned int highest_speed, lowest_speed; /* kHz */ | ||
59 | static unsigned int minmult, maxmult; | 67 | static unsigned int minmult, maxmult; |
60 | static int can_scale_voltage; | 68 | static int can_scale_voltage; |
61 | static int vrmrev; | ||
62 | static struct acpi_processor *pr = NULL; | 69 | static struct acpi_processor *pr = NULL; |
63 | static struct acpi_processor_cx *cx = NULL; | 70 | static struct acpi_processor_cx *cx = NULL; |
64 | static int port22_en = 0; | 71 | static int port22_en; |
65 | 72 | ||
66 | /* Module parameters */ | 73 | /* Module parameters */ |
67 | static int dont_scale_voltage; | 74 | static int scale_voltage; |
68 | static int ignore_latency = 0; | 75 | static 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 */ |
74 | static int clock_ratio[32]; | 81 | static int clock_ratio[32]; |
75 | static int eblcr_table[32]; | 82 | static int eblcr_table[32]; |
76 | static int voltage_table[32]; | ||
77 | static unsigned int highest_speed, lowest_speed; /* kHz */ | 83 | static unsigned int highest_speed, lowest_speed; /* kHz */ |
78 | static int longhaul_version; | 84 | static int longhaul_version; |
79 | static struct cpufreq_frequency_table *longhaul_table; | 85 | static 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) | |||
454 | static void __init longhaul_setup_voltagescaling(void) | 465 | static 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 | ||
776 | module_param (dont_scale_voltage, int, 0644); | 791 | module_param (scale_voltage, int, 0644); |
777 | MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor"); | 792 | MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); |
778 | module_param(ignore_latency, int, 0644); | 793 | module_param(ignore_latency, int, 0644); |
779 | MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test"); | 794 | MODULE_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 | */ |
453 | static int __initdata vrm85scales[32] = { | 453 | |
454 | 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, | 454 | struct 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 | |||
459 | static 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 | |||
470 | static 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 | |||
477 | static 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 | ||
460 | static int __initdata mobilevrmscales[32] = { | 488 | static 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 | ||