• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/x86/kernel/cpu/cpufreq/
1/*
2 *  (C) 2001-2004  Dave Jones. <davej@redhat.com>
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#include <linux/delay.h>
33#include <linux/timex.h>
34#include <linux/io.h>
35#include <linux/acpi.h>
36
37#include <asm/msr.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
59static int cpu_model;
60static unsigned int numscales = 16;
61static unsigned int fsb;
62
63static const struct mV_pos *vrm_mV_table;
64static const unsigned char *mV_vrm_table;
65
66static unsigned int highest_speed, lowest_speed; /* kHz */
67static unsigned int minmult, maxmult;
68static int can_scale_voltage;
69static struct acpi_processor *pr;
70static struct acpi_processor_cx *cx;
71static u32 acpi_regs_addr;
72static u8 longhaul_flags;
73static unsigned int longhaul_index;
74
75/* Module parameters */
76static int scale_voltage;
77static int disable_acpi_c3;
78static int revid_errata;
79
80#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
81		"longhaul", msg)
82
83
84/* Clock ratios multiplied by 10 */
85static int mults[32];
86static int eblcr[32];
87static int longhaul_version;
88static struct cpufreq_frequency_table *longhaul_table;
89
90#ifdef CONFIG_CPU_FREQ_DEBUG
91static char speedbuffer[8];
92
93static char *print_speed(int speed)
94{
95	if (speed < 1000) {
96		snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed);
97		return speedbuffer;
98	}
99
100	if (speed%1000 == 0)
101		snprintf(speedbuffer, sizeof(speedbuffer),
102			"%dGHz", speed/1000);
103	else
104		snprintf(speedbuffer, sizeof(speedbuffer),
105			"%d.%dGHz", speed/1000, (speed%1000)/100);
106
107	return speedbuffer;
108}
109#endif
110
111
112static unsigned int calc_speed(int mult)
113{
114	int khz;
115	khz = (mult/10)*fsb;
116	if (mult%10)
117		khz += fsb/2;
118	khz *= 1000;
119	return khz;
120}
121
122
123static int longhaul_get_cpu_mult(void)
124{
125	unsigned long invalue = 0, lo, hi;
126
127	rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi);
128	invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22;
129	if (longhaul_version == TYPE_LONGHAUL_V2 ||
130	    longhaul_version == TYPE_POWERSAVER) {
131		if (lo & (1<<27))
132			invalue += 16;
133	}
134	return eblcr[invalue];
135}
136
137/* For processor with BCR2 MSR */
138
139static void do_longhaul1(unsigned int mults_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 = mults_index & 0xff;
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
165static void do_powersaver(int cx_address, unsigned int mults_index,
166			  unsigned int dir)
167{
168	union msr_longhaul longhaul;
169	u32 t;
170
171	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
172	/* Setup new frequency */
173	if (!revid_errata)
174		longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
175	else
176		longhaul.bits.RevisionKey = 0;
177	longhaul.bits.SoftBusRatio = mults_index & 0xf;
178	longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4;
179	/* Setup new voltage */
180	if (can_scale_voltage)
181		longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f;
182	/* Sync to timer tick */
183	safe_halt();
184	/* Raise voltage if necessary */
185	if (can_scale_voltage && dir) {
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	}
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 && !dir) {
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	}
240}
241
242/**
243 * longhaul_set_cpu_frequency()
244 * @mults_index : bitpattern of the new multiplier.
245 *
246 * Sets a new clock ratio.
247 */
248
249static void longhaul_setstate(unsigned int table_index)
250{
251	unsigned int mults_index;
252	int speed, mult;
253	struct cpufreq_freqs freqs;
254	unsigned long flags;
255	unsigned int pic1_mask, pic2_mask;
256	u16 bm_status = 0;
257	u32 bm_timeout = 1000;
258	unsigned int dir = 0;
259
260	mults_index = longhaul_table[table_index].index;
261	/* Safety precautions */
262	mult = mults[mults_index & 0x1f];
263	if (mult == -1)
264		return;
265	speed = calc_speed(mult);
266	if ((speed > highest_speed) || (speed < lowest_speed))
267		return;
268	/* Voltage transition before frequency transition? */
269	if (can_scale_voltage && longhaul_index < table_index)
270		dir = 1;
271
272	freqs.old = calc_speed(longhaul_get_cpu_mult());
273	freqs.new = speed;
274	freqs.cpu = 0; /* longhaul.c is UP only driver */
275
276	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
277
278	dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
279			fsb, mult/10, mult%10, print_speed(speed/1000));
280retry_loop:
281	preempt_disable();
282	local_irq_save(flags);
283
284	pic2_mask = inb(0xA1);
285	pic1_mask = inb(0x21);	/* works on C3. save mask. */
286	outb(0xFF, 0xA1);	/* Overkill */
287	outb(0xFE, 0x21);	/* TMR0 only */
288
289	/* Wait while PCI bus is busy. */
290	if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
291	    || ((pr != NULL) && pr->flags.bm_control))) {
292		bm_status = inw(acpi_regs_addr);
293		bm_status &= 1 << 4;
294		while (bm_status && bm_timeout) {
295			outw(1 << 4, acpi_regs_addr);
296			bm_timeout--;
297			bm_status = inw(acpi_regs_addr);
298			bm_status &= 1 << 4;
299		}
300	}
301
302	if (longhaul_flags & USE_NORTHBRIDGE) {
303		/* Disable AGP and PCI arbiters */
304		outb(3, 0x22);
305	} else if ((pr != NULL) && pr->flags.bm_control) {
306		/* Disable bus master arbitration */
307		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
308	}
309	switch (longhaul_version) {
310
311	/*
312	 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
313	 * Software controlled multipliers only.
314	 */
315	case TYPE_LONGHAUL_V1:
316		do_longhaul1(mults_index);
317		break;
318
319	/*
320	 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C]
321	 *
322	 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N])
323	 * Nehemiah can do FSB scaling too, but this has never been proven
324	 * to work in practice.
325	 */
326	case TYPE_LONGHAUL_V2:
327	case TYPE_POWERSAVER:
328		if (longhaul_flags & USE_ACPI_C3) {
329			/* Don't allow wakeup */
330			acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
331			do_powersaver(cx->address, mults_index, dir);
332		} else {
333			do_powersaver(0, mults_index, dir);
334		}
335		break;
336	}
337
338	if (longhaul_flags & USE_NORTHBRIDGE) {
339		/* Enable arbiters */
340		outb(0, 0x22);
341	} else if ((pr != NULL) && pr->flags.bm_control) {
342		/* Enable bus master arbitration */
343		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
344	}
345	outb(pic2_mask, 0xA1);	/* restore mask */
346	outb(pic1_mask, 0x21);
347
348	local_irq_restore(flags);
349	preempt_enable();
350
351	freqs.new = calc_speed(longhaul_get_cpu_mult());
352	/* Check if requested frequency is set. */
353	if (unlikely(freqs.new != speed)) {
354		printk(KERN_INFO PFX "Failed to set requested frequency!\n");
355		/* Revision ID = 1 but processor is expecting revision key
356		 * equal to 0. Jumpers at the bottom of processor will change
357		 * multiplier and FSB, but will not change bits in Longhaul
358		 * MSR nor enable voltage scaling. */
359		if (!revid_errata) {
360			printk(KERN_INFO PFX "Enabling \"Ignore Revision ID\" "
361						"option.\n");
362			revid_errata = 1;
363			msleep(200);
364			goto retry_loop;
365		}
366		/* Why ACPI C3 sometimes doesn't work is a mystery for me.
367		 * But it does happen. Processor is entering ACPI C3 state,
368		 * but it doesn't change frequency. I tried poking various
369		 * bits in northbridge registers, but without success. */
370		if (longhaul_flags & USE_ACPI_C3) {
371			printk(KERN_INFO PFX "Disabling ACPI C3 support.\n");
372			longhaul_flags &= ~USE_ACPI_C3;
373			if (revid_errata) {
374				printk(KERN_INFO PFX "Disabling \"Ignore "
375						"Revision ID\" option.\n");
376				revid_errata = 0;
377			}
378			msleep(200);
379			goto retry_loop;
380		}
381		/* This shouldn't happen. Longhaul ver. 2 was reported not
382		 * working on processors without voltage scaling, but with
383		 * RevID = 1. RevID errata will make things right. Just
384		 * to be 100% sure. */
385		if (longhaul_version == TYPE_LONGHAUL_V2) {
386			printk(KERN_INFO PFX "Switching to Longhaul ver. 1\n");
387			longhaul_version = TYPE_LONGHAUL_V1;
388			msleep(200);
389			goto retry_loop;
390		}
391	}
392	/* Report true CPU frequency */
393	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
394
395	if (!bm_timeout)
396		printk(KERN_INFO PFX "Warning: Timeout while waiting for "
397				"idle PCI bus.\n");
398}
399
400/*
401 * Centaur decided to make life a little more tricky.
402 * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
403 * Samuel2 and above have to try and guess what the FSB is.
404 * We do this by assuming we booted at maximum multiplier, and interpolate
405 * between that value multiplied by possible FSBs and cpu_mhz which
406 * was calculated at boot time. Really ugly, but no other way to do this.
407 */
408
409#define ROUNDING	0xf
410
411static int guess_fsb(int mult)
412{
413	int speed = cpu_khz / 1000;
414	int i;
415	int speeds[] = { 666, 1000, 1333, 2000 };
416	int f_max, f_min;
417
418	for (i = 0; i < 4; i++) {
419		f_max = ((speeds[i] * mult) + 50) / 100;
420		f_max += (ROUNDING / 2);
421		f_min = f_max - ROUNDING;
422		if ((speed <= f_max) && (speed >= f_min))
423			return speeds[i] / 10;
424	}
425	return 0;
426}
427
428
429static int __cpuinit longhaul_get_ranges(void)
430{
431	unsigned int i, j, k = 0;
432	unsigned int ratio;
433	int mult;
434
435	/* Get current frequency */
436	mult = longhaul_get_cpu_mult();
437	if (mult == -1) {
438		printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n");
439		return -EINVAL;
440	}
441	fsb = guess_fsb(mult);
442	if (fsb == 0) {
443		printk(KERN_INFO PFX "Invalid (reserved) FSB!\n");
444		return -EINVAL;
445	}
446	/* Get max multiplier - as we always did.
447	 * Longhaul MSR is usefull only when voltage scaling is enabled.
448	 * C3 is booting at max anyway. */
449	maxmult = mult;
450	/* Get min multiplier */
451	switch (cpu_model) {
452	case CPU_NEHEMIAH:
453		minmult = 50;
454		break;
455	case CPU_NEHEMIAH_C:
456		minmult = 40;
457		break;
458	default:
459		minmult = 30;
460		break;
461	}
462
463	dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n",
464		 minmult/10, minmult%10, maxmult/10, maxmult%10);
465
466	highest_speed = calc_speed(maxmult);
467	lowest_speed = calc_speed(minmult);
468	dprintk("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
469		 print_speed(lowest_speed/1000),
470		 print_speed(highest_speed/1000));
471
472	if (lowest_speed == highest_speed) {
473		printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n");
474		return -EINVAL;
475	}
476	if (lowest_speed > highest_speed) {
477		printk(KERN_INFO PFX "nonsense! lowest (%d > %d) !\n",
478			lowest_speed, highest_speed);
479		return -EINVAL;
480	}
481
482	longhaul_table = kmalloc((numscales + 1) * sizeof(*longhaul_table),
483			GFP_KERNEL);
484	if (!longhaul_table)
485		return -ENOMEM;
486
487	for (j = 0; j < numscales; j++) {
488		ratio = mults[j];
489		if (ratio == -1)
490			continue;
491		if (ratio > maxmult || ratio < minmult)
492			continue;
493		longhaul_table[k].frequency = calc_speed(ratio);
494		longhaul_table[k].index	= j;
495		k++;
496	}
497	if (k <= 1) {
498		kfree(longhaul_table);
499		return -ENODEV;
500	}
501	/* Sort */
502	for (j = 0; j < k - 1; j++) {
503		unsigned int min_f, min_i;
504		min_f = longhaul_table[j].frequency;
505		min_i = j;
506		for (i = j + 1; i < k; i++) {
507			if (longhaul_table[i].frequency < min_f) {
508				min_f = longhaul_table[i].frequency;
509				min_i = i;
510			}
511		}
512		if (min_i != j) {
513			swap(longhaul_table[j].frequency,
514			     longhaul_table[min_i].frequency);
515			swap(longhaul_table[j].index,
516			     longhaul_table[min_i].index);
517		}
518	}
519
520	longhaul_table[k].frequency = CPUFREQ_TABLE_END;
521
522	/* Find index we are running on */
523	for (j = 0; j < k; j++) {
524		if (mults[longhaul_table[j].index & 0x1f] == mult) {
525			longhaul_index = j;
526			break;
527		}
528	}
529	return 0;
530}
531
532
533static void __cpuinit longhaul_setup_voltagescaling(void)
534{
535	union msr_longhaul longhaul;
536	struct mV_pos minvid, maxvid, vid;
537	unsigned int j, speed, pos, kHz_step, numvscales;
538	int min_vid_speed;
539
540	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
541	if (!(longhaul.bits.RevisionID & 1)) {
542		printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");
543		return;
544	}
545
546	if (!longhaul.bits.VRMRev) {
547		printk(KERN_INFO PFX "VRM 8.5\n");
548		vrm_mV_table = &vrm85_mV[0];
549		mV_vrm_table = &mV_vrm85[0];
550	} else {
551		printk(KERN_INFO PFX "Mobile VRM\n");
552		if (cpu_model < CPU_NEHEMIAH)
553			return;
554		vrm_mV_table = &mobilevrm_mV[0];
555		mV_vrm_table = &mV_mobilevrm[0];
556	}
557
558	minvid = vrm_mV_table[longhaul.bits.MinimumVID];
559	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
560
561	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
562		printk(KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
563					"Voltage scaling disabled.\n",
564					minvid.mV/1000, minvid.mV%1000,
565					maxvid.mV/1000, maxvid.mV%1000);
566		return;
567	}
568
569	if (minvid.mV == maxvid.mV) {
570		printk(KERN_INFO PFX "Claims to support voltage scaling but "
571				"min & max are both %d.%03d. "
572				"Voltage scaling disabled\n",
573				maxvid.mV/1000, maxvid.mV%1000);
574		return;
575	}
576
577	/* How many voltage steps*/
578	numvscales = maxvid.pos - minvid.pos + 1;
579	printk(KERN_INFO PFX
580		"Max VID=%d.%03d  "
581		"Min VID=%d.%03d, "
582		"%d possible voltage scales\n",
583		maxvid.mV/1000, maxvid.mV%1000,
584		minvid.mV/1000, minvid.mV%1000,
585		numvscales);
586
587	/* Calculate max frequency at min voltage */
588	j = longhaul.bits.MinMHzBR;
589	if (longhaul.bits.MinMHzBR4)
590		j += 16;
591	min_vid_speed = eblcr[j];
592	if (min_vid_speed == -1)
593		return;
594	switch (longhaul.bits.MinMHzFSB) {
595	case 0:
596		min_vid_speed *= 13333;
597		break;
598	case 1:
599		min_vid_speed *= 10000;
600		break;
601	case 3:
602		min_vid_speed *= 6666;
603		break;
604	default:
605		return;
606		break;
607	}
608	if (min_vid_speed >= highest_speed)
609		return;
610	/* Calculate kHz for one voltage step */
611	kHz_step = (highest_speed - min_vid_speed) / numvscales;
612
613	j = 0;
614	while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
615		speed = longhaul_table[j].frequency;
616		if (speed > min_vid_speed)
617			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
618		else
619			pos = minvid.pos;
620		longhaul_table[j].index |= mV_vrm_table[pos] << 8;
621		vid = vrm_mV_table[mV_vrm_table[pos]];
622		printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
623				speed, j, vid.mV);
624		j++;
625	}
626
627	can_scale_voltage = 1;
628	printk(KERN_INFO PFX "Voltage scaling enabled.\n");
629}
630
631
632static int longhaul_verify(struct cpufreq_policy *policy)
633{
634	return cpufreq_frequency_table_verify(policy, longhaul_table);
635}
636
637
638static int longhaul_target(struct cpufreq_policy *policy,
639			    unsigned int target_freq, unsigned int relation)
640{
641	unsigned int table_index = 0;
642	unsigned int i;
643	unsigned int dir = 0;
644	u8 vid, current_vid;
645
646	if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq,
647				relation, &table_index))
648		return -EINVAL;
649
650	/* Don't set same frequency again */
651	if (longhaul_index == table_index)
652		return 0;
653
654	if (!can_scale_voltage)
655		longhaul_setstate(table_index);
656	else {
657		/* On test system voltage transitions exceeding single
658		 * step up or down were turning motherboard off. Both
659		 * "ondemand" and "userspace" are unsafe. C7 is doing
660		 * this in hardware, C3 is old and we need to do this
661		 * in software. */
662		i = longhaul_index;
663		current_vid = (longhaul_table[longhaul_index].index >> 8);
664		current_vid &= 0x1f;
665		if (table_index > longhaul_index)
666			dir = 1;
667		while (i != table_index) {
668			vid = (longhaul_table[i].index >> 8) & 0x1f;
669			if (vid != current_vid) {
670				longhaul_setstate(i);
671				current_vid = vid;
672				msleep(200);
673			}
674			if (dir)
675				i++;
676			else
677				i--;
678		}
679		longhaul_setstate(table_index);
680	}
681	longhaul_index = table_index;
682	return 0;
683}
684
685
686static unsigned int longhaul_get(unsigned int cpu)
687{
688	if (cpu)
689		return 0;
690	return calc_speed(longhaul_get_cpu_mult());
691}
692
693static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
694					  u32 nesting_level,
695					  void *context, void **return_value)
696{
697	struct acpi_device *d;
698
699	if (acpi_bus_get_device(obj_handle, &d))
700		return 0;
701
702	*return_value = acpi_driver_data(d);
703	return 1;
704}
705
706/* VIA don't support PM2 reg, but have something similar */
707static int enable_arbiter_disable(void)
708{
709	struct pci_dev *dev;
710	int status = 1;
711	int reg;
712	u8 pci_cmd;
713
714	/* Find PLE133 host bridge */
715	reg = 0x78;
716	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
717			     NULL);
718	/* Find PM133/VT8605 host bridge */
719	if (dev == NULL)
720		dev = pci_get_device(PCI_VENDOR_ID_VIA,
721				     PCI_DEVICE_ID_VIA_8605_0, NULL);
722	/* Find CLE266 host bridge */
723	if (dev == NULL) {
724		reg = 0x76;
725		dev = pci_get_device(PCI_VENDOR_ID_VIA,
726				     PCI_DEVICE_ID_VIA_862X_0, NULL);
727		/* Find CN400 V-Link host bridge */
728		if (dev == NULL)
729			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
730	}
731	if (dev != NULL) {
732		/* Enable access to port 0x22 */
733		pci_read_config_byte(dev, reg, &pci_cmd);
734		if (!(pci_cmd & 1<<7)) {
735			pci_cmd |= 1<<7;
736			pci_write_config_byte(dev, reg, pci_cmd);
737			pci_read_config_byte(dev, reg, &pci_cmd);
738			if (!(pci_cmd & 1<<7)) {
739				printk(KERN_ERR PFX
740					"Can't enable access to port 0x22.\n");
741				status = 0;
742			}
743		}
744		pci_dev_put(dev);
745		return status;
746	}
747	return 0;
748}
749
750static int longhaul_setup_southbridge(void)
751{
752	struct pci_dev *dev;
753	u8 pci_cmd;
754
755	/* Find VT8235 southbridge */
756	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
757	if (dev == NULL)
758		/* Find VT8237 southbridge */
759		dev = pci_get_device(PCI_VENDOR_ID_VIA,
760				     PCI_DEVICE_ID_VIA_8237, NULL);
761	if (dev != NULL) {
762		/* Set transition time to max */
763		pci_read_config_byte(dev, 0xec, &pci_cmd);
764		pci_cmd &= ~(1 << 2);
765		pci_write_config_byte(dev, 0xec, pci_cmd);
766		pci_read_config_byte(dev, 0xe4, &pci_cmd);
767		pci_cmd &= ~(1 << 7);
768		pci_write_config_byte(dev, 0xe4, pci_cmd);
769		pci_read_config_byte(dev, 0xe5, &pci_cmd);
770		pci_cmd |= 1 << 7;
771		pci_write_config_byte(dev, 0xe5, pci_cmd);
772		/* Get address of ACPI registers block*/
773		pci_read_config_byte(dev, 0x81, &pci_cmd);
774		if (pci_cmd & 1 << 7) {
775			pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
776			acpi_regs_addr &= 0xff00;
777			printk(KERN_INFO PFX "ACPI I/O at 0x%x\n",
778					acpi_regs_addr);
779		}
780
781		pci_dev_put(dev);
782		return 1;
783	}
784	return 0;
785}
786
787static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy)
788{
789	struct cpuinfo_x86 *c = &cpu_data(0);
790	char *cpuname = NULL;
791	int ret;
792	u32 lo, hi;
793
794	/* Check what we have on this motherboard */
795	switch (c->x86_model) {
796	case 6:
797		cpu_model = CPU_SAMUEL;
798		cpuname = "C3 'Samuel' [C5A]";
799		longhaul_version = TYPE_LONGHAUL_V1;
800		memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
801		memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));
802		break;
803
804	case 7:
805		switch (c->x86_mask) {
806		case 0:
807			longhaul_version = TYPE_LONGHAUL_V1;
808			cpu_model = CPU_SAMUEL2;
809			cpuname = "C3 'Samuel 2' [C5B]";
810			/* Note, this is not a typo, early Samuel2's had
811			 * Samuel1 ratios. */
812			memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
813			memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));
814			break;
815		case 1 ... 15:
816			longhaul_version = TYPE_LONGHAUL_V2;
817			if (c->x86_mask < 8) {
818				cpu_model = CPU_SAMUEL2;
819				cpuname = "C3 'Samuel 2' [C5B]";
820			} else {
821				cpu_model = CPU_EZRA;
822				cpuname = "C3 'Ezra' [C5C]";
823			}
824			memcpy(mults, ezra_mults, sizeof(ezra_mults));
825			memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));
826			break;
827		}
828		break;
829
830	case 8:
831		cpu_model = CPU_EZRA_T;
832		cpuname = "C3 'Ezra-T' [C5M]";
833		longhaul_version = TYPE_POWERSAVER;
834		numscales = 32;
835		memcpy(mults, ezrat_mults, sizeof(ezrat_mults));
836		memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));
837		break;
838
839	case 9:
840		longhaul_version = TYPE_POWERSAVER;
841		numscales = 32;
842		memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
843		memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
844		switch (c->x86_mask) {
845		case 0 ... 1:
846			cpu_model = CPU_NEHEMIAH;
847			cpuname = "C3 'Nehemiah A' [C5XLOE]";
848			break;
849		case 2 ... 4:
850			cpu_model = CPU_NEHEMIAH;
851			cpuname = "C3 'Nehemiah B' [C5XLOH]";
852			break;
853		case 5 ... 15:
854			cpu_model = CPU_NEHEMIAH_C;
855			cpuname = "C3 'Nehemiah C' [C5P]";
856			break;
857		}
858		break;
859
860	default:
861		cpuname = "Unknown";
862		break;
863	}
864	/* Check Longhaul ver. 2 */
865	if (longhaul_version == TYPE_LONGHAUL_V2) {
866		rdmsr(MSR_VIA_LONGHAUL, lo, hi);
867		if (lo == 0 && hi == 0)
868			/* Looks like MSR isn't present */
869			longhaul_version = TYPE_LONGHAUL_V1;
870	}
871
872	printk(KERN_INFO PFX "VIA %s CPU detected.  ", cpuname);
873	switch (longhaul_version) {
874	case TYPE_LONGHAUL_V1:
875	case TYPE_LONGHAUL_V2:
876		printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version);
877		break;
878	case TYPE_POWERSAVER:
879		printk(KERN_CONT "Powersaver supported.\n");
880		break;
881	};
882
883	/* Doesn't hurt */
884	longhaul_setup_southbridge();
885
886	/* Find ACPI data for processor */
887	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
888				ACPI_UINT32_MAX, &longhaul_walk_callback, NULL,
889				NULL, (void *)&pr);
890
891	/* Check ACPI support for C3 state */
892	if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {
893		cx = &pr->power.states[ACPI_STATE_C3];
894		if (cx->address > 0 && cx->latency <= 1000)
895			longhaul_flags |= USE_ACPI_C3;
896	}
897	/* Disable if it isn't working */
898	if (disable_acpi_c3)
899		longhaul_flags &= ~USE_ACPI_C3;
900	/* Check if northbridge is friendly */
901	if (enable_arbiter_disable())
902		longhaul_flags |= USE_NORTHBRIDGE;
903
904	/* Check ACPI support for bus master arbiter disable */
905	if (!(longhaul_flags & USE_ACPI_C3
906	     || longhaul_flags & USE_NORTHBRIDGE)
907	    && ((pr == NULL) || !(pr->flags.bm_control))) {
908		printk(KERN_ERR PFX
909			"No ACPI support. Unsupported northbridge.\n");
910		return -ENODEV;
911	}
912
913	if (longhaul_flags & USE_NORTHBRIDGE)
914		printk(KERN_INFO PFX "Using northbridge support.\n");
915	if (longhaul_flags & USE_ACPI_C3)
916		printk(KERN_INFO PFX "Using ACPI support.\n");
917
918	ret = longhaul_get_ranges();
919	if (ret != 0)
920		return ret;
921
922	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
923		longhaul_setup_voltagescaling();
924
925	policy->cpuinfo.transition_latency = 200000;	/* nsec */
926	policy->cur = calc_speed(longhaul_get_cpu_mult());
927
928	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
929	if (ret)
930		return ret;
931
932	cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
933
934	return 0;
935}
936
937static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
938{
939	cpufreq_frequency_table_put_attr(policy->cpu);
940	return 0;
941}
942
943static struct freq_attr *longhaul_attr[] = {
944	&cpufreq_freq_attr_scaling_available_freqs,
945	NULL,
946};
947
948static struct cpufreq_driver longhaul_driver = {
949	.verify	= longhaul_verify,
950	.target	= longhaul_target,
951	.get	= longhaul_get,
952	.init	= longhaul_cpu_init,
953	.exit	= __devexit_p(longhaul_cpu_exit),
954	.name	= "longhaul",
955	.owner	= THIS_MODULE,
956	.attr	= longhaul_attr,
957};
958
959
960static int __init longhaul_init(void)
961{
962	struct cpuinfo_x86 *c = &cpu_data(0);
963
964	if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
965		return -ENODEV;
966
967#ifdef CONFIG_SMP
968	if (num_online_cpus() > 1) {
969		printk(KERN_ERR PFX "More than 1 CPU detected, "
970				"longhaul disabled.\n");
971		return -ENODEV;
972	}
973#endif
974#ifdef CONFIG_X86_IO_APIC
975	if (cpu_has_apic) {
976		printk(KERN_ERR PFX "APIC detected. Longhaul is currently "
977				"broken in this configuration.\n");
978		return -ENODEV;
979	}
980#endif
981	switch (c->x86_model) {
982	case 6 ... 9:
983		return cpufreq_register_driver(&longhaul_driver);
984	case 10:
985		printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n");
986	default:
987		;
988	}
989
990	return -ENODEV;
991}
992
993
994static void __exit longhaul_exit(void)
995{
996	int i;
997
998	for (i = 0; i < numscales; i++) {
999		if (mults[i] == maxmult) {
1000			longhaul_setstate(i);
1001			break;
1002		}
1003	}
1004
1005	cpufreq_unregister_driver(&longhaul_driver);
1006	kfree(longhaul_table);
1007}
1008
1009/* Even if BIOS is exporting ACPI C3 state, and it is used
1010 * with success when CPU is idle, this state doesn't
1011 * trigger frequency transition in some cases. */
1012module_param(disable_acpi_c3, int, 0644);
1013MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
1014/* Change CPU voltage with frequency. Very usefull to save
1015 * power, but most VIA C3 processors aren't supporting it. */
1016module_param(scale_voltage, int, 0644);
1017MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
1018/* Force revision key to 0 for processors which doesn't
1019 * support voltage scaling, but are introducing itself as
1020 * such. */
1021module_param(revid_errata, int, 0644);
1022MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
1023
1024MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
1025MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
1026MODULE_LICENSE("GPL");
1027
1028late_initcall(longhaul_init);
1029module_exit(longhaul_exit);
1030