• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/linux/linux-2.6/arch/i386/kernel/cpu/cpufreq/
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