blob: d98529c93a1c6848e0288c94fe7aae2ee88f7bb6 [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;
344 unsigned int speed;
345
346 pc.val = (unsigned long) acpi_processor_perf->states[i].control;
347 dprintk ("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
348 i,
349 (u32) acpi_processor_perf->states[i].core_frequency,
350 (u32) acpi_processor_perf->states[i].power,
351 (u32) acpi_processor_perf->states[i].transition_latency,
352 (u32) acpi_processor_perf->states[i].control,
353 pc.bits.sgtc);
354
355 vid = pc.bits.vid;
356 fid = pc.bits.fid;
357
358 powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
359 powernow_table[i].index = fid; /* lower 8 bits */
360 powernow_table[i].index |= (vid << 8); /* upper 8 bits */
361
362 speed = powernow_table[i].frequency;
363
364 if ((fid_codes[fid] % 10)==5) {
365 if (have_a0 == 1)
366 powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
367 }
368
369 dprintk (" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500370 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
371 fid_codes[fid] % 10, speed/1000, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 mobile_vid_table[vid]/1000,
373 mobile_vid_table[vid]%1000);
374
375 if (latency < pc.bits.sgtc)
376 latency = pc.bits.sgtc;
377
378 if (speed < minimum_speed)
379 minimum_speed = speed;
380 if (speed > maximum_speed)
381 maximum_speed = speed;
382 }
383
384 powernow_table[i].frequency = CPUFREQ_TABLE_END;
385 powernow_table[i].index = 0;
386
387 /* notify BIOS that we exist */
388 acpi_processor_notify_smm(THIS_MODULE);
389
390 return 0;
391
392err2:
393 acpi_processor_unregister_performance(acpi_processor_perf, 0);
394err1:
395 kfree(acpi_processor_perf);
396err0:
397 printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n");
398 acpi_processor_perf = NULL;
399 return retval;
400}
401#else
402static int powernow_acpi_init(void)
403{
404 printk(KERN_INFO PFX "no support for ACPI processor found."
405 " Please recompile your kernel with ACPI processor\n");
406 return -EINVAL;
407}
408#endif
409
410static int powernow_decode_bios (int maxfid, int startvid)
411{
412 struct psb_s *psb;
413 struct pst_s *pst;
414 unsigned int i, j;
415 unsigned char *p;
416 unsigned int etuple;
417 unsigned int ret;
418
419 etuple = cpuid_eax(0x80000001);
420
421 for (i=0xC0000; i < 0xffff0 ; i+=16) {
422
423 p = phys_to_virt(i);
424
425 if (memcmp(p, "AMDK7PNOW!", 10) == 0){
426 dprintk ("Found PSB header at %p\n", p);
427 psb = (struct psb_s *) p;
428 dprintk ("Table version: 0x%x\n", psb->tableversion);
429 if (psb->tableversion != 0x12) {
430 printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n");
431 return -ENODEV;
432 }
433
434 dprintk ("Flags: 0x%x\n", psb->flags);
435 if ((psb->flags & 1)==0) {
436 dprintk ("Mobile voltage regulator\n");
437 } else {
438 dprintk ("Desktop voltage regulator\n");
439 }
440
441 latency = psb->settlingtime;
442 if (latency < 100) {
443 printk (KERN_INFO PFX "BIOS set settling time to %d microseconds."
444 "Should be at least 100. Correcting.\n", latency);
445 latency = 100;
446 }
447 dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime);
448 dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst);
449
450 p += sizeof (struct psb_s);
451
452 pst = (struct pst_s *) p;
453
Dave Jones8cbe0162006-05-30 17:26:08 -0400454 for (j=0; j<psb->numpst; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pst = (struct pst_s *) p;
456 number_scales = pst->numpstates;
457
458 if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) &&
459 (maxfid==pst->maxfid) && (startvid==pst->startvid))
460 {
Dave Jones8cbe0162006-05-30 17:26:08 -0400461 dprintk ("PST:%d (@%p)\n", j, pst);
Dave Jones32ee8c32006-02-28 00:43:23 -0500462 dprintk (" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
464
465 ret = get_ranges ((char *) pst + sizeof (struct pst_s));
466 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 } else {
Dave Jones8cbe0162006-05-30 17:26:08 -0400468 unsigned int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 p = (char *) pst + sizeof (struct pst_s);
Dave Jones8cbe0162006-05-30 17:26:08 -0400470 for (k=0; k<number_scales; k++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 p+=2;
472 }
473 }
474 printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple);
475 printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n");
476
477 return -EINVAL;
478 }
479 p++;
480 }
481
482 return -ENODEV;
483}
484
485
486static int powernow_target (struct cpufreq_policy *policy,
487 unsigned int target_freq,
488 unsigned int relation)
489{
490 unsigned int newstate;
491
492 if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate))
493 return -EINVAL;
494
495 change_speed(newstate);
496
497 return 0;
498}
499
500
501static int powernow_verify (struct cpufreq_policy *policy)
502{
503 return cpufreq_frequency_table_verify(policy, powernow_table);
504}
505
506/*
507 * We use the fact that the bus frequency is somehow
508 * a multiple of 100000/3 khz, then we compute sgtc according
509 * to this multiple.
510 * That way, we match more how AMD thinks all of that work.
511 * We will then get the same kind of behaviour already tested under
512 * the "well-known" other OS.
513 */
514static int __init fixup_sgtc(void)
515{
516 unsigned int sgtc;
517 unsigned int m;
518
519 m = fsb / 3333;
520 if ((m % 10) >= 5)
521 m += 5;
522
523 m /= 10;
524
525 sgtc = 100 * m * latency;
526 sgtc = sgtc / 3;
527 if (sgtc > 0xfffff) {
528 printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);
529 sgtc = 0xfffff;
530 }
531 return sgtc;
532}
533
534static unsigned int powernow_get(unsigned int cpu)
535{
536 union msr_fidvidstatus fidvidstatus;
537 unsigned int cfid;
538
539 if (cpu)
540 return 0;
541 rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
542 cfid = fidvidstatus.bits.CFID;
543
544 return (fsb * fid_codes[cfid] / 10);
545}
546
547
548static int __init acer_cpufreq_pst(struct dmi_system_id *d)
549{
550 printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);
551 printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
552 printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");
553 return 0;
554}
555
556/*
557 * Some Athlon laptops have really fucked PST tables.
558 * A BIOS update is all that can save them.
559 * Mention this, and disable cpufreq.
560 */
561static struct dmi_system_id __initdata powernow_dmi_table[] = {
562 {
563 .callback = acer_cpufreq_pst,
564 .ident = "Acer Aspire",
565 .matches = {
566 DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
567 DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
568 },
569 },
570 { }
571};
572
573static int __init powernow_cpu_init (struct cpufreq_policy *policy)
574{
575 union msr_fidvidstatus fidvidstatus;
576 int result;
577
578 if (policy->cpu != 0)
579 return -ENODEV;
580
581 rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
582
Dave Jones436fe7b2006-06-05 14:03:50 -0400583 recalibrate_cpu_khz();
Dave Jones91350ed2005-05-31 19:03:45 -0700584
585 fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (!fsb) {
587 printk(KERN_WARNING PFX "can not determine bus frequency\n");
588 return -EINVAL;
589 }
Dave Jones7eb53d82005-05-31 19:03:42 -0700590 dprintk("FSB: %3dMHz\n", fsb/1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 if (dmi_check_system(powernow_dmi_table) || acpi_force) {
593 printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n");
594 result = powernow_acpi_init();
595 } else {
596 result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID);
597 if (result) {
598 printk (KERN_INFO PFX "Trying ACPI perflib\n");
599 maximum_speed = 0;
600 minimum_speed = -1;
601 latency = 0;
602 result = powernow_acpi_init();
603 if (result) {
604 printk (KERN_INFO PFX "ACPI and legacy methods failed\n");
605 printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.shtml\n");
606 }
607 } else {
608 /* SGTC use the bus clock as timer */
609 latency = fixup_sgtc();
610 printk(KERN_INFO PFX "SGTC: %d\n", latency);
611 }
612 }
613
614 if (result)
615 return result;
616
617 printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
618 minimum_speed/1000, maximum_speed/1000);
619
620 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
621
622 policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
623
624 policy->cur = powernow_get(0);
625
626 cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
627
628 return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
629}
630
631static int powernow_cpu_exit (struct cpufreq_policy *policy) {
632 cpufreq_frequency_table_put_attr(policy->cpu);
633
634#ifdef CONFIG_X86_POWERNOW_K7_ACPI
635 if (acpi_processor_perf) {
636 acpi_processor_unregister_performance(acpi_processor_perf, 0);
637 kfree(acpi_processor_perf);
638 }
639#endif
640
Jesper Juhl4ae66732005-06-25 14:58:48 -0700641 kfree(powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return 0;
643}
644
645static struct freq_attr* powernow_table_attr[] = {
646 &cpufreq_freq_attr_scaling_available_freqs,
647 NULL,
648};
649
Dave Jonesaeeddc12007-02-22 19:08:27 -0500650static const struct cpufreq_driver powernow_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 .verify = powernow_verify,
652 .target = powernow_target,
653 .get = powernow_get,
654 .init = powernow_cpu_init,
655 .exit = powernow_cpu_exit,
656 .name = "powernow-k7",
657 .owner = THIS_MODULE,
658 .attr = powernow_table_attr,
659};
660
661static int __init powernow_init (void)
662{
663 if (check_powernow()==0)
664 return -ENODEV;
665 return cpufreq_register_driver(&powernow_driver);
666}
667
668
669static void __exit powernow_exit (void)
670{
671 cpufreq_unregister_driver(&powernow_driver);
672}
673
674module_param(acpi_force, int, 0444);
675MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
676
677MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
678MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
679MODULE_LICENSE ("GPL");
680
681late_initcall(powernow_init);
682module_exit(powernow_exit);
683