1/* 2 * (C) 2001-2004 Dave Jones. <davej@codemonkey.org.uk> 3 * (C) 2002 Padraig Brady. <padraig@antefacto.com> 4 * 5 * Licensed under the terms of the GNU GPL License version 2. 6 * Based upon datasheets & sample CPUs kindly provided by VIA. 7 * 8 * VIA have currently 3 different versions of Longhaul. 9 * Version 1 (Longhaul) uses the BCR2 MSR at 0x1147. 10 * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0. 11 * Version 2 of longhaul is backward compatible with v1, but adds 12 * LONGHAUL MSR for purpose of both frequency and voltage scaling. 13 * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C). 14 * Version 3 of longhaul got renamed to Powersaver and redesigned 15 * to use only the POWERSAVER MSR at 0x110a. 16 * It is present in Ezra-T (C5M), Nehemiah (C5X) and above. 17 * It's pretty much the same feature wise to longhaul v2, though 18 * there is provision for scaling FSB too, but this doesn't work 19 * too well in practice so we don't even try to use this. 20 * 21 * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* 22 */ 23 24#include <linux/kernel.h> 25#include <linux/module.h> 26#include <linux/moduleparam.h> 27#include <linux/init.h> 28#include <linux/cpufreq.h> 29#include <linux/pci.h> 30#include <linux/slab.h> 31#include <linux/string.h> 32 33#include <asm/msr.h> 34#include <asm/timex.h> 35#include <asm/io.h> 36#include <asm/acpi.h> 37#include <linux/acpi.h> 38#include <acpi/processor.h> 39 40#include "longhaul.h" 41 42#define PFX "longhaul: " 43 44#define TYPE_LONGHAUL_V1 1 45#define TYPE_LONGHAUL_V2 2 46#define TYPE_POWERSAVER 3 47 48#define CPU_SAMUEL 1 49#define CPU_SAMUEL2 2 50#define CPU_EZRA 3 51#define CPU_EZRA_T 4 52#define CPU_NEHEMIAH 5 53#define CPU_NEHEMIAH_C 6 54 55/* Flags */ 56#define USE_ACPI_C3 (1 << 1) 57#define USE_NORTHBRIDGE (1 << 2) 58#define USE_VT8235 (1 << 3) 59 60static int cpu_model; 61static unsigned int numscales=16; 62static unsigned int fsb; 63 64static const struct mV_pos *vrm_mV_table; 65static const unsigned char *mV_vrm_table; 66struct f_msr { 67 u8 vrm; 68 u8 pos; 69}; 70static struct f_msr f_msr_table[32]; 71 72static unsigned int highest_speed, lowest_speed; /* kHz */ 73static unsigned int minmult, maxmult; 74static int can_scale_voltage; 75static struct acpi_processor *pr = NULL; 76static struct acpi_processor_cx *cx = NULL; 77static u8 longhaul_flags; 78static u8 longhaul_pos; 79 80/* Module parameters */ 81static int scale_voltage; 82 83#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) 84 85 86/* Clock ratios multiplied by 10 */ 87static int clock_ratio[32]; 88static int eblcr_table[32]; 89static int longhaul_version; 90static struct cpufreq_frequency_table *longhaul_table; 91 92#ifdef CONFIG_CPU_FREQ_DEBUG 93static char speedbuffer[8]; 94 95static char *print_speed(int speed) 96{ 97 if (speed < 1000) { 98 snprintf(speedbuffer, sizeof(speedbuffer),"%dMHz", speed); 99 return speedbuffer; 100 } 101 102 if (speed%1000 == 0) 103 snprintf(speedbuffer, sizeof(speedbuffer), 104 "%dGHz", speed/1000); 105 else 106 snprintf(speedbuffer, sizeof(speedbuffer), 107 "%d.%dGHz", speed/1000, (speed%1000)/100); 108 109 return speedbuffer; 110} 111#endif 112 113 114static unsigned int calc_speed(int mult) 115{ 116 int khz; 117 khz = (mult/10)*fsb; 118 if (mult%10) 119 khz += fsb/2; 120 khz *= 1000; 121 return khz; 122} 123 124 125static int longhaul_get_cpu_mult(void) 126{ 127 unsigned long invalue=0,lo, hi; 128 129 rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); 130 invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; 131 if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) { 132 if (lo & (1<<27)) 133 invalue+=16; 134 } 135 return eblcr_table[invalue]; 136} 137 138/* For processor with BCR2 MSR */ 139 140static void do_longhaul1(unsigned int clock_ratio_index) 141{ 142 union msr_bcr2 bcr2; 143 144 rdmsrl(MSR_VIA_BCR2, bcr2.val); 145 /* Enable software clock multiplier */ 146 bcr2.bits.ESOFTBF = 1; 147 bcr2.bits.CLOCKMUL = clock_ratio_index; 148 149 /* Sync to timer tick */ 150 safe_halt(); 151 /* Change frequency on next halt or sleep */ 152 wrmsrl(MSR_VIA_BCR2, bcr2.val); 153 /* Invoke transition */ 154 ACPI_FLUSH_CPU_CACHE(); 155 halt(); 156 157 /* Disable software clock multiplier */ 158 local_irq_disable(); 159 rdmsrl(MSR_VIA_BCR2, bcr2.val); 160 bcr2.bits.ESOFTBF = 0; 161 wrmsrl(MSR_VIA_BCR2, bcr2.val); 162} 163 164/* For processor with Longhaul MSR */ 165 166static void do_powersaver(int cx_address, unsigned int clock_ratio_index) 167{ 168 union msr_longhaul longhaul; 169 u8 dest_pos; 170 u32 t; 171 172 dest_pos = f_msr_table[clock_ratio_index].pos; 173 174 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); 175 /* Setup new frequency */ 176 longhaul.bits.RevisionKey = longhaul.bits.RevisionID; 177 longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; 178 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; 179 /* Setup new voltage */ 180 if (can_scale_voltage) 181 longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm; 182 /* Sync to timer tick */ 183 safe_halt(); 184 /* Raise voltage if necessary */ 185 if (can_scale_voltage && longhaul_pos < dest_pos) { 186 longhaul.bits.EnableSoftVID = 1; 187 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 188 /* Change voltage */ 189 if (!cx_address) { 190 ACPI_FLUSH_CPU_CACHE(); 191 halt(); 192 } else { 193 ACPI_FLUSH_CPU_CACHE(); 194 /* Invoke C3 */ 195 inb(cx_address); 196 /* Dummy op - must do something useless after P_LVL3 197 * read */ 198 t = inl(acpi_gbl_FADT.xpm_timer_block.address); 199 } 200 longhaul.bits.EnableSoftVID = 0; 201 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 202 longhaul_pos = dest_pos; 203 } 204 205 /* Change frequency on next halt or sleep */ 206 longhaul.bits.EnableSoftBusRatio = 1; 207 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 208 if (!cx_address) { 209 ACPI_FLUSH_CPU_CACHE(); 210 halt(); 211 } else { 212 ACPI_FLUSH_CPU_CACHE(); 213 /* Invoke C3 */ 214 inb(cx_address); 215 /* Dummy op - must do something useless after P_LVL3 read */ 216 t = inl(acpi_gbl_FADT.xpm_timer_block.address); 217 } 218 /* Disable bus ratio bit */ 219 longhaul.bits.EnableSoftBusRatio = 0; 220 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 221 222 /* Reduce voltage if necessary */ 223 if (can_scale_voltage && longhaul_pos > dest_pos) { 224 longhaul.bits.EnableSoftVID = 1; 225 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 226 /* Change voltage */ 227 if (!cx_address) { 228 ACPI_FLUSH_CPU_CACHE(); 229 halt(); 230 } else { 231 ACPI_FLUSH_CPU_CACHE(); 232 /* Invoke C3 */ 233 inb(cx_address); 234 /* Dummy op - must do something useless after P_LVL3 235 * read */ 236 t = inl(acpi_gbl_FADT.xpm_timer_block.address); 237 } 238 longhaul.bits.EnableSoftVID = 0; 239 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 240 longhaul_pos = dest_pos; 241 } 242} 243 244/** 245 * longhaul_set_cpu_frequency() 246 * @clock_ratio_index : bitpattern of the new multiplier. 247 * 248 * Sets a new clock ratio. 249 */ 250 251static void longhaul_setstate(unsigned int clock_ratio_index) 252{ 253 int speed, mult; 254 struct cpufreq_freqs freqs; 255 static unsigned int old_ratio=-1; 256 unsigned long flags; 257 unsigned int pic1_mask, pic2_mask; 258 259 if (old_ratio == clock_ratio_index) 260 return; 261 old_ratio = clock_ratio_index; 262 263 mult = clock_ratio[clock_ratio_index]; 264 if (mult == -1) 265 return; 266 267 speed = calc_speed(mult); 268 if ((speed > highest_speed) || (speed < lowest_speed)) 269 return; 270 271 freqs.old = calc_speed(longhaul_get_cpu_mult()); 272 freqs.new = speed; 273 freqs.cpu = 0; /* longhaul.c is UP only driver */ 274 275 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 276 277 dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", 278 fsb, mult/10, mult%10, print_speed(speed/1000)); 279 280 preempt_disable(); 281 local_irq_save(flags); 282 283 pic2_mask = inb(0xA1); 284 pic1_mask = inb(0x21); /* works on C3. save mask. */ 285 outb(0xFF,0xA1); /* Overkill */ 286 outb(0xFE,0x21); /* TMR0 only */ 287 288 if (longhaul_flags & USE_NORTHBRIDGE) { 289 /* Disable AGP and PCI arbiters */ 290 outb(3, 0x22); 291 } else if ((pr != NULL) && pr->flags.bm_control) { 292 /* Disable bus master arbitration */ 293 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); 294 } 295 switch (longhaul_version) { 296 297 /* 298 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B]) 299 * Software controlled multipliers only. 300 */ 301 case TYPE_LONGHAUL_V1: 302 do_longhaul1(clock_ratio_index); 303 break; 304 305 /* 306 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C] 307 * 308 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N]) 309 * Nehemiah can do FSB scaling too, but this has never been proven 310 * to work in practice. 311 */ 312 case TYPE_LONGHAUL_V2: 313 case TYPE_POWERSAVER: 314 if (longhaul_flags & USE_ACPI_C3) { 315 /* Don't allow wakeup */ 316 acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); 317 do_powersaver(cx->address, clock_ratio_index); 318 } else { 319 do_powersaver(0, clock_ratio_index); 320 } 321 break; 322 } 323 324 if (longhaul_flags & USE_NORTHBRIDGE) { 325 /* Enable arbiters */ 326 outb(0, 0x22); 327 } else if ((pr != NULL) && pr->flags.bm_control) { 328 /* Enable bus master arbitration */ 329 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); 330 } 331 outb(pic2_mask,0xA1); /* restore mask */ 332 outb(pic1_mask,0x21); 333 334 local_irq_restore(flags); 335 preempt_enable(); 336 337 freqs.new = calc_speed(longhaul_get_cpu_mult()); 338 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 339} 340 341/* 342 * Centaur decided to make life a little more tricky. 343 * Only longhaul v1 is allowed to read EBLCR BSEL[0:1]. 344 * Samuel2 and above have to try and guess what the FSB is. 345 * We do this by assuming we booted at maximum multiplier, and interpolate 346 * between that value multiplied by possible FSBs and cpu_mhz which 347 * was calculated at boot time. Really ugly, but no other way to do this. 348 */ 349 350#define ROUNDING 0xf 351 352static int guess_fsb(int mult) 353{ 354 int speed = cpu_khz / 1000; 355 int i; 356 int speeds[] = { 666, 1000, 1333, 2000 }; 357 int f_max, f_min; 358 359 for (i = 0; i < 4; i++) { 360 f_max = ((speeds[i] * mult) + 50) / 100; 361 f_max += (ROUNDING / 2); 362 f_min = f_max - ROUNDING; 363 if ((speed <= f_max) && (speed >= f_min)) 364 return speeds[i] / 10; 365 } 366 return 0; 367} 368 369 370static int __init longhaul_get_ranges(void) 371{ 372 unsigned int j, k = 0; 373 int mult; 374 375 /* Get current frequency */ 376 mult = longhaul_get_cpu_mult(); 377 if (mult == -1) { 378 printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n"); 379 return -EINVAL; 380 } 381 fsb = guess_fsb(mult); 382 if (fsb == 0) { 383 printk(KERN_INFO PFX "Invalid (reserved) FSB!\n"); 384 return -EINVAL; 385 } 386 /* Get max multiplier - as we always did. 387 * Longhaul MSR is usefull only when voltage scaling is enabled. 388 * C3 is booting at max anyway. */ 389 maxmult = mult; 390 /* Get min multiplier */ 391 switch (cpu_model) { 392 case CPU_NEHEMIAH: 393 minmult = 50; 394 break; 395 case CPU_NEHEMIAH_C: 396 minmult = 40; 397 break; 398 default: 399 minmult = 30; 400 break; 401 } 402 403 dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", 404 minmult/10, minmult%10, maxmult/10, maxmult%10); 405 406 highest_speed = calc_speed(maxmult); 407 lowest_speed = calc_speed(minmult); 408 dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, 409 print_speed(lowest_speed/1000), 410 print_speed(highest_speed/1000)); 411 412 if (lowest_speed == highest_speed) { 413 printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n"); 414 return -EINVAL; 415 } 416 if (lowest_speed > highest_speed) { 417 printk (KERN_INFO PFX "nonsense! lowest (%d > %d) !\n", 418 lowest_speed, highest_speed); 419 return -EINVAL; 420 } 421 422 longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL); 423 if(!longhaul_table) 424 return -ENOMEM; 425 426 for (j=0; j < numscales; j++) { 427 unsigned int ratio; 428 ratio = clock_ratio[j]; 429 if (ratio == -1) 430 continue; 431 if (ratio > maxmult || ratio < minmult) 432 continue; 433 longhaul_table[k].frequency = calc_speed(ratio); 434 longhaul_table[k].index = j; 435 k++; 436 } 437 438 longhaul_table[k].frequency = CPUFREQ_TABLE_END; 439 if (!k) { 440 kfree (longhaul_table); 441 return -EINVAL; 442 } 443 444 return 0; 445} 446 447 448static void __init longhaul_setup_voltagescaling(void) 449{ 450 union msr_longhaul longhaul; 451 struct mV_pos minvid, maxvid; 452 unsigned int j, speed, pos, kHz_step, numvscales; 453 int min_vid_speed; 454 455 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); 456 if (!(longhaul.bits.RevisionID & 1)) { 457 printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n"); 458 return; 459 } 460 461 if (!longhaul.bits.VRMRev) { 462 printk (KERN_INFO PFX "VRM 8.5\n"); 463 vrm_mV_table = &vrm85_mV[0]; 464 mV_vrm_table = &mV_vrm85[0]; 465 } else { 466 printk (KERN_INFO PFX "Mobile VRM\n"); 467 if (cpu_model < CPU_NEHEMIAH) 468 return; 469 vrm_mV_table = &mobilevrm_mV[0]; 470 mV_vrm_table = &mV_mobilevrm[0]; 471 } 472 473 minvid = vrm_mV_table[longhaul.bits.MinimumVID]; 474 maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; 475 476 if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { 477 printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " 478 "Voltage scaling disabled.\n", 479 minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000); 480 return; 481 } 482 483 if (minvid.mV == maxvid.mV) { 484 printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are " 485 "both %d.%03d. Voltage scaling disabled\n", 486 maxvid.mV/1000, maxvid.mV%1000); 487 return; 488 } 489 490 /* How many voltage steps */ 491 numvscales = maxvid.pos - minvid.pos + 1; 492 printk(KERN_INFO PFX 493 "Max VID=%d.%03d " 494 "Min VID=%d.%03d, " 495 "%d possible voltage scales\n", 496 maxvid.mV/1000, maxvid.mV%1000, 497 minvid.mV/1000, minvid.mV%1000, 498 numvscales); 499 500 /* Calculate max frequency at min voltage */ 501 j = longhaul.bits.MinMHzBR; 502 if (longhaul.bits.MinMHzBR4) 503 j += 16; 504 min_vid_speed = eblcr_table[j]; 505 if (min_vid_speed == -1) 506 return; 507 switch (longhaul.bits.MinMHzFSB) { 508 case 0: 509 min_vid_speed *= 13333; 510 break; 511 case 1: 512 min_vid_speed *= 10000; 513 break; 514 case 3: 515 min_vid_speed *= 6666; 516 break; 517 default: 518 return; 519 break; 520 } 521 if (min_vid_speed >= highest_speed) 522 return; 523 /* Calculate kHz for one voltage step */ 524 kHz_step = (highest_speed - min_vid_speed) / numvscales; 525 526 527 j = 0; 528 while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { 529 speed = longhaul_table[j].frequency; 530 if (speed > min_vid_speed) 531 pos = (speed - min_vid_speed) / kHz_step + minvid.pos; 532 else 533 pos = minvid.pos; 534 f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos]; 535 f_msr_table[longhaul_table[j].index].pos = pos; 536 j++; 537 } 538 539 longhaul_pos = maxvid.pos; 540 can_scale_voltage = 1; 541 printk(KERN_INFO PFX "Voltage scaling enabled. " 542 "Use of \"conservative\" governor is highly recommended.\n"); 543} 544 545 546static int longhaul_verify(struct cpufreq_policy *policy) 547{ 548 return cpufreq_frequency_table_verify(policy, longhaul_table); 549} 550 551 552static int longhaul_target(struct cpufreq_policy *policy, 553 unsigned int target_freq, unsigned int relation) 554{ 555 unsigned int table_index = 0; 556 unsigned int new_clock_ratio = 0; 557 558 if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index)) 559 return -EINVAL; 560 561 new_clock_ratio = longhaul_table[table_index].index & 0xFF; 562 563 longhaul_setstate(new_clock_ratio); 564 565 return 0; 566} 567 568 569static unsigned int longhaul_get(unsigned int cpu) 570{ 571 if (cpu) 572 return 0; 573 return calc_speed(longhaul_get_cpu_mult()); 574} 575 576static acpi_status longhaul_walk_callback(acpi_handle obj_handle, 577 u32 nesting_level, 578 void *context, void **return_value) 579{ 580 struct acpi_device *d; 581 582 if ( acpi_bus_get_device(obj_handle, &d) ) { 583 return 0; 584 } 585 *return_value = (void *)acpi_driver_data(d); 586 return 1; 587} 588 589/* VIA don't support PM2 reg, but have something similar */ 590static int enable_arbiter_disable(void) 591{ 592 struct pci_dev *dev; 593 int status; 594 int reg; 595 u8 pci_cmd; 596 597 status = 1; 598 /* Find PLE133 host bridge */ 599 reg = 0x78; 600 dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, 601 NULL); 602 /* Find CLE266 host bridge */ 603 if (dev == NULL) { 604 reg = 0x76; 605 dev = pci_get_device(PCI_VENDOR_ID_VIA, 606 PCI_DEVICE_ID_VIA_862X_0, NULL); 607 /* Find CN400 V-Link host bridge */ 608 if (dev == NULL) 609 dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); 610 } 611 if (dev != NULL) { 612 /* Enable access to port 0x22 */ 613 pci_read_config_byte(dev, reg, &pci_cmd); 614 if (!(pci_cmd & 1<<7)) { 615 pci_cmd |= 1<<7; 616 pci_write_config_byte(dev, reg, pci_cmd); 617 pci_read_config_byte(dev, reg, &pci_cmd); 618 if (!(pci_cmd & 1<<7)) { 619 printk(KERN_ERR PFX 620 "Can't enable access to port 0x22.\n"); 621 status = 0; 622 } 623 } 624 pci_dev_put(dev); 625 return status; 626 } 627 return 0; 628} 629 630static int longhaul_setup_vt8235(void) 631{ 632 struct pci_dev *dev; 633 u8 pci_cmd; 634 635 /* Find VT8235 southbridge */ 636 dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); 637 if (dev != NULL) { 638 /* Set transition time to max */ 639 pci_read_config_byte(dev, 0xec, &pci_cmd); 640 pci_cmd &= ~(1 << 2); 641 pci_write_config_byte(dev, 0xec, pci_cmd); 642 pci_read_config_byte(dev, 0xe4, &pci_cmd); 643 pci_cmd &= ~(1 << 7); 644 pci_write_config_byte(dev, 0xe4, pci_cmd); 645 pci_read_config_byte(dev, 0xe5, &pci_cmd); 646 pci_cmd |= 1 << 7; 647 pci_write_config_byte(dev, 0xe5, pci_cmd); 648 pci_dev_put(dev); 649 return 1; 650 } 651 return 0; 652} 653 654static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 655{ 656 struct cpuinfo_x86 *c = cpu_data; 657 char *cpuname=NULL; 658 int ret; 659 u32 lo, hi; 660 int vt8235_present; 661 662 /* Check what we have on this motherboard */ 663 switch (c->x86_model) { 664 case 6: 665 cpu_model = CPU_SAMUEL; 666 cpuname = "C3 'Samuel' [C5A]"; 667 longhaul_version = TYPE_LONGHAUL_V1; 668 memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio)); 669 memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); 670 break; 671 672 case 7: 673 switch (c->x86_mask) { 674 case 0: 675 longhaul_version = TYPE_LONGHAUL_V1; 676 cpu_model = CPU_SAMUEL2; 677 cpuname = "C3 'Samuel 2' [C5B]"; 678 /* Note, this is not a typo, early Samuel2's had 679 * Samuel1 ratios. */ 680 memcpy(clock_ratio, samuel1_clock_ratio, 681 sizeof(samuel1_clock_ratio)); 682 memcpy(eblcr_table, samuel2_eblcr, 683 sizeof(samuel2_eblcr)); 684 break; 685 case 1 ... 15: 686 longhaul_version = TYPE_LONGHAUL_V1; 687 if (c->x86_mask < 8) { 688 cpu_model = CPU_SAMUEL2; 689 cpuname = "C3 'Samuel 2' [C5B]"; 690 } else { 691 cpu_model = CPU_EZRA; 692 cpuname = "C3 'Ezra' [C5C]"; 693 } 694 memcpy(clock_ratio, ezra_clock_ratio, 695 sizeof(ezra_clock_ratio)); 696 memcpy(eblcr_table, ezra_eblcr, 697 sizeof(ezra_eblcr)); 698 break; 699 } 700 break; 701 702 case 8: 703 cpu_model = CPU_EZRA_T; 704 cpuname = "C3 'Ezra-T' [C5M]"; 705 longhaul_version = TYPE_POWERSAVER; 706 numscales=32; 707 memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio)); 708 memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr)); 709 break; 710 711 case 9: 712 longhaul_version = TYPE_POWERSAVER; 713 numscales = 32; 714 memcpy(clock_ratio, 715 nehemiah_clock_ratio, 716 sizeof(nehemiah_clock_ratio)); 717 memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr)); 718 switch (c->x86_mask) { 719 case 0 ... 1: 720 cpu_model = CPU_NEHEMIAH; 721 cpuname = "C3 'Nehemiah A' [C5XLOE]"; 722 break; 723 case 2 ... 4: 724 cpu_model = CPU_NEHEMIAH; 725 cpuname = "C3 'Nehemiah B' [C5XLOH]"; 726 break; 727 case 5 ... 15: 728 cpu_model = CPU_NEHEMIAH_C; 729 cpuname = "C3 'Nehemiah C' [C5P]"; 730 break; 731 } 732 break; 733 734 default: 735 cpuname = "Unknown"; 736 break; 737 } 738 /* Check Longhaul ver. 2 */ 739 if (longhaul_version == TYPE_LONGHAUL_V2) { 740 rdmsr(MSR_VIA_LONGHAUL, lo, hi); 741 if (lo == 0 && hi == 0) 742 /* Looks like MSR isn't present */ 743 longhaul_version = TYPE_LONGHAUL_V1; 744 } 745 746 printk (KERN_INFO PFX "VIA %s CPU detected. ", cpuname); 747 switch (longhaul_version) { 748 case TYPE_LONGHAUL_V1: 749 case TYPE_LONGHAUL_V2: 750 printk ("Longhaul v%d supported.\n", longhaul_version); 751 break; 752 case TYPE_POWERSAVER: 753 printk ("Powersaver supported.\n"); 754 break; 755 }; 756 757 /* Doesn't hurt */ 758 vt8235_present = longhaul_setup_vt8235(); 759 760 /* Find ACPI data for processor */ 761 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 762 ACPI_UINT32_MAX, &longhaul_walk_callback, 763 NULL, (void *)&pr); 764 765 /* Check ACPI support for C3 state */ 766 if (pr != NULL && longhaul_version == TYPE_POWERSAVER) { 767 cx = &pr->power.states[ACPI_STATE_C3]; 768 if (cx->address > 0 && cx->latency <= 1000) { 769 longhaul_flags |= USE_ACPI_C3; 770 goto print_support_type; 771 } 772 } 773 /* Check if northbridge is friendly */ 774 if (enable_arbiter_disable()) { 775 longhaul_flags |= USE_NORTHBRIDGE; 776 goto print_support_type; 777 } 778 /* Use VT8235 southbridge if present */ 779 if (longhaul_version == TYPE_POWERSAVER && vt8235_present) { 780 longhaul_flags |= USE_VT8235; 781 goto print_support_type; 782 } 783 /* Check ACPI support for bus master arbiter disable */ 784 if ((pr == NULL) || !(pr->flags.bm_control)) { 785 printk(KERN_ERR PFX 786 "No ACPI support. Unsupported northbridge.\n"); 787 return -ENODEV; 788 } 789 790print_support_type: 791 if (longhaul_flags & USE_NORTHBRIDGE) 792 printk (KERN_INFO PFX "Using northbridge support.\n"); 793 else if (longhaul_flags & USE_VT8235) 794 printk (KERN_INFO PFX "Using VT8235 support.\n"); 795 else 796 printk (KERN_INFO PFX "Using ACPI support.\n"); 797 798 ret = longhaul_get_ranges(); 799 if (ret != 0) 800 return ret; 801 802 if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) 803 longhaul_setup_voltagescaling(); 804 805 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 806 policy->cpuinfo.transition_latency = 200000; /* nsec */ 807 policy->cur = calc_speed(longhaul_get_cpu_mult()); 808 809 ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); 810 if (ret) 811 return ret; 812 813 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); 814 815 return 0; 816} 817 818static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) 819{ 820 cpufreq_frequency_table_put_attr(policy->cpu); 821 return 0; 822} 823 824static struct freq_attr* longhaul_attr[] = { 825 &cpufreq_freq_attr_scaling_available_freqs, 826 NULL, 827}; 828 829static struct cpufreq_driver longhaul_driver = { 830 .verify = longhaul_verify, 831 .target = longhaul_target, 832 .get = longhaul_get, 833 .init = longhaul_cpu_init, 834 .exit = __devexit_p(longhaul_cpu_exit), 835 .name = "longhaul", 836 .owner = THIS_MODULE, 837 .attr = longhaul_attr, 838}; 839 840 841static int __init longhaul_init(void) 842{ 843 struct cpuinfo_x86 *c = cpu_data; 844 845 if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6) 846 return -ENODEV; 847 848#ifdef CONFIG_SMP 849 if (num_online_cpus() > 1) { 850 printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); 851 return -ENODEV; 852 } 853#endif 854#ifdef CONFIG_X86_IO_APIC 855 if (cpu_has_apic) { 856 printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n"); 857 return -ENODEV; 858 } 859#endif 860 switch (c->x86_model) { 861 case 6 ... 9: 862 return cpufreq_register_driver(&longhaul_driver); 863 case 10: 864 printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n"); 865 default: 866 ;; 867 } 868 869 return -ENODEV; 870} 871 872 873static void __exit longhaul_exit(void) 874{ 875 int i; 876 877 for (i=0; i < numscales; i++) { 878 if (clock_ratio[i] == maxmult) { 879 longhaul_setstate(i); 880 break; 881 } 882 } 883 884 cpufreq_unregister_driver(&longhaul_driver); 885 kfree(longhaul_table); 886} 887 888module_param (scale_voltage, int, 0644); 889MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); 890 891MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); 892MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); 893MODULE_LICENSE ("GPL"); 894 895late_initcall(longhaul_init); 896module_exit(longhaul_exit); 897