blob: ca3e1d341889dfc00964fd2d052e13d9108d8562 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * AMD K7 Powernow driver.
3 * (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs.
4 * (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 *
9 * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt.
10 * - We cli/sti on stepping A0 CPUs around the FID/VID transition.
11 * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
12 * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/init.h>
19#include <linux/cpufreq.h>
20#include <linux/slab.h>
21#include <linux/string.h>
22#include <linux/dmi.h>
23
24#include <asm/msr.h>
Dave Jones91350ed2005-05-31 19:03:45 -070025#include <asm/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/timex.h>
27#include <asm/io.h>
28#include <asm/system.h>
29
30#ifdef CONFIG_X86_POWERNOW_K7_ACPI
31#include <linux/acpi.h>
32#include <acpi/processor.h>
33#endif
34
35#include "powernow-k7.h"
36
37#define PFX "powernow: "
38
39
40struct psb_s {
41 u8 signature[10];
42 u8 tableversion;
43 u8 flags;
44 u16 settlingtime;
45 u8 reserved1;
46 u8 numpst;
47};
48
49struct pst_s {
50 u32 cpuid;
51 u8 fsbspeed;
52 u8 maxfid;
53 u8 startvid;
54 u8 numpstates;
55};
56
57#ifdef CONFIG_X86_POWERNOW_K7_ACPI
58union powernow_acpi_control_t {
59 struct {
60 unsigned long fid:5,
61 vid:5,
62 sgtc:20,
63 res1:2;
64 } bits;
65 unsigned long val;
66};
67#endif
68
69#ifdef CONFIG_CPU_FREQ_DEBUG
70/* divide by 1000 to get VCore voltage in V. */
Dave Jonesbd5ab262007-02-22 19:11:16 -050071static const int mobile_vid_table[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
73 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
74 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
75 1075, 1050, 1025, 1000, 975, 950, 925, 0,
76};
77#endif
78
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;
97static unsigned int minimum_speed=-1;
98static unsigned int maximum_speed;
99static unsigned int number_scales;
100static unsigned int fsb;
101static unsigned int latency;
102static char have_a0;
103
104#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k7", msg)
105
106static int check_fsb(unsigned int fsbspeed)
107{
108 int delta;
109 unsigned int f = fsb / 1000;
110
111 delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
112 return (delta < 5);
113}
114
115static int check_powernow(void)
116{
117 struct cpuinfo_x86 *c = cpu_data;
118 unsigned int maxei, eax, ebx, ecx, edx;
119
120 if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 !=6)) {
121#ifdef MODULE
122 printk (KERN_INFO PFX "This module only works with AMD K7 CPUs\n");
123#endif
124 return 0;
125 }
126
127 /* Get maximum capabilities */
128 maxei = cpuid_eax (0x80000000);
129 if (maxei < 0x80000007) { /* Any powernow info ? */
130#ifdef MODULE
131 printk (KERN_INFO PFX "No powernow capabilities detected\n");
132#endif
133 return 0;
134 }
135
136 if ((c->x86_model == 6) && (c->x86_mask == 0)) {
137 printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n");
138 have_a0 = 1;
139 }
140
141 cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
142
143 /* Check we can actually do something before we say anything.*/
144 if (!(edx & (1 << 1 | 1 << 2)))
145 return 0;
146
147 printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
148
149 if (edx & 1 << 1) {
150 printk ("frequency");
151 can_scale_bus=1;
152 }
153
154 if ((edx & (1 << 1 | 1 << 2)) == 0x6)
155 printk (" and ");
156
157 if (edx & 1 << 2) {
158 printk ("voltage");
159 can_scale_vid=1;
160 }
161
162 printk (".\n");
163 return 1;
164}
165
166
167static int get_ranges (unsigned char *pst)
168{
169 unsigned int j;
170 unsigned int speed;
171 u8 fid, vid;
172
Dave Jonesbfdc7082005-10-20 15:16:15 -0700173 powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (!powernow_table)
175 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177 for (j=0 ; j < number_scales; j++) {
178 fid = *pst++;
179
180 powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
181 powernow_table[j].index = fid; /* lower 8 bits */
182
183 speed = powernow_table[j].frequency;
184
185 if ((fid_codes[fid] % 10)==5) {
186#ifdef CONFIG_X86_POWERNOW_K7_ACPI
187 if (have_a0 == 1)
188 powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
189#endif
190 }
191
192 if (speed < minimum_speed)
193 minimum_speed = speed;
194 if (speed > maximum_speed)
195 maximum_speed = speed;
196
197 vid = *pst++;
198 powernow_table[j].index |= (vid << 8); /* upper 8 bits */
199
200 dprintk (" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500201 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
202 fid_codes[fid] % 10, speed/1000, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 mobile_vid_table[vid]/1000,
204 mobile_vid_table[vid]%1000);
205 }
206 powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
207 powernow_table[number_scales].index = 0;
208
209 return 0;
210}
211
212
213static void change_FID(int fid)
214{
215 union msr_fidvidctl fidvidctl;
216
217 rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
218 if (fidvidctl.bits.FID != fid) {
219 fidvidctl.bits.SGTC = latency;
220 fidvidctl.bits.FID = fid;
221 fidvidctl.bits.VIDC = 0;
222 fidvidctl.bits.FIDC = 1;
223 wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
224 }
225}
226
227
228static void change_VID(int vid)
229{
230 union msr_fidvidctl fidvidctl;
231
232 rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
233 if (fidvidctl.bits.VID != vid) {
234 fidvidctl.bits.SGTC = latency;
235 fidvidctl.bits.VID = vid;
236 fidvidctl.bits.FIDC = 0;
237 fidvidctl.bits.VIDC = 1;
238 wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
239 }
240}
241
242
243static void change_speed (unsigned int index)
244{
245 u8 fid, vid;
246 struct cpufreq_freqs freqs;
247 union msr_fidvidstatus fidvidstatus;
248 int cfid;
249
250 /* fid are the lower 8 bits of the index we stored into
251 * the cpufreq frequency table in powernow_decode_bios,
252 * vid are the upper 8 bits.
253 */
254
255 fid = powernow_table[index].index & 0xFF;
256 vid = (powernow_table[index].index & 0xFF00) >> 8;
257
258 freqs.cpu = 0;
259
260 rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
261 cfid = fidvidstatus.bits.CFID;
262 freqs.old = fsb * fid_codes[cfid] / 10;
263
264 freqs.new = powernow_table[index].frequency;
265
266 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
267
268 /* Now do the magic poking into the MSRs. */
269
270 if (have_a0 == 1) /* A0 errata 5 */
271 local_irq_disable();
272
273 if (freqs.old > freqs.new) {
274 /* Going down, so change FID first */
275 change_FID(fid);
276 change_VID(vid);
277 } else {
278 /* Going up, so change VID first */
279 change_VID(vid);
280 change_FID(fid);
281 }
282
283
284 if (have_a0 == 1)
285 local_irq_enable();
286
287 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
288}
289
290
291#ifdef CONFIG_X86_POWERNOW_K7_ACPI
292
293static struct acpi_processor_performance *acpi_processor_perf;
294
295static int powernow_acpi_init(void)
296{
297 int i;
298 int retval = 0;
299 union powernow_acpi_control_t pc;
300
301 if (acpi_processor_perf != NULL && powernow_table != NULL) {
302 retval = -EINVAL;
303 goto err0;
304 }
305
Dave Jonesbfdc7082005-10-20 15:16:15 -0700306 acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (!acpi_processor_perf) {
309 retval = -ENOMEM;
310 goto err0;
311 }
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
314 retval = -EIO;
315 goto err1;
316 }
317
318 if (acpi_processor_perf->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
319 retval = -ENODEV;
320 goto err2;
321 }
322
323 if (acpi_processor_perf->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
324 retval = -ENODEV;
325 goto err2;
326 }
327
328 number_scales = acpi_processor_perf->state_count;
329
330 if (number_scales < 2) {
331 retval = -ENODEV;
332 goto err2;
333 }
334
Dave Jonesbfdc7082005-10-20 15:16:15 -0700335 powernow_table = kzalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 if (!powernow_table) {
337 retval = -ENOMEM;
338 goto err2;
339 }
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 pc.val = (unsigned long) acpi_processor_perf->states[0].control;
342 for (i = 0; i < number_scales; i++) {
343 u8 fid, vid;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100344 struct acpi_processor_px *state =
345 &acpi_processor_perf->states[i];
346 unsigned int speed, speed_mhz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Daniel Drakedc2585e2007-05-02 23:19:05 +0100348 pc.val = (unsigned long) state->control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 dprintk ("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
350 i,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100351 (u32) state->core_frequency,
352 (u32) state->power,
353 (u32) state->transition_latency,
354 (u32) state->control,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 pc.bits.sgtc);
356
357 vid = pc.bits.vid;
358 fid = pc.bits.fid;
359
360 powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
361 powernow_table[i].index = fid; /* lower 8 bits */
362 powernow_table[i].index |= (vid << 8); /* upper 8 bits */
363
364 speed = powernow_table[i].frequency;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100365 speed_mhz = speed / 1000;
366
367 /* processor_perflib will multiply the MHz value by 1000 to
368 * get a KHz value (e.g. 1266000). However, powernow-k7 works
369 * with true KHz values (e.g. 1266768). To ensure that all
370 * powernow frequencies are available, we must ensure that
371 * ACPI doesn't restrict them, so we round up the MHz value
372 * to ensure that perflib's computed KHz value is greater than
373 * or equal to powernow's KHz value.
374 */
375 if (speed % 1000 > 0)
376 speed_mhz++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 if ((fid_codes[fid] % 10)==5) {
379 if (have_a0 == 1)
380 powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
381 }
382
383 dprintk (" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500384 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100385 fid_codes[fid] % 10, speed_mhz, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 mobile_vid_table[vid]/1000,
387 mobile_vid_table[vid]%1000);
388
Daniel Drakedc2585e2007-05-02 23:19:05 +0100389 if (state->core_frequency != speed_mhz) {
390 state->core_frequency = speed_mhz;
391 dprintk(" Corrected ACPI frequency to %d\n",
392 speed_mhz);
393 }
394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 if (latency < pc.bits.sgtc)
396 latency = pc.bits.sgtc;
397
398 if (speed < minimum_speed)
399 minimum_speed = speed;
400 if (speed > maximum_speed)
401 maximum_speed = speed;
402 }
403
404 powernow_table[i].frequency = CPUFREQ_TABLE_END;
405 powernow_table[i].index = 0;
406
407 /* notify BIOS that we exist */
408 acpi_processor_notify_smm(THIS_MODULE);
409
410 return 0;
411
412err2:
413 acpi_processor_unregister_performance(acpi_processor_perf, 0);
414err1:
415 kfree(acpi_processor_perf);
416err0:
417 printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n");
418 acpi_processor_perf = NULL;
419 return retval;
420}
421#else
422static int powernow_acpi_init(void)
423{
424 printk(KERN_INFO PFX "no support for ACPI processor found."
425 " Please recompile your kernel with ACPI processor\n");
426 return -EINVAL;
427}
428#endif
429
430static int powernow_decode_bios (int maxfid, int startvid)
431{
432 struct psb_s *psb;
433 struct pst_s *pst;
434 unsigned int i, j;
435 unsigned char *p;
436 unsigned int etuple;
437 unsigned int ret;
438
439 etuple = cpuid_eax(0x80000001);
440
441 for (i=0xC0000; i < 0xffff0 ; i+=16) {
442
443 p = phys_to_virt(i);
444
445 if (memcmp(p, "AMDK7PNOW!", 10) == 0){
446 dprintk ("Found PSB header at %p\n", p);
447 psb = (struct psb_s *) p;
448 dprintk ("Table version: 0x%x\n", psb->tableversion);
449 if (psb->tableversion != 0x12) {
450 printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n");
451 return -ENODEV;
452 }
453
454 dprintk ("Flags: 0x%x\n", psb->flags);
455 if ((psb->flags & 1)==0) {
456 dprintk ("Mobile voltage regulator\n");
457 } else {
458 dprintk ("Desktop voltage regulator\n");
459 }
460
461 latency = psb->settlingtime;
462 if (latency < 100) {
463 printk (KERN_INFO PFX "BIOS set settling time to %d microseconds."
464 "Should be at least 100. Correcting.\n", latency);
465 latency = 100;
466 }
467 dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime);
468 dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst);
469
470 p += sizeof (struct psb_s);
471
472 pst = (struct pst_s *) p;
473
Dave Jones8cbe0162006-05-30 17:26:08 -0400474 for (j=0; j<psb->numpst; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 pst = (struct pst_s *) p;
476 number_scales = pst->numpstates;
477
478 if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) &&
479 (maxfid==pst->maxfid) && (startvid==pst->startvid))
480 {
Dave Jones8cbe0162006-05-30 17:26:08 -0400481 dprintk ("PST:%d (@%p)\n", j, pst);
Dave Jones32ee8c32006-02-28 00:43:23 -0500482 dprintk (" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
484
485 ret = get_ranges ((char *) pst + sizeof (struct pst_s));
486 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 } else {
Dave Jones8cbe0162006-05-30 17:26:08 -0400488 unsigned int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 p = (char *) pst + sizeof (struct pst_s);
Dave Jones8cbe0162006-05-30 17:26:08 -0400490 for (k=0; k<number_scales; k++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 p+=2;
492 }
493 }
494 printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple);
495 printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n");
496
497 return -EINVAL;
498 }
499 p++;
500 }
501
502 return -ENODEV;
503}
504
505
506static int powernow_target (struct cpufreq_policy *policy,
507 unsigned int target_freq,
508 unsigned int relation)
509{
510 unsigned int newstate;
511
512 if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate))
513 return -EINVAL;
514
515 change_speed(newstate);
516
517 return 0;
518}
519
520
521static int powernow_verify (struct cpufreq_policy *policy)
522{
523 return cpufreq_frequency_table_verify(policy, powernow_table);
524}
525
526/*
527 * We use the fact that the bus frequency is somehow
528 * a multiple of 100000/3 khz, then we compute sgtc according
529 * to this multiple.
530 * That way, we match more how AMD thinks all of that work.
531 * We will then get the same kind of behaviour already tested under
532 * the "well-known" other OS.
533 */
534static int __init fixup_sgtc(void)
535{
536 unsigned int sgtc;
537 unsigned int m;
538
539 m = fsb / 3333;
540 if ((m % 10) >= 5)
541 m += 5;
542
543 m /= 10;
544
545 sgtc = 100 * m * latency;
546 sgtc = sgtc / 3;
547 if (sgtc > 0xfffff) {
548 printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);
549 sgtc = 0xfffff;
550 }
551 return sgtc;
552}
553
554static unsigned int powernow_get(unsigned int cpu)
555{
556 union msr_fidvidstatus fidvidstatus;
557 unsigned int cfid;
558
559 if (cpu)
560 return 0;
561 rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
562 cfid = fidvidstatus.bits.CFID;
563
564 return (fsb * fid_codes[cfid] / 10);
565}
566
567
568static int __init acer_cpufreq_pst(struct dmi_system_id *d)
569{
570 printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);
571 printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
572 printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");
573 return 0;
574}
575
576/*
577 * Some Athlon laptops have really fucked PST tables.
578 * A BIOS update is all that can save them.
579 * Mention this, and disable cpufreq.
580 */
581static struct dmi_system_id __initdata powernow_dmi_table[] = {
582 {
583 .callback = acer_cpufreq_pst,
584 .ident = "Acer Aspire",
585 .matches = {
586 DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
587 DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
588 },
589 },
590 { }
591};
592
593static int __init powernow_cpu_init (struct cpufreq_policy *policy)
594{
595 union msr_fidvidstatus fidvidstatus;
596 int result;
597
598 if (policy->cpu != 0)
599 return -ENODEV;
600
601 rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
602
Dave Jones436fe7b2006-06-05 14:03:50 -0400603 recalibrate_cpu_khz();
Dave Jones91350ed2005-05-31 19:03:45 -0700604
605 fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (!fsb) {
607 printk(KERN_WARNING PFX "can not determine bus frequency\n");
608 return -EINVAL;
609 }
Dave Jones7eb53d82005-05-31 19:03:42 -0700610 dprintk("FSB: %3dMHz\n", fsb/1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 if (dmi_check_system(powernow_dmi_table) || acpi_force) {
613 printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n");
614 result = powernow_acpi_init();
615 } else {
616 result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID);
617 if (result) {
618 printk (KERN_INFO PFX "Trying ACPI perflib\n");
619 maximum_speed = 0;
620 minimum_speed = -1;
621 latency = 0;
622 result = powernow_acpi_init();
623 if (result) {
624 printk (KERN_INFO PFX "ACPI and legacy methods failed\n");
Daniel Drakedc2585e2007-05-02 23:19:05 +0100625 printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.html\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
627 } else {
628 /* SGTC use the bus clock as timer */
629 latency = fixup_sgtc();
630 printk(KERN_INFO PFX "SGTC: %d\n", latency);
631 }
632 }
633
634 if (result)
635 return result;
636
637 printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
638 minimum_speed/1000, maximum_speed/1000);
639
640 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
641
642 policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
643
644 policy->cur = powernow_get(0);
645
646 cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
647
648 return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
649}
650
651static int powernow_cpu_exit (struct cpufreq_policy *policy) {
652 cpufreq_frequency_table_put_attr(policy->cpu);
653
654#ifdef CONFIG_X86_POWERNOW_K7_ACPI
655 if (acpi_processor_perf) {
656 acpi_processor_unregister_performance(acpi_processor_perf, 0);
657 kfree(acpi_processor_perf);
658 }
659#endif
660
Jesper Juhl4ae66732005-06-25 14:58:48 -0700661 kfree(powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return 0;
663}
664
665static struct freq_attr* powernow_table_attr[] = {
666 &cpufreq_freq_attr_scaling_available_freqs,
667 NULL,
668};
669
Linus Torvalds221dee22007-02-26 14:55:48 -0800670static struct cpufreq_driver powernow_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 .verify = powernow_verify,
672 .target = powernow_target,
673 .get = powernow_get,
674 .init = powernow_cpu_init,
675 .exit = powernow_cpu_exit,
676 .name = "powernow-k7",
677 .owner = THIS_MODULE,
678 .attr = powernow_table_attr,
679};
680
681static int __init powernow_init (void)
682{
683 if (check_powernow()==0)
684 return -ENODEV;
685 return cpufreq_register_driver(&powernow_driver);
686}
687
688
689static void __exit powernow_exit (void)
690{
691 cpufreq_unregister_driver(&powernow_driver);
692}
693
694module_param(acpi_force, int, 0444);
695MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
696
697MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
698MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
699MODULE_LICENSE ("GPL");
700
701late_initcall(powernow_init);
702module_exit(powernow_exit);
703