blob: 334cc2f1e9f1fe1a675b7d9eadf9819fbedadfce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * AMD K7 Powernow driver.
Dave Jonesf4432c52008-10-20 13:31:45 -04003 * (C) 2003 Dave Jones on behalf of SuSE Labs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * (C) 2003-2004 Dave Jones <davej@redhat.com>
5 *
6 * Licensed under the terms of the GNU GPL License version 2.
7 * Based upon datasheets & sample CPUs kindly provided by AMD.
8 *
Dave Jonesb9e76382009-01-18 00:32:26 -05009 * Errata 5:
10 * CPU may fail to execute a FID/VID change in presence of interrupt.
11 * - We cli/sti on stepping A0 CPUs around the FID/VID transition.
12 * Errata 15:
13 * CPU with half frequency multipliers may hang upon wakeup from disconnect.
14 * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/cpufreq.h>
22#include <linux/slab.h>
23#include <linux/string.h>
24#include <linux/dmi.h>
Dave Jonesb9e76382009-01-18 00:32:26 -050025#include <linux/timex.h>
26#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Dave Jonesb9e76382009-01-18 00:32:26 -050028#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/msr.h>
Andi Kleenfa8031a2012-01-26 00:09:12 +010030#include <asm/cpu_device_id.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#ifdef CONFIG_X86_POWERNOW_K7_ACPI
33#include <linux/acpi.h>
34#include <acpi/processor.h>
35#endif
36
37#include "powernow-k7.h"
38
39#define PFX "powernow: "
40
41
42struct psb_s {
43 u8 signature[10];
44 u8 tableversion;
45 u8 flags;
46 u16 settlingtime;
47 u8 reserved1;
48 u8 numpst;
49};
50
51struct pst_s {
52 u32 cpuid;
53 u8 fsbspeed;
54 u8 maxfid;
55 u8 startvid;
56 u8 numpstates;
57};
58
59#ifdef CONFIG_X86_POWERNOW_K7_ACPI
60union powernow_acpi_control_t {
61 struct {
62 unsigned long fid:5,
Dave Jonesb9e76382009-01-18 00:32:26 -050063 vid:5,
64 sgtc:20,
65 res1:2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 } bits;
67 unsigned long val;
68};
69#endif
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* divide by 1000 to get VCore voltage in V. */
Dave Jonesbd5ab262007-02-22 19:11:16 -050072static const int mobile_vid_table[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
74 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
75 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
76 1075, 1050, 1025, 1000, 975, 950, 925, 0,
77};
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* divide by 10 to get FID. */
Dave Jonesbd5ab262007-02-22 19:11:16 -050080static const int fid_codes[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 110, 115, 120, 125, 50, 55, 60, 65,
82 70, 75, 80, 85, 90, 95, 100, 105,
83 30, 190, 40, 200, 130, 135, 140, 210,
84 150, 225, 160, 165, 170, 180, -1, -1,
85};
86
87/* This parameter is used in order to force ACPI instead of legacy method for
88 * configuration purpose.
89 */
90
91static int acpi_force;
92
93static struct cpufreq_frequency_table *powernow_table;
94
95static unsigned int can_scale_bus;
96static unsigned int can_scale_vid;
Dave Jonesfff78ad2009-01-17 22:28:42 -050097static unsigned int minimum_speed = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static unsigned int maximum_speed;
99static unsigned int number_scales;
100static unsigned int fsb;
101static unsigned int latency;
102static char have_a0;
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static int check_fsb(unsigned int fsbspeed)
105{
106 int delta;
107 unsigned int f = fsb / 1000;
108
109 delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
Dave Jonesb9e76382009-01-18 00:32:26 -0500110 return delta < 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
Andi Kleenfa8031a2012-01-26 00:09:12 +0100113static const struct x86_cpu_id powernow_k7_cpuids[] = {
Ben Hutchings30bcfff2012-02-11 22:58:14 +0000114 { X86_VENDOR_AMD, 6, },
Andi Kleenfa8031a2012-01-26 00:09:12 +0100115 {}
116};
117MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static int check_powernow(void)
120{
Mike Travis92cb7612007-10-19 20:35:04 +0200121 struct cpuinfo_x86 *c = &cpu_data(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 unsigned int maxei, eax, ebx, ecx, edx;
123
Andi Kleenfa8031a2012-01-26 00:09:12 +0100124 if (!x86_match_cpu(powernow_k7_cpuids))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 /* Get maximum capabilities */
Dave Jonesb9e76382009-01-18 00:32:26 -0500128 maxei = cpuid_eax(0x80000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 if (maxei < 0x80000007) { /* Any powernow info ? */
130#ifdef MODULE
Dave Jonesb9e76382009-01-18 00:32:26 -0500131 printk(KERN_INFO PFX "No powernow capabilities detected\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132#endif
133 return 0;
134 }
135
136 if ((c->x86_model == 6) && (c->x86_mask == 0)) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500137 printk(KERN_INFO PFX "K7 660[A0] core detected, "
138 "enabling errata workarounds\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 have_a0 = 1;
140 }
141
142 cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
143
144 /* Check we can actually do something before we say anything.*/
145 if (!(edx & (1 << 1 | 1 << 2)))
146 return 0;
147
Dave Jonesb9e76382009-01-18 00:32:26 -0500148 printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 if (edx & 1 << 1) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500151 printk("frequency");
152 can_scale_bus = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 }
154
155 if ((edx & (1 << 1 | 1 << 2)) == 0x6)
Dave Jonesb9e76382009-01-18 00:32:26 -0500156 printk(" and ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158 if (edx & 1 << 2) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500159 printk("voltage");
160 can_scale_vid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
162
Dave Jonesb9e76382009-01-18 00:32:26 -0500163 printk(".\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 return 1;
165}
166
Dave Jonesd38e73e2009-04-23 13:36:12 -0400167#ifdef CONFIG_X86_POWERNOW_K7_ACPI
Dave Jonesb9e76382009-01-18 00:32:26 -0500168static void invalidate_entry(unsigned int entry)
169{
170 powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
171}
Dave Jonesd38e73e2009-04-23 13:36:12 -0400172#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Dave Jonesb9e76382009-01-18 00:32:26 -0500174static int get_ranges(unsigned char *pst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 unsigned int j;
177 unsigned int speed;
178 u8 fid, vid;
179
Dave Jonesb9e76382009-01-18 00:32:26 -0500180 powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
181 (number_scales + 1)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 if (!powernow_table)
183 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Dave Jonesb9e76382009-01-18 00:32:26 -0500185 for (j = 0 ; j < number_scales; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 fid = *pst++;
187
188 powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
189 powernow_table[j].index = fid; /* lower 8 bits */
190
191 speed = powernow_table[j].frequency;
192
Dave Jonesb9e76382009-01-18 00:32:26 -0500193 if ((fid_codes[fid] % 10) == 5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194#ifdef CONFIG_X86_POWERNOW_K7_ACPI
195 if (have_a0 == 1)
Dave Jonesb9e76382009-01-18 00:32:26 -0500196 invalidate_entry(j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197#endif
198 }
199
200 if (speed < minimum_speed)
201 minimum_speed = speed;
202 if (speed > maximum_speed)
203 maximum_speed = speed;
204
205 vid = *pst++;
206 powernow_table[j].index |= (vid << 8); /* upper 8 bits */
207
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200208 pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500209 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
210 fid_codes[fid] % 10, speed/1000, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 mobile_vid_table[vid]/1000,
212 mobile_vid_table[vid]%1000);
213 }
214 powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
215 powernow_table[number_scales].index = 0;
216
217 return 0;
218}
219
220
221static void change_FID(int fid)
222{
223 union msr_fidvidctl fidvidctl;
224
Dave Jonesb9e76382009-01-18 00:32:26 -0500225 rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 if (fidvidctl.bits.FID != fid) {
227 fidvidctl.bits.SGTC = latency;
228 fidvidctl.bits.FID = fid;
229 fidvidctl.bits.VIDC = 0;
230 fidvidctl.bits.FIDC = 1;
Dave Jonesb9e76382009-01-18 00:32:26 -0500231 wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
233}
234
235
236static void change_VID(int vid)
237{
238 union msr_fidvidctl fidvidctl;
239
Dave Jonesb9e76382009-01-18 00:32:26 -0500240 rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 if (fidvidctl.bits.VID != vid) {
242 fidvidctl.bits.SGTC = latency;
243 fidvidctl.bits.VID = vid;
244 fidvidctl.bits.FIDC = 0;
245 fidvidctl.bits.VIDC = 1;
Dave Jonesb9e76382009-01-18 00:32:26 -0500246 wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248}
249
250
Dave Jonesb9e76382009-01-18 00:32:26 -0500251static void change_speed(unsigned int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{
253 u8 fid, vid;
254 struct cpufreq_freqs freqs;
255 union msr_fidvidstatus fidvidstatus;
256 int cfid;
257
258 /* fid are the lower 8 bits of the index we stored into
259 * the cpufreq frequency table in powernow_decode_bios,
260 * vid are the upper 8 bits.
261 */
262
263 fid = powernow_table[index].index & 0xFF;
264 vid = (powernow_table[index].index & 0xFF00) >> 8;
265
266 freqs.cpu = 0;
267
Dave Jonesb9e76382009-01-18 00:32:26 -0500268 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 cfid = fidvidstatus.bits.CFID;
270 freqs.old = fsb * fid_codes[cfid] / 10;
271
272 freqs.new = powernow_table[index].frequency;
273
274 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
275
276 /* Now do the magic poking into the MSRs. */
277
278 if (have_a0 == 1) /* A0 errata 5 */
279 local_irq_disable();
280
281 if (freqs.old > freqs.new) {
282 /* Going down, so change FID first */
283 change_FID(fid);
284 change_VID(vid);
285 } else {
286 /* Going up, so change VID first */
287 change_VID(vid);
288 change_FID(fid);
289 }
290
291
292 if (have_a0 == 1)
293 local_irq_enable();
294
295 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
296}
297
298
299#ifdef CONFIG_X86_POWERNOW_K7_ACPI
300
301static struct acpi_processor_performance *acpi_processor_perf;
302
303static int powernow_acpi_init(void)
304{
305 int i;
306 int retval = 0;
307 union powernow_acpi_control_t pc;
308
309 if (acpi_processor_perf != NULL && powernow_table != NULL) {
310 retval = -EINVAL;
311 goto err0;
312 }
313
Dave Jonesbfdc7082005-10-20 15:16:15 -0700314 acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if (!acpi_processor_perf) {
317 retval = -ENOMEM;
318 goto err0;
319 }
320
Yinghai Lueaa95842009-06-06 14:51:36 -0700321 if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map,
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800322 GFP_KERNEL)) {
323 retval = -ENOMEM;
324 goto err05;
325 }
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
328 retval = -EIO;
329 goto err1;
330 }
331
Dave Jonesb9e76382009-01-18 00:32:26 -0500332 if (acpi_processor_perf->control_register.space_id !=
333 ACPI_ADR_SPACE_FIXED_HARDWARE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 retval = -ENODEV;
335 goto err2;
336 }
337
Dave Jonesb9e76382009-01-18 00:32:26 -0500338 if (acpi_processor_perf->status_register.space_id !=
339 ACPI_ADR_SPACE_FIXED_HARDWARE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 retval = -ENODEV;
341 goto err2;
342 }
343
344 number_scales = acpi_processor_perf->state_count;
345
346 if (number_scales < 2) {
347 retval = -ENODEV;
348 goto err2;
349 }
350
Dave Jonesb9e76382009-01-18 00:32:26 -0500351 powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
352 (number_scales + 1)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (!powernow_table) {
354 retval = -ENOMEM;
355 goto err2;
356 }
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 pc.val = (unsigned long) acpi_processor_perf->states[0].control;
359 for (i = 0; i < number_scales; i++) {
360 u8 fid, vid;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100361 struct acpi_processor_px *state =
362 &acpi_processor_perf->states[i];
363 unsigned int speed, speed_mhz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Daniel Drakedc2585e2007-05-02 23:19:05 +0100365 pc.val = (unsigned long) state->control;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200366 pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 i,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100368 (u32) state->core_frequency,
369 (u32) state->power,
370 (u32) state->transition_latency,
371 (u32) state->control,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 pc.bits.sgtc);
373
374 vid = pc.bits.vid;
375 fid = pc.bits.fid;
376
377 powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
378 powernow_table[i].index = fid; /* lower 8 bits */
379 powernow_table[i].index |= (vid << 8); /* upper 8 bits */
380
381 speed = powernow_table[i].frequency;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100382 speed_mhz = speed / 1000;
383
384 /* processor_perflib will multiply the MHz value by 1000 to
385 * get a KHz value (e.g. 1266000). However, powernow-k7 works
386 * with true KHz values (e.g. 1266768). To ensure that all
387 * powernow frequencies are available, we must ensure that
388 * ACPI doesn't restrict them, so we round up the MHz value
389 * to ensure that perflib's computed KHz value is greater than
390 * or equal to powernow's KHz value.
391 */
392 if (speed % 1000 > 0)
393 speed_mhz++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Dave Jonesb9e76382009-01-18 00:32:26 -0500395 if ((fid_codes[fid] % 10) == 5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if (have_a0 == 1)
Dave Jonesb9e76382009-01-18 00:32:26 -0500397 invalidate_entry(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200400 pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500401 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100402 fid_codes[fid] % 10, speed_mhz, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 mobile_vid_table[vid]/1000,
404 mobile_vid_table[vid]%1000);
405
Daniel Drakedc2585e2007-05-02 23:19:05 +0100406 if (state->core_frequency != speed_mhz) {
407 state->core_frequency = speed_mhz;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200408 pr_debug(" Corrected ACPI frequency to %d\n",
Daniel Drakedc2585e2007-05-02 23:19:05 +0100409 speed_mhz);
410 }
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (latency < pc.bits.sgtc)
413 latency = pc.bits.sgtc;
414
415 if (speed < minimum_speed)
416 minimum_speed = speed;
417 if (speed > maximum_speed)
418 maximum_speed = speed;
419 }
420
421 powernow_table[i].frequency = CPUFREQ_TABLE_END;
422 powernow_table[i].index = 0;
423
424 /* notify BIOS that we exist */
425 acpi_processor_notify_smm(THIS_MODULE);
426
427 return 0;
428
429err2:
430 acpi_processor_unregister_performance(acpi_processor_perf, 0);
431err1:
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800432 free_cpumask_var(acpi_processor_perf->shared_cpu_map);
433err05:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 kfree(acpi_processor_perf);
435err0:
Dave Jonesb9e76382009-01-18 00:32:26 -0500436 printk(KERN_WARNING PFX "ACPI perflib can not be used on "
437 "this platform\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 acpi_processor_perf = NULL;
439 return retval;
440}
441#else
442static int powernow_acpi_init(void)
443{
444 printk(KERN_INFO PFX "no support for ACPI processor found."
445 " Please recompile your kernel with ACPI processor\n");
446 return -EINVAL;
447}
448#endif
449
Dave Jonesb9e76382009-01-18 00:32:26 -0500450static void print_pst_entry(struct pst_s *pst, unsigned int j)
451{
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200452 pr_debug("PST:%d (@%p)\n", j, pst);
453 pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
Dave Jonesb9e76382009-01-18 00:32:26 -0500454 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
455}
456
457static int powernow_decode_bios(int maxfid, int startvid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 struct psb_s *psb;
460 struct pst_s *pst;
461 unsigned int i, j;
462 unsigned char *p;
463 unsigned int etuple;
464 unsigned int ret;
465
466 etuple = cpuid_eax(0x80000001);
467
Dave Jonesb9e76382009-01-18 00:32:26 -0500468 for (i = 0xC0000; i < 0xffff0 ; i += 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 p = phys_to_virt(i);
471
Dave Jonesb9e76382009-01-18 00:32:26 -0500472 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200473 pr_debug("Found PSB header at %p\n", p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 psb = (struct psb_s *) p;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200475 pr_debug("Table version: 0x%x\n", psb->tableversion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 if (psb->tableversion != 0x12) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500477 printk(KERN_INFO PFX "Sorry, only v1.2 tables"
478 " supported right now\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 return -ENODEV;
480 }
481
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200482 pr_debug("Flags: 0x%x\n", psb->flags);
Dave Jonesb9e76382009-01-18 00:32:26 -0500483 if ((psb->flags & 1) == 0)
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200484 pr_debug("Mobile voltage regulator\n");
Dave Jonesb9e76382009-01-18 00:32:26 -0500485 else
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200486 pr_debug("Desktop voltage regulator\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 latency = psb->settlingtime;
489 if (latency < 100) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500490 printk(KERN_INFO PFX "BIOS set settling time "
491 "to %d microseconds. "
492 "Should be at least 100. "
493 "Correcting.\n", latency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 latency = 100;
495 }
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200496 pr_debug("Settling Time: %d microseconds.\n",
Dave Jonesb9e76382009-01-18 00:32:26 -0500497 psb->settlingtime);
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200498 pr_debug("Has %d PST tables. (Only dumping ones "
Dave Jonesb9e76382009-01-18 00:32:26 -0500499 "relevant to this CPU).\n",
500 psb->numpst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Dave Jonesb9e76382009-01-18 00:32:26 -0500502 p += sizeof(struct psb_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 pst = (struct pst_s *) p;
505
Dave Jonesb9e76382009-01-18 00:32:26 -0500506 for (j = 0; j < psb->numpst; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 pst = (struct pst_s *) p;
508 number_scales = pst->numpstates;
509
Dave Jonesb9e76382009-01-18 00:32:26 -0500510 if ((etuple == pst->cpuid) &&
511 check_fsb(pst->fsbspeed) &&
512 (maxfid == pst->maxfid) &&
513 (startvid == pst->startvid)) {
514 print_pst_entry(pst, j);
515 p = (char *)pst + sizeof(struct pst_s);
516 ret = get_ranges(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 } else {
Dave Jones8cbe0162006-05-30 17:26:08 -0400519 unsigned int k;
Dave Jonesb9e76382009-01-18 00:32:26 -0500520 p = (char *)pst + sizeof(struct pst_s);
521 for (k = 0; k < number_scales; k++)
522 p += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
524 }
Dave Jonesb9e76382009-01-18 00:32:26 -0500525 printk(KERN_INFO PFX "No PST tables match this cpuid "
526 "(0x%x)\n", etuple);
527 printk(KERN_INFO PFX "This is indicative of a broken "
528 "BIOS.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 return -EINVAL;
531 }
532 p++;
533 }
534
535 return -ENODEV;
536}
537
538
Dave Jonesb9e76382009-01-18 00:32:26 -0500539static int powernow_target(struct cpufreq_policy *policy,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 unsigned int target_freq,
541 unsigned int relation)
542{
543 unsigned int newstate;
544
Dave Jonesb9e76382009-01-18 00:32:26 -0500545 if (cpufreq_frequency_table_target(policy, powernow_table, target_freq,
546 relation, &newstate))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return -EINVAL;
548
549 change_speed(newstate);
550
551 return 0;
552}
553
554
Dave Jonesb9e76382009-01-18 00:32:26 -0500555static int powernow_verify(struct cpufreq_policy *policy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 return cpufreq_frequency_table_verify(policy, powernow_table);
558}
559
560/*
561 * We use the fact that the bus frequency is somehow
562 * a multiple of 100000/3 khz, then we compute sgtc according
563 * to this multiple.
564 * That way, we match more how AMD thinks all of that work.
565 * We will then get the same kind of behaviour already tested under
566 * the "well-known" other OS.
567 */
Holger Freyther307069c2010-07-19 03:29:16 +0800568static int __cpuinit fixup_sgtc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 unsigned int sgtc;
571 unsigned int m;
572
573 m = fsb / 3333;
574 if ((m % 10) >= 5)
575 m += 5;
576
577 m /= 10;
578
579 sgtc = 100 * m * latency;
580 sgtc = sgtc / 3;
581 if (sgtc > 0xfffff) {
582 printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);
583 sgtc = 0xfffff;
584 }
585 return sgtc;
586}
587
588static unsigned int powernow_get(unsigned int cpu)
589{
590 union msr_fidvidstatus fidvidstatus;
591 unsigned int cfid;
592
593 if (cpu)
594 return 0;
Dave Jonesb9e76382009-01-18 00:32:26 -0500595 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 cfid = fidvidstatus.bits.CFID;
597
Dave Jonesb9e76382009-01-18 00:32:26 -0500598 return fsb * fid_codes[cfid] / 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599}
600
601
Holger Freyther307069c2010-07-19 03:29:16 +0800602static int __cpuinit acer_cpufreq_pst(const struct dmi_system_id *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Dave Jonesb9e76382009-01-18 00:32:26 -0500604 printk(KERN_WARNING PFX
605 "%s laptop with broken PST tables in BIOS detected.\n",
606 d->ident);
607 printk(KERN_WARNING PFX
608 "You need to downgrade to 3A21 (09/09/2002), or try a newer "
609 "BIOS than 3A71 (01/20/2003)\n");
610 printk(KERN_WARNING PFX
611 "cpufreq scaling has been disabled as a result of this.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return 0;
613}
614
615/*
616 * Some Athlon laptops have really fucked PST tables.
617 * A BIOS update is all that can save them.
618 * Mention this, and disable cpufreq.
619 */
Holger Freyther307069c2010-07-19 03:29:16 +0800620static struct dmi_system_id __cpuinitdata powernow_dmi_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 {
622 .callback = acer_cpufreq_pst,
623 .ident = "Acer Aspire",
624 .matches = {
625 DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
626 DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
627 },
628 },
629 { }
630};
631
Holger Freyther307069c2010-07-19 03:29:16 +0800632static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
634 union msr_fidvidstatus fidvidstatus;
635 int result;
636
637 if (policy->cpu != 0)
638 return -ENODEV;
639
Dave Jonesb9e76382009-01-18 00:32:26 -0500640 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Dave Jones436fe7b2006-06-05 14:03:50 -0400642 recalibrate_cpu_khz();
Dave Jones91350ed2005-05-31 19:03:45 -0700643
644 fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (!fsb) {
646 printk(KERN_WARNING PFX "can not determine bus frequency\n");
647 return -EINVAL;
648 }
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200649 pr_debug("FSB: %3dMHz\n", fsb/1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 if (dmi_check_system(powernow_dmi_table) || acpi_force) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500652 printk(KERN_INFO PFX "PSB/PST known to be broken. "
653 "Trying ACPI instead\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 result = powernow_acpi_init();
655 } else {
Dave Jonesb9e76382009-01-18 00:32:26 -0500656 result = powernow_decode_bios(fidvidstatus.bits.MFID,
657 fidvidstatus.bits.SVID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if (result) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500659 printk(KERN_INFO PFX "Trying ACPI perflib\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 maximum_speed = 0;
661 minimum_speed = -1;
662 latency = 0;
663 result = powernow_acpi_init();
664 if (result) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500665 printk(KERN_INFO PFX
666 "ACPI and legacy methods failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668 } else {
669 /* SGTC use the bus clock as timer */
670 latency = fixup_sgtc();
671 printk(KERN_INFO PFX "SGTC: %d\n", latency);
672 }
673 }
674
675 if (result)
676 return result;
677
Dave Jonesb9e76382009-01-18 00:32:26 -0500678 printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 minimum_speed/1000, maximum_speed/1000);
680
Dave Jonesb9e76382009-01-18 00:32:26 -0500681 policy->cpuinfo.transition_latency =
682 cpufreq_scale(2000000UL, fsb, latency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 policy->cur = powernow_get(0);
685
686 cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
687
688 return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
689}
690
Dave Jonesb9e76382009-01-18 00:32:26 -0500691static int powernow_cpu_exit(struct cpufreq_policy *policy)
692{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 cpufreq_frequency_table_put_attr(policy->cpu);
694
695#ifdef CONFIG_X86_POWERNOW_K7_ACPI
696 if (acpi_processor_perf) {
697 acpi_processor_unregister_performance(acpi_processor_perf, 0);
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800698 free_cpumask_var(acpi_processor_perf->shared_cpu_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 kfree(acpi_processor_perf);
700 }
701#endif
702
Jesper Juhl4ae66732005-06-25 14:58:48 -0700703 kfree(powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return 0;
705}
706
Dave Jonesb9e76382009-01-18 00:32:26 -0500707static struct freq_attr *powernow_table_attr[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 &cpufreq_freq_attr_scaling_available_freqs,
709 NULL,
710};
711
Linus Torvalds221dee22007-02-26 14:55:48 -0800712static struct cpufreq_driver powernow_driver = {
Thomas Renningere2f74f32009-11-19 12:31:01 +0100713 .verify = powernow_verify,
714 .target = powernow_target,
715 .get = powernow_get,
716#ifdef CONFIG_X86_POWERNOW_K7_ACPI
717 .bios_limit = acpi_processor_get_bios_limit,
718#endif
719 .init = powernow_cpu_init,
720 .exit = powernow_cpu_exit,
721 .name = "powernow-k7",
722 .owner = THIS_MODULE,
723 .attr = powernow_table_attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724};
725
Dave Jonesb9e76382009-01-18 00:32:26 -0500726static int __init powernow_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727{
Dave Jonesb9e76382009-01-18 00:32:26 -0500728 if (check_powernow() == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return -ENODEV;
730 return cpufreq_register_driver(&powernow_driver);
731}
732
733
Dave Jonesb9e76382009-01-18 00:32:26 -0500734static void __exit powernow_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
736 cpufreq_unregister_driver(&powernow_driver);
737}
738
739module_param(acpi_force, int, 0444);
740MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
741
Dave Jonesb9e76382009-01-18 00:32:26 -0500742MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
743MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
744MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746late_initcall(powernow_init);
747module_exit(powernow_exit);
748