xref: /openbmc/linux/drivers/cpufreq/powernow-k7.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
14f19048fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bb0a56ecSDave Jones /*
3bb0a56ecSDave Jones  *  AMD K7 Powernow driver.
4bb0a56ecSDave Jones  *  (C) 2003 Dave Jones on behalf of SuSE Labs.
5bb0a56ecSDave Jones  *
6bb0a56ecSDave Jones  *  Based upon datasheets & sample CPUs kindly provided by AMD.
7bb0a56ecSDave Jones  *
8bb0a56ecSDave Jones  * Errata 5:
9bb0a56ecSDave Jones  *  CPU may fail to execute a FID/VID change in presence of interrupt.
10bb0a56ecSDave Jones  *  - We cli/sti on stepping A0 CPUs around the FID/VID transition.
11bb0a56ecSDave Jones  * Errata 15:
12bb0a56ecSDave Jones  *  CPU with half frequency multipliers may hang upon wakeup from disconnect.
13bb0a56ecSDave Jones  *  - We disable half multipliers if ACPI is used on A0 stepping CPUs.
14bb0a56ecSDave Jones  */
15bb0a56ecSDave Jones 
161c5864e2SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
171c5864e2SJoe Perches 
18bb0a56ecSDave Jones #include <linux/kernel.h>
19bb0a56ecSDave Jones #include <linux/module.h>
20bb0a56ecSDave Jones #include <linux/moduleparam.h>
21bb0a56ecSDave Jones #include <linux/init.h>
22bb0a56ecSDave Jones #include <linux/cpufreq.h>
23bb0a56ecSDave Jones #include <linux/slab.h>
24bb0a56ecSDave Jones #include <linux/string.h>
25bb0a56ecSDave Jones #include <linux/dmi.h>
26bb0a56ecSDave Jones #include <linux/timex.h>
27bb0a56ecSDave Jones #include <linux/io.h>
28bb0a56ecSDave Jones 
29bb0a56ecSDave Jones #include <asm/timer.h>		/* Needed for recalibrate_cpu_khz() */
30bb0a56ecSDave Jones #include <asm/msr.h>
31fa8031aeSAndi Kleen #include <asm/cpu_device_id.h>
32bb0a56ecSDave Jones 
33bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
34bb0a56ecSDave Jones #include <linux/acpi.h>
35bb0a56ecSDave Jones #include <acpi/processor.h>
36bb0a56ecSDave Jones #endif
37bb0a56ecSDave Jones 
38bb0a56ecSDave Jones #include "powernow-k7.h"
39bb0a56ecSDave Jones 
40bb0a56ecSDave Jones struct psb_s {
41bb0a56ecSDave Jones 	u8 signature[10];
42bb0a56ecSDave Jones 	u8 tableversion;
43bb0a56ecSDave Jones 	u8 flags;
44bb0a56ecSDave Jones 	u16 settlingtime;
45bb0a56ecSDave Jones 	u8 reserved1;
46bb0a56ecSDave Jones 	u8 numpst;
47bb0a56ecSDave Jones };
48bb0a56ecSDave Jones 
49bb0a56ecSDave Jones struct pst_s {
50bb0a56ecSDave Jones 	u32 cpuid;
51bb0a56ecSDave Jones 	u8 fsbspeed;
52bb0a56ecSDave Jones 	u8 maxfid;
53bb0a56ecSDave Jones 	u8 startvid;
54bb0a56ecSDave Jones 	u8 numpstates;
55bb0a56ecSDave Jones };
56bb0a56ecSDave Jones 
57bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
58bb0a56ecSDave Jones union powernow_acpi_control_t {
59bb0a56ecSDave Jones 	struct {
60bb0a56ecSDave Jones 		unsigned long fid:5,
61bb0a56ecSDave Jones 			vid:5,
62bb0a56ecSDave Jones 			sgtc:20,
63bb0a56ecSDave Jones 			res1:2;
64bb0a56ecSDave Jones 	} bits;
65bb0a56ecSDave Jones 	unsigned long val;
66bb0a56ecSDave Jones };
67bb0a56ecSDave Jones #endif
68bb0a56ecSDave Jones 
69bb0a56ecSDave Jones /* divide by 1000 to get VCore voltage in V. */
70bb0a56ecSDave Jones static const int mobile_vid_table[32] = {
71bb0a56ecSDave Jones     2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
72bb0a56ecSDave Jones     1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
73bb0a56ecSDave Jones     1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
74bb0a56ecSDave Jones     1075, 1050, 1025, 1000, 975, 950, 925, 0,
75bb0a56ecSDave Jones };
76bb0a56ecSDave Jones 
77bb0a56ecSDave Jones /* divide by 10 to get FID. */
78bb0a56ecSDave Jones static const int fid_codes[32] = {
79bb0a56ecSDave Jones     110, 115, 120, 125, 50, 55, 60, 65,
80bb0a56ecSDave Jones     70, 75, 80, 85, 90, 95, 100, 105,
81bb0a56ecSDave Jones     30, 190, 40, 200, 130, 135, 140, 210,
82bb0a56ecSDave Jones     150, 225, 160, 165, 170, 180, -1, -1,
83bb0a56ecSDave Jones };
84bb0a56ecSDave Jones 
85bb0a56ecSDave Jones /* This parameter is used in order to force ACPI instead of legacy method for
86bb0a56ecSDave Jones  * configuration purpose.
87bb0a56ecSDave Jones  */
88bb0a56ecSDave Jones 
89bb0a56ecSDave Jones static int acpi_force;
90bb0a56ecSDave Jones 
91bb0a56ecSDave Jones static struct cpufreq_frequency_table *powernow_table;
92bb0a56ecSDave Jones 
93bb0a56ecSDave Jones static unsigned int can_scale_bus;
94bb0a56ecSDave Jones static unsigned int can_scale_vid;
95bb0a56ecSDave Jones static unsigned int minimum_speed = -1;
96bb0a56ecSDave Jones static unsigned int maximum_speed;
97bb0a56ecSDave Jones static unsigned int number_scales;
98bb0a56ecSDave Jones static unsigned int fsb;
99bb0a56ecSDave Jones static unsigned int latency;
100bb0a56ecSDave Jones static char have_a0;
101bb0a56ecSDave Jones 
check_fsb(unsigned int fsbspeed)102bb0a56ecSDave Jones static int check_fsb(unsigned int fsbspeed)
103bb0a56ecSDave Jones {
104bb0a56ecSDave Jones 	int delta;
105bb0a56ecSDave Jones 	unsigned int f = fsb / 1000;
106bb0a56ecSDave Jones 
107bb0a56ecSDave Jones 	delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
108bb0a56ecSDave Jones 	return delta < 5;
109bb0a56ecSDave Jones }
110bb0a56ecSDave Jones 
111fa8031aeSAndi Kleen static const struct x86_cpu_id powernow_k7_cpuids[] = {
112*b11d77faSThomas Gleixner 	X86_MATCH_VENDOR_FAM(AMD, 6, NULL),
113fa8031aeSAndi Kleen 	{}
114fa8031aeSAndi Kleen };
115fa8031aeSAndi Kleen MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
116fa8031aeSAndi Kleen 
check_powernow(void)117bb0a56ecSDave Jones static int check_powernow(void)
118bb0a56ecSDave Jones {
119bb0a56ecSDave Jones 	struct cpuinfo_x86 *c = &cpu_data(0);
120bb0a56ecSDave Jones 	unsigned int maxei, eax, ebx, ecx, edx;
121bb0a56ecSDave Jones 
122fa8031aeSAndi Kleen 	if (!x86_match_cpu(powernow_k7_cpuids))
123bb0a56ecSDave Jones 		return 0;
124bb0a56ecSDave Jones 
125bb0a56ecSDave Jones 	/* Get maximum capabilities */
126bb0a56ecSDave Jones 	maxei = cpuid_eax(0x80000000);
127bb0a56ecSDave Jones 	if (maxei < 0x80000007) {	/* Any powernow info ? */
128bb0a56ecSDave Jones #ifdef MODULE
1291c5864e2SJoe Perches 		pr_info("No powernow capabilities detected\n");
130bb0a56ecSDave Jones #endif
131bb0a56ecSDave Jones 		return 0;
132bb0a56ecSDave Jones 	}
133bb0a56ecSDave Jones 
134b399151cSJia Zhang 	if ((c->x86_model == 6) && (c->x86_stepping == 0)) {
1351c5864e2SJoe Perches 		pr_info("K7 660[A0] core detected, enabling errata workarounds\n");
136bb0a56ecSDave Jones 		have_a0 = 1;
137bb0a56ecSDave Jones 	}
138bb0a56ecSDave Jones 
139bb0a56ecSDave Jones 	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
140bb0a56ecSDave Jones 
141bb0a56ecSDave Jones 	/* Check we can actually do something before we say anything.*/
142bb0a56ecSDave Jones 	if (!(edx & (1 << 1 | 1 << 2)))
143bb0a56ecSDave Jones 		return 0;
144bb0a56ecSDave Jones 
1451c5864e2SJoe Perches 	pr_info("PowerNOW! Technology present. Can scale: ");
146bb0a56ecSDave Jones 
147bb0a56ecSDave Jones 	if (edx & 1 << 1) {
148b49c22a6SJoe Perches 		pr_cont("frequency");
149bb0a56ecSDave Jones 		can_scale_bus = 1;
150bb0a56ecSDave Jones 	}
151bb0a56ecSDave Jones 
152bb0a56ecSDave Jones 	if ((edx & (1 << 1 | 1 << 2)) == 0x6)
153b49c22a6SJoe Perches 		pr_cont(" and ");
154bb0a56ecSDave Jones 
155bb0a56ecSDave Jones 	if (edx & 1 << 2) {
156b49c22a6SJoe Perches 		pr_cont("voltage");
157bb0a56ecSDave Jones 		can_scale_vid = 1;
158bb0a56ecSDave Jones 	}
159bb0a56ecSDave Jones 
160b49c22a6SJoe Perches 	pr_cont("\n");
161bb0a56ecSDave Jones 	return 1;
162bb0a56ecSDave Jones }
163bb0a56ecSDave Jones 
164bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
invalidate_entry(unsigned int entry)165bb0a56ecSDave Jones static void invalidate_entry(unsigned int entry)
166bb0a56ecSDave Jones {
167bb0a56ecSDave Jones 	powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
168bb0a56ecSDave Jones }
169bb0a56ecSDave Jones #endif
170bb0a56ecSDave Jones 
get_ranges(unsigned char * pst)171bb0a56ecSDave Jones static int get_ranges(unsigned char *pst)
172bb0a56ecSDave Jones {
173bb0a56ecSDave Jones 	unsigned int j;
174bb0a56ecSDave Jones 	unsigned int speed;
175bb0a56ecSDave Jones 	u8 fid, vid;
176bb0a56ecSDave Jones 
177d5b73cd8SViresh Kumar 	powernow_table = kzalloc((sizeof(*powernow_table) *
178bb0a56ecSDave Jones 				(number_scales + 1)), GFP_KERNEL);
179bb0a56ecSDave Jones 	if (!powernow_table)
180bb0a56ecSDave Jones 		return -ENOMEM;
181bb0a56ecSDave Jones 
182bb0a56ecSDave Jones 	for (j = 0 ; j < number_scales; j++) {
183bb0a56ecSDave Jones 		fid = *pst++;
184bb0a56ecSDave Jones 
185bb0a56ecSDave Jones 		powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
18650701588SViresh Kumar 		powernow_table[j].driver_data = fid; /* lower 8 bits */
187bb0a56ecSDave Jones 
188bb0a56ecSDave Jones 		speed = powernow_table[j].frequency;
189bb0a56ecSDave Jones 
190bb0a56ecSDave Jones 		if ((fid_codes[fid] % 10) == 5) {
191bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
192bb0a56ecSDave Jones 			if (have_a0 == 1)
193bb0a56ecSDave Jones 				invalidate_entry(j);
194bb0a56ecSDave Jones #endif
195bb0a56ecSDave Jones 		}
196bb0a56ecSDave Jones 
197bb0a56ecSDave Jones 		if (speed < minimum_speed)
198bb0a56ecSDave Jones 			minimum_speed = speed;
199bb0a56ecSDave Jones 		if (speed > maximum_speed)
200bb0a56ecSDave Jones 			maximum_speed = speed;
201bb0a56ecSDave Jones 
202bb0a56ecSDave Jones 		vid = *pst++;
20350701588SViresh Kumar 		powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */
204bb0a56ecSDave Jones 
205bb0a56ecSDave Jones 		pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "
206bb0a56ecSDave Jones 			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
207bb0a56ecSDave Jones 			 fid_codes[fid] % 10, speed/1000, vid,
208bb0a56ecSDave Jones 			 mobile_vid_table[vid]/1000,
209bb0a56ecSDave Jones 			 mobile_vid_table[vid]%1000);
210bb0a56ecSDave Jones 	}
211bb0a56ecSDave Jones 	powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
21250701588SViresh Kumar 	powernow_table[number_scales].driver_data = 0;
213bb0a56ecSDave Jones 
214bb0a56ecSDave Jones 	return 0;
215bb0a56ecSDave Jones }
216bb0a56ecSDave Jones 
217bb0a56ecSDave Jones 
change_FID(int fid)218bb0a56ecSDave Jones static void change_FID(int fid)
219bb0a56ecSDave Jones {
220bb0a56ecSDave Jones 	union msr_fidvidctl fidvidctl;
221bb0a56ecSDave Jones 
222bb0a56ecSDave Jones 	rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
223bb0a56ecSDave Jones 	if (fidvidctl.bits.FID != fid) {
224bb0a56ecSDave Jones 		fidvidctl.bits.SGTC = latency;
225bb0a56ecSDave Jones 		fidvidctl.bits.FID = fid;
226bb0a56ecSDave Jones 		fidvidctl.bits.VIDC = 0;
227bb0a56ecSDave Jones 		fidvidctl.bits.FIDC = 1;
228bb0a56ecSDave Jones 		wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
229bb0a56ecSDave Jones 	}
230bb0a56ecSDave Jones }
231bb0a56ecSDave Jones 
232bb0a56ecSDave Jones 
change_VID(int vid)233bb0a56ecSDave Jones static void change_VID(int vid)
234bb0a56ecSDave Jones {
235bb0a56ecSDave Jones 	union msr_fidvidctl fidvidctl;
236bb0a56ecSDave Jones 
237bb0a56ecSDave Jones 	rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
238bb0a56ecSDave Jones 	if (fidvidctl.bits.VID != vid) {
239bb0a56ecSDave Jones 		fidvidctl.bits.SGTC = latency;
240bb0a56ecSDave Jones 		fidvidctl.bits.VID = vid;
241bb0a56ecSDave Jones 		fidvidctl.bits.FIDC = 0;
242bb0a56ecSDave Jones 		fidvidctl.bits.VIDC = 1;
243bb0a56ecSDave Jones 		wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
244bb0a56ecSDave Jones 	}
245bb0a56ecSDave Jones }
246bb0a56ecSDave Jones 
247bb0a56ecSDave Jones 
powernow_target(struct cpufreq_policy * policy,unsigned int index)2489c0ebcf7SViresh Kumar static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
249bb0a56ecSDave Jones {
250bb0a56ecSDave Jones 	u8 fid, vid;
251bb0a56ecSDave Jones 	struct cpufreq_freqs freqs;
252bb0a56ecSDave Jones 	union msr_fidvidstatus fidvidstatus;
253bb0a56ecSDave Jones 	int cfid;
254bb0a56ecSDave Jones 
255bb0a56ecSDave Jones 	/* fid are the lower 8 bits of the index we stored into
256bb0a56ecSDave Jones 	 * the cpufreq frequency table in powernow_decode_bios,
257bb0a56ecSDave Jones 	 * vid are the upper 8 bits.
258bb0a56ecSDave Jones 	 */
259bb0a56ecSDave Jones 
26050701588SViresh Kumar 	fid = powernow_table[index].driver_data & 0xFF;
26150701588SViresh Kumar 	vid = (powernow_table[index].driver_data & 0xFF00) >> 8;
262bb0a56ecSDave Jones 
263bb0a56ecSDave Jones 	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
264bb0a56ecSDave Jones 	cfid = fidvidstatus.bits.CFID;
265bb0a56ecSDave Jones 	freqs.old = fsb * fid_codes[cfid] / 10;
266bb0a56ecSDave Jones 
267bb0a56ecSDave Jones 	freqs.new = powernow_table[index].frequency;
268bb0a56ecSDave Jones 
269bb0a56ecSDave Jones 	/* Now do the magic poking into the MSRs.  */
270bb0a56ecSDave Jones 
271bb0a56ecSDave Jones 	if (have_a0 == 1)	/* A0 errata 5 */
272bb0a56ecSDave Jones 		local_irq_disable();
273bb0a56ecSDave Jones 
274bb0a56ecSDave Jones 	if (freqs.old > freqs.new) {
275bb0a56ecSDave Jones 		/* Going down, so change FID first */
276bb0a56ecSDave Jones 		change_FID(fid);
277bb0a56ecSDave Jones 		change_VID(vid);
278bb0a56ecSDave Jones 	} else {
279bb0a56ecSDave Jones 		/* Going up, so change VID first */
280bb0a56ecSDave Jones 		change_VID(vid);
281bb0a56ecSDave Jones 		change_FID(fid);
282bb0a56ecSDave Jones 	}
283bb0a56ecSDave Jones 
284bb0a56ecSDave Jones 
285bb0a56ecSDave Jones 	if (have_a0 == 1)
286bb0a56ecSDave Jones 		local_irq_enable();
287bb0a56ecSDave Jones 
2889c0ebcf7SViresh Kumar 	return 0;
289bb0a56ecSDave Jones }
290bb0a56ecSDave Jones 
291bb0a56ecSDave Jones 
292bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
293bb0a56ecSDave Jones 
294bb0a56ecSDave Jones static struct acpi_processor_performance *acpi_processor_perf;
295bb0a56ecSDave Jones 
powernow_acpi_init(void)296bb0a56ecSDave Jones static int powernow_acpi_init(void)
297bb0a56ecSDave Jones {
298bb0a56ecSDave Jones 	int i;
299bb0a56ecSDave Jones 	int retval = 0;
300bb0a56ecSDave Jones 	union powernow_acpi_control_t pc;
301bb0a56ecSDave Jones 
302bb0a56ecSDave Jones 	if (acpi_processor_perf != NULL && powernow_table != NULL) {
303bb0a56ecSDave Jones 		retval = -EINVAL;
304bb0a56ecSDave Jones 		goto err0;
305bb0a56ecSDave Jones 	}
306bb0a56ecSDave Jones 
307d5b73cd8SViresh Kumar 	acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);
308bb0a56ecSDave Jones 	if (!acpi_processor_perf) {
309bb0a56ecSDave Jones 		retval = -ENOMEM;
310bb0a56ecSDave Jones 		goto err0;
311bb0a56ecSDave Jones 	}
312bb0a56ecSDave Jones 
313bb0a56ecSDave Jones 	if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map,
314bb0a56ecSDave Jones 								GFP_KERNEL)) {
315bb0a56ecSDave Jones 		retval = -ENOMEM;
316bb0a56ecSDave Jones 		goto err05;
317bb0a56ecSDave Jones 	}
318bb0a56ecSDave Jones 
319bb0a56ecSDave Jones 	if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
320bb0a56ecSDave Jones 		retval = -EIO;
321bb0a56ecSDave Jones 		goto err1;
322bb0a56ecSDave Jones 	}
323bb0a56ecSDave Jones 
324bb0a56ecSDave Jones 	if (acpi_processor_perf->control_register.space_id !=
325bb0a56ecSDave Jones 			ACPI_ADR_SPACE_FIXED_HARDWARE) {
326bb0a56ecSDave Jones 		retval = -ENODEV;
327bb0a56ecSDave Jones 		goto err2;
328bb0a56ecSDave Jones 	}
329bb0a56ecSDave Jones 
330bb0a56ecSDave Jones 	if (acpi_processor_perf->status_register.space_id !=
331bb0a56ecSDave Jones 			ACPI_ADR_SPACE_FIXED_HARDWARE) {
332bb0a56ecSDave Jones 		retval = -ENODEV;
333bb0a56ecSDave Jones 		goto err2;
334bb0a56ecSDave Jones 	}
335bb0a56ecSDave Jones 
336bb0a56ecSDave Jones 	number_scales = acpi_processor_perf->state_count;
337bb0a56ecSDave Jones 
338bb0a56ecSDave Jones 	if (number_scales < 2) {
339bb0a56ecSDave Jones 		retval = -ENODEV;
340bb0a56ecSDave Jones 		goto err2;
341bb0a56ecSDave Jones 	}
342bb0a56ecSDave Jones 
343d5b73cd8SViresh Kumar 	powernow_table = kzalloc((sizeof(*powernow_table) *
344bb0a56ecSDave Jones 				(number_scales + 1)), GFP_KERNEL);
345bb0a56ecSDave Jones 	if (!powernow_table) {
346bb0a56ecSDave Jones 		retval = -ENOMEM;
347bb0a56ecSDave Jones 		goto err2;
348bb0a56ecSDave Jones 	}
349bb0a56ecSDave Jones 
350bb0a56ecSDave Jones 	pc.val = (unsigned long) acpi_processor_perf->states[0].control;
351bb0a56ecSDave Jones 	for (i = 0; i < number_scales; i++) {
352bb0a56ecSDave Jones 		u8 fid, vid;
353bb0a56ecSDave Jones 		struct acpi_processor_px *state =
354bb0a56ecSDave Jones 			&acpi_processor_perf->states[i];
355bb0a56ecSDave Jones 		unsigned int speed, speed_mhz;
356bb0a56ecSDave Jones 
357bb0a56ecSDave Jones 		pc.val = (unsigned long) state->control;
358bb0a56ecSDave Jones 		pr_debug("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
359bb0a56ecSDave Jones 			 i,
360bb0a56ecSDave Jones 			 (u32) state->core_frequency,
361bb0a56ecSDave Jones 			 (u32) state->power,
362bb0a56ecSDave Jones 			 (u32) state->transition_latency,
363bb0a56ecSDave Jones 			 (u32) state->control,
364bb0a56ecSDave Jones 			 pc.bits.sgtc);
365bb0a56ecSDave Jones 
366bb0a56ecSDave Jones 		vid = pc.bits.vid;
367bb0a56ecSDave Jones 		fid = pc.bits.fid;
368bb0a56ecSDave Jones 
369bb0a56ecSDave Jones 		powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
37050701588SViresh Kumar 		powernow_table[i].driver_data = fid; /* lower 8 bits */
37150701588SViresh Kumar 		powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */
372bb0a56ecSDave Jones 
373bb0a56ecSDave Jones 		speed = powernow_table[i].frequency;
374bb0a56ecSDave Jones 		speed_mhz = speed / 1000;
375bb0a56ecSDave Jones 
376bb0a56ecSDave Jones 		/* processor_perflib will multiply the MHz value by 1000 to
377bb0a56ecSDave Jones 		 * get a KHz value (e.g. 1266000). However, powernow-k7 works
378bb0a56ecSDave Jones 		 * with true KHz values (e.g. 1266768). To ensure that all
379bb0a56ecSDave Jones 		 * powernow frequencies are available, we must ensure that
380bb0a56ecSDave Jones 		 * ACPI doesn't restrict them, so we round up the MHz value
381bb0a56ecSDave Jones 		 * to ensure that perflib's computed KHz value is greater than
382bb0a56ecSDave Jones 		 * or equal to powernow's KHz value.
383bb0a56ecSDave Jones 		 */
384bb0a56ecSDave Jones 		if (speed % 1000 > 0)
385bb0a56ecSDave Jones 			speed_mhz++;
386bb0a56ecSDave Jones 
387bb0a56ecSDave Jones 		if ((fid_codes[fid] % 10) == 5) {
388bb0a56ecSDave Jones 			if (have_a0 == 1)
389bb0a56ecSDave Jones 				invalidate_entry(i);
390bb0a56ecSDave Jones 		}
391bb0a56ecSDave Jones 
392bb0a56ecSDave Jones 		pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "
393bb0a56ecSDave Jones 			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
394bb0a56ecSDave Jones 			 fid_codes[fid] % 10, speed_mhz, vid,
395bb0a56ecSDave Jones 			 mobile_vid_table[vid]/1000,
396bb0a56ecSDave Jones 			 mobile_vid_table[vid]%1000);
397bb0a56ecSDave Jones 
398bb0a56ecSDave Jones 		if (state->core_frequency != speed_mhz) {
399bb0a56ecSDave Jones 			state->core_frequency = speed_mhz;
400bb0a56ecSDave Jones 			pr_debug("   Corrected ACPI frequency to %d\n",
401bb0a56ecSDave Jones 				speed_mhz);
402bb0a56ecSDave Jones 		}
403bb0a56ecSDave Jones 
404bb0a56ecSDave Jones 		if (latency < pc.bits.sgtc)
405bb0a56ecSDave Jones 			latency = pc.bits.sgtc;
406bb0a56ecSDave Jones 
407bb0a56ecSDave Jones 		if (speed < minimum_speed)
408bb0a56ecSDave Jones 			minimum_speed = speed;
409bb0a56ecSDave Jones 		if (speed > maximum_speed)
410bb0a56ecSDave Jones 			maximum_speed = speed;
411bb0a56ecSDave Jones 	}
412bb0a56ecSDave Jones 
413bb0a56ecSDave Jones 	powernow_table[i].frequency = CPUFREQ_TABLE_END;
41450701588SViresh Kumar 	powernow_table[i].driver_data = 0;
415bb0a56ecSDave Jones 
416bb0a56ecSDave Jones 	/* notify BIOS that we exist */
417bb0a56ecSDave Jones 	acpi_processor_notify_smm(THIS_MODULE);
418bb0a56ecSDave Jones 
419bb0a56ecSDave Jones 	return 0;
420bb0a56ecSDave Jones 
421bb0a56ecSDave Jones err2:
422b2f8dc4cSRafael J. Wysocki 	acpi_processor_unregister_performance(0);
423bb0a56ecSDave Jones err1:
424bb0a56ecSDave Jones 	free_cpumask_var(acpi_processor_perf->shared_cpu_map);
425bb0a56ecSDave Jones err05:
426bb0a56ecSDave Jones 	kfree(acpi_processor_perf);
427bb0a56ecSDave Jones err0:
4281c5864e2SJoe Perches 	pr_warn("ACPI perflib can not be used on this platform\n");
429bb0a56ecSDave Jones 	acpi_processor_perf = NULL;
430bb0a56ecSDave Jones 	return retval;
431bb0a56ecSDave Jones }
432bb0a56ecSDave Jones #else
powernow_acpi_init(void)433bb0a56ecSDave Jones static int powernow_acpi_init(void)
434bb0a56ecSDave Jones {
4351c5864e2SJoe Perches 	pr_info("no support for ACPI processor found - please recompile your kernel with ACPI processor\n");
436bb0a56ecSDave Jones 	return -EINVAL;
437bb0a56ecSDave Jones }
438bb0a56ecSDave Jones #endif
439bb0a56ecSDave Jones 
print_pst_entry(struct pst_s * pst,unsigned int j)440bb0a56ecSDave Jones static void print_pst_entry(struct pst_s *pst, unsigned int j)
441bb0a56ecSDave Jones {
442bb0a56ecSDave Jones 	pr_debug("PST:%d (@%p)\n", j, pst);
443bb0a56ecSDave Jones 	pr_debug(" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
444bb0a56ecSDave Jones 		pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
445bb0a56ecSDave Jones }
446bb0a56ecSDave Jones 
powernow_decode_bios(int maxfid,int startvid)447bb0a56ecSDave Jones static int powernow_decode_bios(int maxfid, int startvid)
448bb0a56ecSDave Jones {
449bb0a56ecSDave Jones 	struct psb_s *psb;
450bb0a56ecSDave Jones 	struct pst_s *pst;
451bb0a56ecSDave Jones 	unsigned int i, j;
452bb0a56ecSDave Jones 	unsigned char *p;
453bb0a56ecSDave Jones 	unsigned int etuple;
454bb0a56ecSDave Jones 	unsigned int ret;
455bb0a56ecSDave Jones 
456bb0a56ecSDave Jones 	etuple = cpuid_eax(0x80000001);
457bb0a56ecSDave Jones 
458bb0a56ecSDave Jones 	for (i = 0xC0000; i < 0xffff0 ; i += 16) {
459bb0a56ecSDave Jones 
460bb0a56ecSDave Jones 		p = phys_to_virt(i);
461bb0a56ecSDave Jones 
462bb0a56ecSDave Jones 		if (memcmp(p, "AMDK7PNOW!",  10) == 0) {
463bb0a56ecSDave Jones 			pr_debug("Found PSB header at %p\n", p);
464bb0a56ecSDave Jones 			psb = (struct psb_s *) p;
465bb0a56ecSDave Jones 			pr_debug("Table version: 0x%x\n", psb->tableversion);
466bb0a56ecSDave Jones 			if (psb->tableversion != 0x12) {
4671c5864e2SJoe Perches 				pr_info("Sorry, only v1.2 tables supported right now\n");
468bb0a56ecSDave Jones 				return -ENODEV;
469bb0a56ecSDave Jones 			}
470bb0a56ecSDave Jones 
471bb0a56ecSDave Jones 			pr_debug("Flags: 0x%x\n", psb->flags);
472bb0a56ecSDave Jones 			if ((psb->flags & 1) == 0)
473bb0a56ecSDave Jones 				pr_debug("Mobile voltage regulator\n");
474bb0a56ecSDave Jones 			else
475bb0a56ecSDave Jones 				pr_debug("Desktop voltage regulator\n");
476bb0a56ecSDave Jones 
477bb0a56ecSDave Jones 			latency = psb->settlingtime;
478bb0a56ecSDave Jones 			if (latency < 100) {
4791c5864e2SJoe Perches 				pr_info("BIOS set settling time to %d microseconds. Should be at least 100. Correcting.\n",
480b49c22a6SJoe Perches 					latency);
481bb0a56ecSDave Jones 				latency = 100;
482bb0a56ecSDave Jones 			}
483bb0a56ecSDave Jones 			pr_debug("Settling Time: %d microseconds.\n",
484bb0a56ecSDave Jones 					psb->settlingtime);
485bb0a56ecSDave Jones 			pr_debug("Has %d PST tables. (Only dumping ones "
486bb0a56ecSDave Jones 					"relevant to this CPU).\n",
487bb0a56ecSDave Jones 					psb->numpst);
488bb0a56ecSDave Jones 
489d5b73cd8SViresh Kumar 			p += sizeof(*psb);
490bb0a56ecSDave Jones 
491bb0a56ecSDave Jones 			pst = (struct pst_s *) p;
492bb0a56ecSDave Jones 
493bb0a56ecSDave Jones 			for (j = 0; j < psb->numpst; j++) {
494bb0a56ecSDave Jones 				pst = (struct pst_s *) p;
495bb0a56ecSDave Jones 				number_scales = pst->numpstates;
496bb0a56ecSDave Jones 
497bb0a56ecSDave Jones 				if ((etuple == pst->cpuid) &&
498bb0a56ecSDave Jones 				    check_fsb(pst->fsbspeed) &&
499bb0a56ecSDave Jones 				    (maxfid == pst->maxfid) &&
500bb0a56ecSDave Jones 				    (startvid == pst->startvid)) {
501bb0a56ecSDave Jones 					print_pst_entry(pst, j);
502d5b73cd8SViresh Kumar 					p = (char *)pst + sizeof(*pst);
503bb0a56ecSDave Jones 					ret = get_ranges(p);
504bb0a56ecSDave Jones 					return ret;
505bb0a56ecSDave Jones 				} else {
506bb0a56ecSDave Jones 					unsigned int k;
507d5b73cd8SViresh Kumar 					p = (char *)pst + sizeof(*pst);
508bb0a56ecSDave Jones 					for (k = 0; k < number_scales; k++)
509bb0a56ecSDave Jones 						p += 2;
510bb0a56ecSDave Jones 				}
511bb0a56ecSDave Jones 			}
5121c5864e2SJoe Perches 			pr_info("No PST tables match this cpuid (0x%x)\n",
513b49c22a6SJoe Perches 				etuple);
5141c5864e2SJoe Perches 			pr_info("This is indicative of a broken BIOS\n");
515bb0a56ecSDave Jones 
516bb0a56ecSDave Jones 			return -EINVAL;
517bb0a56ecSDave Jones 		}
518bb0a56ecSDave Jones 		p++;
519bb0a56ecSDave Jones 	}
520bb0a56ecSDave Jones 
521bb0a56ecSDave Jones 	return -ENODEV;
522bb0a56ecSDave Jones }
523bb0a56ecSDave Jones 
524bb0a56ecSDave Jones 
525bb0a56ecSDave Jones /*
526bb0a56ecSDave Jones  * We use the fact that the bus frequency is somehow
527bb0a56ecSDave Jones  * a multiple of 100000/3 khz, then we compute sgtc according
528bb0a56ecSDave Jones  * to this multiple.
529bb0a56ecSDave Jones  * That way, we match more how AMD thinks all of that work.
530bb0a56ecSDave Jones  * We will then get the same kind of behaviour already tested under
531bb0a56ecSDave Jones  * the "well-known" other OS.
532bb0a56ecSDave Jones  */
fixup_sgtc(void)5332760984fSPaul Gortmaker static int fixup_sgtc(void)
534bb0a56ecSDave Jones {
535bb0a56ecSDave Jones 	unsigned int sgtc;
536bb0a56ecSDave Jones 	unsigned int m;
537bb0a56ecSDave Jones 
538bb0a56ecSDave Jones 	m = fsb / 3333;
539bb0a56ecSDave Jones 	if ((m % 10) >= 5)
540bb0a56ecSDave Jones 		m += 5;
541bb0a56ecSDave Jones 
542bb0a56ecSDave Jones 	m /= 10;
543bb0a56ecSDave Jones 
544bb0a56ecSDave Jones 	sgtc = 100 * m * latency;
545bb0a56ecSDave Jones 	sgtc = sgtc / 3;
546bb0a56ecSDave Jones 	if (sgtc > 0xfffff) {
5471c5864e2SJoe Perches 		pr_warn("SGTC too large %d\n", sgtc);
548bb0a56ecSDave Jones 		sgtc = 0xfffff;
549bb0a56ecSDave Jones 	}
550bb0a56ecSDave Jones 	return sgtc;
551bb0a56ecSDave Jones }
552bb0a56ecSDave Jones 
powernow_get(unsigned int cpu)553bb0a56ecSDave Jones static unsigned int powernow_get(unsigned int cpu)
554bb0a56ecSDave Jones {
555bb0a56ecSDave Jones 	union msr_fidvidstatus fidvidstatus;
556bb0a56ecSDave Jones 	unsigned int cfid;
557bb0a56ecSDave Jones 
558bb0a56ecSDave Jones 	if (cpu)
559bb0a56ecSDave Jones 		return 0;
560bb0a56ecSDave Jones 	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
561bb0a56ecSDave Jones 	cfid = fidvidstatus.bits.CFID;
562bb0a56ecSDave Jones 
563bb0a56ecSDave Jones 	return fsb * fid_codes[cfid] / 10;
564bb0a56ecSDave Jones }
565bb0a56ecSDave Jones 
566bb0a56ecSDave Jones 
acer_cpufreq_pst(const struct dmi_system_id * d)5672760984fSPaul Gortmaker static int acer_cpufreq_pst(const struct dmi_system_id *d)
568bb0a56ecSDave Jones {
5691c5864e2SJoe Perches 	pr_warn("%s laptop with broken PST tables in BIOS detected\n",
570bb0a56ecSDave Jones 		d->ident);
5711c5864e2SJoe Perches 	pr_warn("You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
5721c5864e2SJoe Perches 	pr_warn("cpufreq scaling has been disabled as a result of this\n");
573bb0a56ecSDave Jones 	return 0;
574bb0a56ecSDave Jones }
575bb0a56ecSDave Jones 
576bb0a56ecSDave Jones /*
577bb0a56ecSDave Jones  * Some Athlon laptops have really fucked PST tables.
578bb0a56ecSDave Jones  * A BIOS update is all that can save them.
579bb0a56ecSDave Jones  * Mention this, and disable cpufreq.
580bb0a56ecSDave Jones  */
5816faadbbbSChristoph Hellwig static const struct dmi_system_id powernow_dmi_table[] = {
582bb0a56ecSDave Jones 	{
583bb0a56ecSDave Jones 		.callback = acer_cpufreq_pst,
584bb0a56ecSDave Jones 		.ident = "Acer Aspire",
585bb0a56ecSDave Jones 		.matches = {
586bb0a56ecSDave Jones 			DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
587bb0a56ecSDave Jones 			DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
588bb0a56ecSDave Jones 		},
589bb0a56ecSDave Jones 	},
590bb0a56ecSDave Jones 	{ }
591bb0a56ecSDave Jones };
592bb0a56ecSDave Jones 
powernow_cpu_init(struct cpufreq_policy * policy)5932760984fSPaul Gortmaker static int powernow_cpu_init(struct cpufreq_policy *policy)
594bb0a56ecSDave Jones {
595bb0a56ecSDave Jones 	union msr_fidvidstatus fidvidstatus;
596bb0a56ecSDave Jones 	int result;
597bb0a56ecSDave Jones 
598bb0a56ecSDave Jones 	if (policy->cpu != 0)
599bb0a56ecSDave Jones 		return -ENODEV;
600bb0a56ecSDave Jones 
601bb0a56ecSDave Jones 	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
602bb0a56ecSDave Jones 
603bb0a56ecSDave Jones 	recalibrate_cpu_khz();
604bb0a56ecSDave Jones 
605bb0a56ecSDave Jones 	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
606bb0a56ecSDave Jones 	if (!fsb) {
6071c5864e2SJoe Perches 		pr_warn("can not determine bus frequency\n");
608bb0a56ecSDave Jones 		return -EINVAL;
609bb0a56ecSDave Jones 	}
610bb0a56ecSDave Jones 	pr_debug("FSB: %3dMHz\n", fsb/1000);
611bb0a56ecSDave Jones 
612bb0a56ecSDave Jones 	if (dmi_check_system(powernow_dmi_table) || acpi_force) {
6131c5864e2SJoe Perches 		pr_info("PSB/PST known to be broken - trying ACPI instead\n");
614bb0a56ecSDave Jones 		result = powernow_acpi_init();
615bb0a56ecSDave Jones 	} else {
616bb0a56ecSDave Jones 		result = powernow_decode_bios(fidvidstatus.bits.MFID,
617bb0a56ecSDave Jones 				fidvidstatus.bits.SVID);
618bb0a56ecSDave Jones 		if (result) {
6191c5864e2SJoe Perches 			pr_info("Trying ACPI perflib\n");
620bb0a56ecSDave Jones 			maximum_speed = 0;
621bb0a56ecSDave Jones 			minimum_speed = -1;
622bb0a56ecSDave Jones 			latency = 0;
623bb0a56ecSDave Jones 			result = powernow_acpi_init();
624bb0a56ecSDave Jones 			if (result) {
6251c5864e2SJoe Perches 				pr_info("ACPI and legacy methods failed\n");
626bb0a56ecSDave Jones 			}
627bb0a56ecSDave Jones 		} else {
628bb0a56ecSDave Jones 			/* SGTC use the bus clock as timer */
629bb0a56ecSDave Jones 			latency = fixup_sgtc();
6301c5864e2SJoe Perches 			pr_info("SGTC: %d\n", latency);
631bb0a56ecSDave Jones 		}
632bb0a56ecSDave Jones 	}
633bb0a56ecSDave Jones 
634bb0a56ecSDave Jones 	if (result)
635bb0a56ecSDave Jones 		return result;
636bb0a56ecSDave Jones 
6371c5864e2SJoe Perches 	pr_info("Minimum speed %d MHz - Maximum speed %d MHz\n",
638bb0a56ecSDave Jones 		minimum_speed/1000, maximum_speed/1000);
639bb0a56ecSDave Jones 
640bb0a56ecSDave Jones 	policy->cpuinfo.transition_latency =
641bb0a56ecSDave Jones 		cpufreq_scale(2000000UL, fsb, latency);
642e2376d1fSViresh Kumar 	policy->freq_table = powernow_table;
643bb0a56ecSDave Jones 
644e2376d1fSViresh Kumar 	return 0;
645bb0a56ecSDave Jones }
646bb0a56ecSDave Jones 
powernow_cpu_exit(struct cpufreq_policy * policy)647bb0a56ecSDave Jones static int powernow_cpu_exit(struct cpufreq_policy *policy)
648bb0a56ecSDave Jones {
649bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
650bb0a56ecSDave Jones 	if (acpi_processor_perf) {
651b2f8dc4cSRafael J. Wysocki 		acpi_processor_unregister_performance(0);
652bb0a56ecSDave Jones 		free_cpumask_var(acpi_processor_perf->shared_cpu_map);
653bb0a56ecSDave Jones 		kfree(acpi_processor_perf);
654bb0a56ecSDave Jones 	}
655bb0a56ecSDave Jones #endif
656bb0a56ecSDave Jones 
657bb0a56ecSDave Jones 	kfree(powernow_table);
658bb0a56ecSDave Jones 	return 0;
659bb0a56ecSDave Jones }
660bb0a56ecSDave Jones 
661bb0a56ecSDave Jones static struct cpufreq_driver powernow_driver = {
662d63bd27fSViresh Kumar 	.verify		= cpufreq_generic_frequency_table_verify,
6639c0ebcf7SViresh Kumar 	.target_index	= powernow_target,
664bb0a56ecSDave Jones 	.get		= powernow_get,
665bb0a56ecSDave Jones #ifdef CONFIG_X86_POWERNOW_K7_ACPI
666bb0a56ecSDave Jones 	.bios_limit	= acpi_processor_get_bios_limit,
667bb0a56ecSDave Jones #endif
668bb0a56ecSDave Jones 	.init		= powernow_cpu_init,
669bb0a56ecSDave Jones 	.exit		= powernow_cpu_exit,
670bb0a56ecSDave Jones 	.name		= "powernow-k7",
671d63bd27fSViresh Kumar 	.attr		= cpufreq_generic_attr,
672bb0a56ecSDave Jones };
673bb0a56ecSDave Jones 
powernow_init(void)674bb0a56ecSDave Jones static int __init powernow_init(void)
675bb0a56ecSDave Jones {
676bb0a56ecSDave Jones 	if (check_powernow() == 0)
677bb0a56ecSDave Jones 		return -ENODEV;
678bb0a56ecSDave Jones 	return cpufreq_register_driver(&powernow_driver);
679bb0a56ecSDave Jones }
680bb0a56ecSDave Jones 
681bb0a56ecSDave Jones 
powernow_exit(void)682bb0a56ecSDave Jones static void __exit powernow_exit(void)
683bb0a56ecSDave Jones {
684bb0a56ecSDave Jones 	cpufreq_unregister_driver(&powernow_driver);
685bb0a56ecSDave Jones }
686bb0a56ecSDave Jones 
687bb0a56ecSDave Jones module_param(acpi_force,  int, 0444);
688bb0a56ecSDave Jones MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
689bb0a56ecSDave Jones 
690d5e80b4bSDave Jones MODULE_AUTHOR("Dave Jones");
691bb0a56ecSDave Jones MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
692bb0a56ecSDave Jones MODULE_LICENSE("GPL");
693bb0a56ecSDave Jones 
694bb0a56ecSDave Jones late_initcall(powernow_init);
695bb0a56ecSDave Jones module_exit(powernow_exit);
696bb0a56ecSDave Jones 
697