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