diff options
Diffstat (limited to 'arch/i386/kernel/cpu/cpufreq/longhaul.c')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 186 |
1 files changed, 123 insertions, 63 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 4f2c3aeef724..f5cc9f5c9bab 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/cpufreq.h> | 29 | #include <linux/cpufreq.h> |
30 | #include <linux/pci.h> | ||
30 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
31 | #include <linux/string.h> | 32 | #include <linux/string.h> |
32 | 33 | ||
@@ -52,18 +53,26 @@ | |||
52 | #define CPU_NEHEMIAH 5 | 53 | #define CPU_NEHEMIAH 5 |
53 | 54 | ||
54 | static int cpu_model; | 55 | static int cpu_model; |
55 | static unsigned int numscales=16, numvscales; | 56 | static unsigned int numscales=16; |
56 | static unsigned int fsb; | 57 | static unsigned int fsb; |
57 | 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 */ | ||
58 | static unsigned int minmult, maxmult; | 67 | static unsigned int minmult, maxmult; |
59 | static int can_scale_voltage; | 68 | static int can_scale_voltage; |
60 | static int vrmrev; | ||
61 | static struct acpi_processor *pr = NULL; | 69 | static struct acpi_processor *pr = NULL; |
62 | static struct acpi_processor_cx *cx = NULL; | 70 | static struct acpi_processor_cx *cx = NULL; |
71 | static int port22_en; | ||
63 | 72 | ||
64 | /* Module parameters */ | 73 | /* Module parameters */ |
65 | static int dont_scale_voltage; | 74 | static int scale_voltage; |
66 | 75 | static int ignore_latency; | |
67 | 76 | ||
68 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) | 77 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) |
69 | 78 | ||
@@ -71,7 +80,6 @@ static int dont_scale_voltage; | |||
71 | /* Clock ratios multiplied by 10 */ | 80 | /* Clock ratios multiplied by 10 */ |
72 | static int clock_ratio[32]; | 81 | static int clock_ratio[32]; |
73 | static int eblcr_table[32]; | 82 | static int eblcr_table[32]; |
74 | static int voltage_table[32]; | ||
75 | static unsigned int highest_speed, lowest_speed; /* kHz */ | 83 | static unsigned int highest_speed, lowest_speed; /* kHz */ |
76 | static int longhaul_version; | 84 | static int longhaul_version; |
77 | static struct cpufreq_frequency_table *longhaul_table; | 85 | static struct cpufreq_frequency_table *longhaul_table; |
@@ -124,10 +132,9 @@ static int longhaul_get_cpu_mult(void) | |||
124 | 132 | ||
125 | /* For processor with BCR2 MSR */ | 133 | /* For processor with BCR2 MSR */ |
126 | 134 | ||
127 | static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) | 135 | static void do_longhaul1(unsigned int clock_ratio_index) |
128 | { | 136 | { |
129 | union msr_bcr2 bcr2; | 137 | union msr_bcr2 bcr2; |
130 | u32 t; | ||
131 | 138 | ||
132 | rdmsrl(MSR_VIA_BCR2, bcr2.val); | 139 | rdmsrl(MSR_VIA_BCR2, bcr2.val); |
133 | /* Enable software clock multiplier */ | 140 | /* Enable software clock multiplier */ |
@@ -136,13 +143,11 @@ static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) | |||
136 | 143 | ||
137 | /* Sync to timer tick */ | 144 | /* Sync to timer tick */ |
138 | safe_halt(); | 145 | safe_halt(); |
139 | ACPI_FLUSH_CPU_CACHE(); | ||
140 | /* Change frequency on next halt or sleep */ | 146 | /* Change frequency on next halt or sleep */ |
141 | wrmsrl(MSR_VIA_BCR2, bcr2.val); | 147 | wrmsrl(MSR_VIA_BCR2, bcr2.val); |
142 | /* Invoke C3 */ | 148 | /* Invoke transition */ |
143 | inb(cx_address); | 149 | ACPI_FLUSH_CPU_CACHE(); |
144 | /* Dummy op - must do something useless after P_LVL3 read */ | 150 | halt(); |
145 | t = inl(acpi_fadt.xpm_tmr_blk.address); | ||
146 | 151 | ||
147 | /* Disable software clock multiplier */ | 152 | /* Disable software clock multiplier */ |
148 | local_irq_disable(); | 153 | local_irq_disable(); |
@@ -164,11 +169,16 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index) | |||
164 | longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; | 169 | longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; |
165 | longhaul.bits.EnableSoftBusRatio = 1; | 170 | longhaul.bits.EnableSoftBusRatio = 1; |
166 | 171 | ||
172 | if (can_scale_voltage) { | ||
173 | longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm; | ||
174 | longhaul.bits.EnableSoftVID = 1; | ||
175 | } | ||
176 | |||
167 | /* Sync to timer tick */ | 177 | /* Sync to timer tick */ |
168 | safe_halt(); | 178 | safe_halt(); |
169 | ACPI_FLUSH_CPU_CACHE(); | ||
170 | /* Change frequency on next halt or sleep */ | 179 | /* Change frequency on next halt or sleep */ |
171 | wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); | 180 | wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); |
181 | ACPI_FLUSH_CPU_CACHE(); | ||
172 | /* Invoke C3 */ | 182 | /* Invoke C3 */ |
173 | inb(cx_address); | 183 | inb(cx_address); |
174 | /* Dummy op - must do something useless after P_LVL3 read */ | 184 | /* Dummy op - must do something useless after P_LVL3 read */ |
@@ -227,10 +237,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
227 | outb(0xFF,0xA1); /* Overkill */ | 237 | outb(0xFF,0xA1); /* Overkill */ |
228 | outb(0xFE,0x21); /* TMR0 only */ | 238 | outb(0xFE,0x21); /* TMR0 only */ |
229 | 239 | ||
230 | /* Disable bus master arbitration */ | 240 | if (pr->flags.bm_control) { |
231 | if (pr->flags.bm_check) { | 241 | /* Disable bus master arbitration */ |
232 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, | 242 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, |
233 | ACPI_MTX_DO_NOT_LOCK); | 243 | ACPI_MTX_DO_NOT_LOCK); |
244 | } else if (port22_en) { | ||
245 | /* Disable AGP and PCI arbiters */ | ||
246 | outb(3, 0x22); | ||
234 | } | 247 | } |
235 | 248 | ||
236 | switch (longhaul_version) { | 249 | switch (longhaul_version) { |
@@ -244,7 +257,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
244 | */ | 257 | */ |
245 | case TYPE_LONGHAUL_V1: | 258 | case TYPE_LONGHAUL_V1: |
246 | case TYPE_LONGHAUL_V2: | 259 | case TYPE_LONGHAUL_V2: |
247 | do_longhaul1(cx->address, clock_ratio_index); | 260 | do_longhaul1(clock_ratio_index); |
248 | break; | 261 | break; |
249 | 262 | ||
250 | /* | 263 | /* |
@@ -259,14 +272,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
259 | * to work in practice. | 272 | * to work in practice. |
260 | */ | 273 | */ |
261 | case TYPE_POWERSAVER: | 274 | case TYPE_POWERSAVER: |
275 | /* Don't allow wakeup */ | ||
276 | acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, | ||
277 | ACPI_MTX_DO_NOT_LOCK); | ||
262 | do_powersaver(cx->address, clock_ratio_index); | 278 | do_powersaver(cx->address, clock_ratio_index); |
263 | break; | 279 | break; |
264 | } | 280 | } |
265 | 281 | ||
266 | /* Enable bus master arbitration */ | 282 | if (pr->flags.bm_control) { |
267 | if (pr->flags.bm_check) { | 283 | /* Enable bus master arbitration */ |
268 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, | 284 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, |
269 | ACPI_MTX_DO_NOT_LOCK); | 285 | ACPI_MTX_DO_NOT_LOCK); |
286 | } else if (port22_en) { | ||
287 | /* Enable arbiters */ | ||
288 | outb(0, 0x22); | ||
270 | } | 289 | } |
271 | 290 | ||
272 | outb(pic2_mask,0xA1); /* restore mask */ | 291 | outb(pic2_mask,0xA1); /* restore mask */ |
@@ -446,53 +465,57 @@ static int __init longhaul_get_ranges(void) | |||
446 | static void __init longhaul_setup_voltagescaling(void) | 465 | static void __init longhaul_setup_voltagescaling(void) |
447 | { | 466 | { |
448 | union msr_longhaul longhaul; | 467 | union msr_longhaul longhaul; |
468 | struct mV_pos minvid, maxvid; | ||
469 | unsigned int j, speed, pos, kHz_step, numvscales; | ||
449 | 470 | ||
450 | rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); | 471 | rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); |
451 | 472 | if (!(longhaul.bits.RevisionID & 1)) { | |
452 | if (!(longhaul.bits.RevisionID & 1)) | 473 | printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n"); |
453 | 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 | } | ||
454 | 486 | ||
455 | minvid = longhaul.bits.MinimumVID; | 487 | minvid = vrm_mV_table[longhaul.bits.MinimumVID]; |
456 | maxvid = longhaul.bits.MaximumVID; | 488 | maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; |
457 | vrmrev = longhaul.bits.VRMRev; | 489 | numvscales = maxvid.pos - minvid.pos + 1; |
490 | kHz_step = (highest_speed - lowest_speed) / numvscales; | ||
458 | 491 | ||
459 | if (minvid == 0 || maxvid == 0) { | 492 | if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { |
460 | 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. " |
461 | "Voltage scaling disabled.\n", | 494 | "Voltage scaling disabled.\n", |
462 | minvid/1000, minvid%1000, maxvid/1000, maxvid%1000); | 495 | minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000); |
463 | return; | 496 | return; |
464 | } | 497 | } |
465 | 498 | ||
466 | if (minvid == maxvid) { | 499 | if (minvid.mV == maxvid.mV) { |
467 | 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 " |
468 | "both %d.%03d. Voltage scaling disabled\n", | 501 | "both %d.%03d. Voltage scaling disabled\n", |
469 | maxvid/1000, maxvid%1000); | 502 | maxvid.mV/1000, maxvid.mV%1000); |
470 | return; | 503 | return; |
471 | } | 504 | } |
472 | 505 | ||
473 | if (vrmrev==0) { | 506 | printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n", |
474 | dprintk ("VRM 8.5\n"); | 507 | maxvid.mV/1000, maxvid.mV%1000, |
475 | memcpy (voltage_table, vrm85scales, sizeof(voltage_table)); | 508 | minvid.mV/1000, minvid.mV%1000, |
476 | numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25; | 509 | numvscales); |
477 | } else { | 510 | |
478 | dprintk ("Mobile VRM\n"); | 511 | j = 0; |
479 | memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table)); | 512 | while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { |
480 | 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++; | ||
481 | } | 517 | } |
482 | 518 | ||
483 | /* Current voltage isn't readable at first, so we need to | ||
484 | set it to a known value. The spec says to use maxvid */ | ||
485 | longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */ | ||
486 | longhaul.bits.EnableSoftVID = 1; | ||
487 | longhaul.bits.SoftVID = maxvid; | ||
488 | wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); | ||
489 | |||
490 | minvid = voltage_table[minvid]; | ||
491 | maxvid = voltage_table[maxvid]; | ||
492 | |||
493 | dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n", | ||
494 | maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales); | ||
495 | |||
496 | can_scale_voltage = 1; | 519 | can_scale_voltage = 1; |
497 | } | 520 | } |
498 | 521 | ||
@@ -540,21 +563,33 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle, | |||
540 | return 1; | 563 | return 1; |
541 | } | 564 | } |
542 | 565 | ||
566 | /* VIA don't support PM2 reg, but have something similar */ | ||
567 | static int enable_arbiter_disable(void) | ||
568 | { | ||
569 | struct pci_dev *dev; | ||
570 | u8 pci_cmd; | ||
571 | |||
572 | /* Find PLE133 host bridge */ | ||
573 | dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL); | ||
574 | if (dev != NULL) { | ||
575 | /* Enable access to port 0x22 */ | ||
576 | pci_read_config_byte(dev, 0x78, &pci_cmd); | ||
577 | if ( !(pci_cmd & 1<<7) ) { | ||
578 | pci_cmd |= 1<<7; | ||
579 | pci_write_config_byte(dev, 0x78, pci_cmd); | ||
580 | } | ||
581 | return 1; | ||
582 | } | ||
583 | return 0; | ||
584 | } | ||
585 | |||
543 | static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | 586 | static int __init longhaul_cpu_init(struct cpufreq_policy *policy) |
544 | { | 587 | { |
545 | struct cpuinfo_x86 *c = cpu_data; | 588 | struct cpuinfo_x86 *c = cpu_data; |
546 | char *cpuname=NULL; | 589 | char *cpuname=NULL; |
547 | int ret; | 590 | int ret; |
548 | 591 | ||
549 | /* Check ACPI support for C3 state */ | 592 | /* Check what we have on this motherboard */ |
550 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | ||
551 | &longhaul_walk_callback, NULL, (void *)&pr); | ||
552 | if (pr == NULL) goto err_acpi; | ||
553 | |||
554 | cx = &pr->power.states[ACPI_STATE_C3]; | ||
555 | if (cx->address == 0 || cx->latency > 1000) goto err_acpi; | ||
556 | |||
557 | /* Now check what we have on this motherboard */ | ||
558 | switch (c->x86_model) { | 593 | switch (c->x86_model) { |
559 | case 6: | 594 | case 6: |
560 | cpu_model = CPU_SAMUEL; | 595 | cpu_model = CPU_SAMUEL; |
@@ -636,12 +671,36 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | |||
636 | break; | 671 | break; |
637 | }; | 672 | }; |
638 | 673 | ||
674 | /* Find ACPI data for processor */ | ||
675 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | ||
676 | &longhaul_walk_callback, NULL, (void *)&pr); | ||
677 | if (pr == NULL) | ||
678 | goto err_acpi; | ||
679 | |||
680 | if (longhaul_version == TYPE_POWERSAVER) { | ||
681 | /* Check ACPI support for C3 state */ | ||
682 | cx = &pr->power.states[ACPI_STATE_C3]; | ||
683 | if (cx->address == 0 || | ||
684 | (cx->latency > 1000 && ignore_latency == 0) ) | ||
685 | goto err_acpi; | ||
686 | |||
687 | } else { | ||
688 | /* Check ACPI support for bus master arbiter disable */ | ||
689 | if (!pr->flags.bm_control) { | ||
690 | if (!enable_arbiter_disable()) { | ||
691 | printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n"); | ||
692 | return -ENODEV; | ||
693 | } else | ||
694 | port22_en = 1; | ||
695 | } | ||
696 | } | ||
697 | |||
639 | ret = longhaul_get_ranges(); | 698 | ret = longhaul_get_ranges(); |
640 | if (ret != 0) | 699 | if (ret != 0) |
641 | return ret; | 700 | return ret; |
642 | 701 | ||
643 | if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && | 702 | if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && |
644 | (dont_scale_voltage==0)) | 703 | (scale_voltage != 0)) |
645 | longhaul_setup_voltagescaling(); | 704 | longhaul_setup_voltagescaling(); |
646 | 705 | ||
647 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | 706 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; |
@@ -729,8 +788,10 @@ static void __exit longhaul_exit(void) | |||
729 | kfree(longhaul_table); | 788 | kfree(longhaul_table); |
730 | } | 789 | } |
731 | 790 | ||
732 | module_param (dont_scale_voltage, int, 0644); | 791 | module_param (scale_voltage, int, 0644); |
733 | MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor"); | 792 | MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); |
793 | module_param(ignore_latency, int, 0644); | ||
794 | MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test"); | ||
734 | 795 | ||
735 | MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); | 796 | MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); |
736 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); | 797 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); |
@@ -738,4 +799,3 @@ MODULE_LICENSE ("GPL"); | |||
738 | 799 | ||
739 | late_initcall(longhaul_init); | 800 | late_initcall(longhaul_init); |
740 | module_exit(longhaul_exit); | 801 | module_exit(longhaul_exit); |
741 | |||