blob: 37c5742482d8cf4b5a58218cc84f36135184bb06 [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 *
5 * Licensed under the terms of the GNU GPL License version 2.
6 * Based upon datasheets & sample CPUs kindly provided by AMD.
7 *
Dave Jonesb9e76382009-01-18 00:32:26 -05008 * Errata 5:
9 * CPU 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:
12 * CPU with half frequency multipliers may hang upon wakeup from disconnect.
13 * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 */
15
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/init.h>
20#include <linux/cpufreq.h>
21#include <linux/slab.h>
22#include <linux/string.h>
23#include <linux/dmi.h>
Dave Jonesb9e76382009-01-18 00:32:26 -050024#include <linux/timex.h>
25#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Dave Jonesb9e76382009-01-18 00:32:26 -050027#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/msr.h>
Andi Kleenfa8031a2012-01-26 00:09:12 +010029#include <asm/cpu_device_id.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#ifdef CONFIG_X86_POWERNOW_K7_ACPI
32#include <linux/acpi.h>
33#include <acpi/processor.h>
34#endif
35
36#include "powernow-k7.h"
37
38#define PFX "powernow: "
39
40
41struct psb_s {
42 u8 signature[10];
43 u8 tableversion;
44 u8 flags;
45 u16 settlingtime;
46 u8 reserved1;
47 u8 numpst;
48};
49
50struct pst_s {
51 u32 cpuid;
52 u8 fsbspeed;
53 u8 maxfid;
54 u8 startvid;
55 u8 numpstates;
56};
57
58#ifdef CONFIG_X86_POWERNOW_K7_ACPI
59union powernow_acpi_control_t {
60 struct {
61 unsigned long fid:5,
Dave Jonesb9e76382009-01-18 00:32:26 -050062 vid:5,
63 sgtc:20,
64 res1:2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 } bits;
66 unsigned long val;
67};
68#endif
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/* 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};
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78/* divide by 10 to get FID. */
Dave Jonesbd5ab262007-02-22 19:11:16 -050079static const int fid_codes[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 110, 115, 120, 125, 50, 55, 60, 65,
81 70, 75, 80, 85, 90, 95, 100, 105,
82 30, 190, 40, 200, 130, 135, 140, 210,
83 150, 225, 160, 165, 170, 180, -1, -1,
84};
85
86/* This parameter is used in order to force ACPI instead of legacy method for
87 * configuration purpose.
88 */
89
90static int acpi_force;
91
92static struct cpufreq_frequency_table *powernow_table;
93
94static unsigned int can_scale_bus;
95static unsigned int can_scale_vid;
Dave Jonesfff78ad2009-01-17 22:28:42 -050096static unsigned int minimum_speed = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static unsigned int maximum_speed;
98static unsigned int number_scales;
99static unsigned int fsb;
100static unsigned int latency;
101static char have_a0;
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static int check_fsb(unsigned int fsbspeed)
104{
105 int delta;
106 unsigned int f = fsb / 1000;
107
108 delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
Dave Jonesb9e76382009-01-18 00:32:26 -0500109 return delta < 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110}
111
Andi Kleenfa8031a2012-01-26 00:09:12 +0100112static const struct x86_cpu_id powernow_k7_cpuids[] = {
Ben Hutchings30bcfff2012-02-11 22:58:14 +0000113 { X86_VENDOR_AMD, 6, },
Andi Kleenfa8031a2012-01-26 00:09:12 +0100114 {}
115};
116MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118static int check_powernow(void)
119{
Mike Travis92cb7612007-10-19 20:35:04 +0200120 struct cpuinfo_x86 *c = &cpu_data(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 unsigned int maxei, eax, ebx, ecx, edx;
122
Andi Kleenfa8031a2012-01-26 00:09:12 +0100123 if (!x86_match_cpu(powernow_k7_cpuids))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 /* Get maximum capabilities */
Dave Jonesb9e76382009-01-18 00:32:26 -0500127 maxei = cpuid_eax(0x80000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 if (maxei < 0x80000007) { /* Any powernow info ? */
129#ifdef MODULE
Dave Jonesb9e76382009-01-18 00:32:26 -0500130 printk(KERN_INFO PFX "No powernow capabilities detected\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131#endif
132 return 0;
133 }
134
135 if ((c->x86_model == 6) && (c->x86_mask == 0)) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500136 printk(KERN_INFO PFX "K7 660[A0] core detected, "
137 "enabling errata workarounds\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 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
Dave Jonesb9e76382009-01-18 00:32:26 -0500147 printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 if (edx & 1 << 1) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500150 printk("frequency");
151 can_scale_bus = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
153
154 if ((edx & (1 << 1 | 1 << 2)) == 0x6)
Dave Jonesb9e76382009-01-18 00:32:26 -0500155 printk(" and ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 if (edx & 1 << 2) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500158 printk("voltage");
159 can_scale_vid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161
Dave Jonesb9e76382009-01-18 00:32:26 -0500162 printk(".\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 return 1;
164}
165
Dave Jonesd38e73e2009-04-23 13:36:12 -0400166#ifdef CONFIG_X86_POWERNOW_K7_ACPI
Dave Jonesb9e76382009-01-18 00:32:26 -0500167static void invalidate_entry(unsigned int entry)
168{
169 powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
170}
Dave Jonesd38e73e2009-04-23 13:36:12 -0400171#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Dave Jonesb9e76382009-01-18 00:32:26 -0500173static int get_ranges(unsigned char *pst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 unsigned int j;
176 unsigned int speed;
177 u8 fid, vid;
178
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530179 powernow_table = kzalloc((sizeof(*powernow_table) *
Dave Jonesb9e76382009-01-18 00:32:26 -0500180 (number_scales + 1)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 if (!powernow_table)
182 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Dave Jonesb9e76382009-01-18 00:32:26 -0500184 for (j = 0 ; j < number_scales; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 fid = *pst++;
186
187 powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
Viresh Kumar50701582013-03-30 16:25:15 +0530188 powernow_table[j].driver_data = fid; /* lower 8 bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 speed = powernow_table[j].frequency;
191
Dave Jonesb9e76382009-01-18 00:32:26 -0500192 if ((fid_codes[fid] % 10) == 5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#ifdef CONFIG_X86_POWERNOW_K7_ACPI
194 if (have_a0 == 1)
Dave Jonesb9e76382009-01-18 00:32:26 -0500195 invalidate_entry(j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196#endif
197 }
198
199 if (speed < minimum_speed)
200 minimum_speed = speed;
201 if (speed > maximum_speed)
202 maximum_speed = speed;
203
204 vid = *pst++;
Viresh Kumar50701582013-03-30 16:25:15 +0530205 powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200207 pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500208 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
209 fid_codes[fid] % 10, speed/1000, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 mobile_vid_table[vid]/1000,
211 mobile_vid_table[vid]%1000);
212 }
213 powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
Viresh Kumar50701582013-03-30 16:25:15 +0530214 powernow_table[number_scales].driver_data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 return 0;
217}
218
219
220static void change_FID(int fid)
221{
222 union msr_fidvidctl fidvidctl;
223
Dave Jonesb9e76382009-01-18 00:32:26 -0500224 rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 if (fidvidctl.bits.FID != fid) {
226 fidvidctl.bits.SGTC = latency;
227 fidvidctl.bits.FID = fid;
228 fidvidctl.bits.VIDC = 0;
229 fidvidctl.bits.FIDC = 1;
Dave Jonesb9e76382009-01-18 00:32:26 -0500230 wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 }
232}
233
234
235static void change_VID(int vid)
236{
237 union msr_fidvidctl fidvidctl;
238
Dave Jonesb9e76382009-01-18 00:32:26 -0500239 rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (fidvidctl.bits.VID != vid) {
241 fidvidctl.bits.SGTC = latency;
242 fidvidctl.bits.VID = vid;
243 fidvidctl.bits.FIDC = 0;
244 fidvidctl.bits.VIDC = 1;
Dave Jonesb9e76382009-01-18 00:32:26 -0500245 wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
247}
248
249
Viresh Kumar9c0ebcf2013-10-25 19:45:48 +0530250static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
252 u8 fid, vid;
253 struct cpufreq_freqs freqs;
254 union msr_fidvidstatus fidvidstatus;
255 int cfid;
256
257 /* fid are the lower 8 bits of the index we stored into
258 * the cpufreq frequency table in powernow_decode_bios,
259 * vid are the upper 8 bits.
260 */
261
Viresh Kumar50701582013-03-30 16:25:15 +0530262 fid = powernow_table[index].driver_data & 0xFF;
263 vid = (powernow_table[index].driver_data & 0xFF00) >> 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Dave Jonesb9e76382009-01-18 00:32:26 -0500265 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 cfid = fidvidstatus.bits.CFID;
267 freqs.old = fsb * fid_codes[cfid] / 10;
268
269 freqs.new = powernow_table[index].frequency;
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /* Now do the magic poking into the MSRs. */
272
273 if (have_a0 == 1) /* A0 errata 5 */
274 local_irq_disable();
275
276 if (freqs.old > freqs.new) {
277 /* Going down, so change FID first */
278 change_FID(fid);
279 change_VID(vid);
280 } else {
281 /* Going up, so change VID first */
282 change_VID(vid);
283 change_FID(fid);
284 }
285
286
287 if (have_a0 == 1)
288 local_irq_enable();
289
Viresh Kumar9c0ebcf2013-10-25 19:45:48 +0530290 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291}
292
293
294#ifdef CONFIG_X86_POWERNOW_K7_ACPI
295
296static struct acpi_processor_performance *acpi_processor_perf;
297
298static int powernow_acpi_init(void)
299{
300 int i;
301 int retval = 0;
302 union powernow_acpi_control_t pc;
303
304 if (acpi_processor_perf != NULL && powernow_table != NULL) {
305 retval = -EINVAL;
306 goto err0;
307 }
308
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530309 acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 if (!acpi_processor_perf) {
311 retval = -ENOMEM;
312 goto err0;
313 }
314
Yinghai Lueaa95842009-06-06 14:51:36 -0700315 if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map,
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800316 GFP_KERNEL)) {
317 retval = -ENOMEM;
318 goto err05;
319 }
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
322 retval = -EIO;
323 goto err1;
324 }
325
Dave Jonesb9e76382009-01-18 00:32:26 -0500326 if (acpi_processor_perf->control_register.space_id !=
327 ACPI_ADR_SPACE_FIXED_HARDWARE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 retval = -ENODEV;
329 goto err2;
330 }
331
Dave Jonesb9e76382009-01-18 00:32:26 -0500332 if (acpi_processor_perf->status_register.space_id !=
333 ACPI_ADR_SPACE_FIXED_HARDWARE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 retval = -ENODEV;
335 goto err2;
336 }
337
338 number_scales = acpi_processor_perf->state_count;
339
340 if (number_scales < 2) {
341 retval = -ENODEV;
342 goto err2;
343 }
344
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530345 powernow_table = kzalloc((sizeof(*powernow_table) *
Dave Jonesb9e76382009-01-18 00:32:26 -0500346 (number_scales + 1)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 if (!powernow_table) {
348 retval = -ENOMEM;
349 goto err2;
350 }
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 pc.val = (unsigned long) acpi_processor_perf->states[0].control;
353 for (i = 0; i < number_scales; i++) {
354 u8 fid, vid;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100355 struct acpi_processor_px *state =
356 &acpi_processor_perf->states[i];
357 unsigned int speed, speed_mhz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Daniel Drakedc2585e2007-05-02 23:19:05 +0100359 pc.val = (unsigned long) state->control;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200360 pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 i,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100362 (u32) state->core_frequency,
363 (u32) state->power,
364 (u32) state->transition_latency,
365 (u32) state->control,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 pc.bits.sgtc);
367
368 vid = pc.bits.vid;
369 fid = pc.bits.fid;
370
371 powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
Viresh Kumar50701582013-03-30 16:25:15 +0530372 powernow_table[i].driver_data = fid; /* lower 8 bits */
373 powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 speed = powernow_table[i].frequency;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100376 speed_mhz = speed / 1000;
377
378 /* processor_perflib will multiply the MHz value by 1000 to
379 * get a KHz value (e.g. 1266000). However, powernow-k7 works
380 * with true KHz values (e.g. 1266768). To ensure that all
381 * powernow frequencies are available, we must ensure that
382 * ACPI doesn't restrict them, so we round up the MHz value
383 * to ensure that perflib's computed KHz value is greater than
384 * or equal to powernow's KHz value.
385 */
386 if (speed % 1000 > 0)
387 speed_mhz++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Dave Jonesb9e76382009-01-18 00:32:26 -0500389 if ((fid_codes[fid] % 10) == 5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (have_a0 == 1)
Dave Jonesb9e76382009-01-18 00:32:26 -0500391 invalidate_entry(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200394 pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500395 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100396 fid_codes[fid] % 10, speed_mhz, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 mobile_vid_table[vid]/1000,
398 mobile_vid_table[vid]%1000);
399
Daniel Drakedc2585e2007-05-02 23:19:05 +0100400 if (state->core_frequency != speed_mhz) {
401 state->core_frequency = speed_mhz;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200402 pr_debug(" Corrected ACPI frequency to %d\n",
Daniel Drakedc2585e2007-05-02 23:19:05 +0100403 speed_mhz);
404 }
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if (latency < pc.bits.sgtc)
407 latency = pc.bits.sgtc;
408
409 if (speed < minimum_speed)
410 minimum_speed = speed;
411 if (speed > maximum_speed)
412 maximum_speed = speed;
413 }
414
415 powernow_table[i].frequency = CPUFREQ_TABLE_END;
Viresh Kumar50701582013-03-30 16:25:15 +0530416 powernow_table[i].driver_data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 /* notify BIOS that we exist */
419 acpi_processor_notify_smm(THIS_MODULE);
420
421 return 0;
422
423err2:
424 acpi_processor_unregister_performance(acpi_processor_perf, 0);
425err1:
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800426 free_cpumask_var(acpi_processor_perf->shared_cpu_map);
427err05:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 kfree(acpi_processor_perf);
429err0:
Dave Jonesb9e76382009-01-18 00:32:26 -0500430 printk(KERN_WARNING PFX "ACPI perflib can not be used on "
431 "this platform\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 acpi_processor_perf = NULL;
433 return retval;
434}
435#else
436static int powernow_acpi_init(void)
437{
438 printk(KERN_INFO PFX "no support for ACPI processor found."
439 " Please recompile your kernel with ACPI processor\n");
440 return -EINVAL;
441}
442#endif
443
Dave Jonesb9e76382009-01-18 00:32:26 -0500444static void print_pst_entry(struct pst_s *pst, unsigned int j)
445{
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200446 pr_debug("PST:%d (@%p)\n", j, pst);
447 pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
Dave Jonesb9e76382009-01-18 00:32:26 -0500448 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
449}
450
451static int powernow_decode_bios(int maxfid, int startvid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 struct psb_s *psb;
454 struct pst_s *pst;
455 unsigned int i, j;
456 unsigned char *p;
457 unsigned int etuple;
458 unsigned int ret;
459
460 etuple = cpuid_eax(0x80000001);
461
Dave Jonesb9e76382009-01-18 00:32:26 -0500462 for (i = 0xC0000; i < 0xffff0 ; i += 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 p = phys_to_virt(i);
465
Dave Jonesb9e76382009-01-18 00:32:26 -0500466 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200467 pr_debug("Found PSB header at %p\n", p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 psb = (struct psb_s *) p;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200469 pr_debug("Table version: 0x%x\n", psb->tableversion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 if (psb->tableversion != 0x12) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500471 printk(KERN_INFO PFX "Sorry, only v1.2 tables"
472 " supported right now\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 return -ENODEV;
474 }
475
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200476 pr_debug("Flags: 0x%x\n", psb->flags);
Dave Jonesb9e76382009-01-18 00:32:26 -0500477 if ((psb->flags & 1) == 0)
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200478 pr_debug("Mobile voltage regulator\n");
Dave Jonesb9e76382009-01-18 00:32:26 -0500479 else
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200480 pr_debug("Desktop voltage regulator\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 latency = psb->settlingtime;
483 if (latency < 100) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500484 printk(KERN_INFO PFX "BIOS set settling time "
485 "to %d microseconds. "
486 "Should be at least 100. "
487 "Correcting.\n", latency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 latency = 100;
489 }
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200490 pr_debug("Settling Time: %d microseconds.\n",
Dave Jonesb9e76382009-01-18 00:32:26 -0500491 psb->settlingtime);
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200492 pr_debug("Has %d PST tables. (Only dumping ones "
Dave Jonesb9e76382009-01-18 00:32:26 -0500493 "relevant to this CPU).\n",
494 psb->numpst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530496 p += sizeof(*psb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 pst = (struct pst_s *) p;
499
Dave Jonesb9e76382009-01-18 00:32:26 -0500500 for (j = 0; j < psb->numpst; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 pst = (struct pst_s *) p;
502 number_scales = pst->numpstates;
503
Dave Jonesb9e76382009-01-18 00:32:26 -0500504 if ((etuple == pst->cpuid) &&
505 check_fsb(pst->fsbspeed) &&
506 (maxfid == pst->maxfid) &&
507 (startvid == pst->startvid)) {
508 print_pst_entry(pst, j);
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530509 p = (char *)pst + sizeof(*pst);
Dave Jonesb9e76382009-01-18 00:32:26 -0500510 ret = get_ranges(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 } else {
Dave Jones8cbe0162006-05-30 17:26:08 -0400513 unsigned int k;
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530514 p = (char *)pst + sizeof(*pst);
Dave Jonesb9e76382009-01-18 00:32:26 -0500515 for (k = 0; k < number_scales; k++)
516 p += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 }
518 }
Dave Jonesb9e76382009-01-18 00:32:26 -0500519 printk(KERN_INFO PFX "No PST tables match this cpuid "
520 "(0x%x)\n", etuple);
521 printk(KERN_INFO PFX "This is indicative of a broken "
522 "BIOS.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 return -EINVAL;
525 }
526 p++;
527 }
528
529 return -ENODEV;
530}
531
532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533/*
534 * We use the fact that the bus frequency is somehow
535 * a multiple of 100000/3 khz, then we compute sgtc according
536 * to this multiple.
537 * That way, we match more how AMD thinks all of that work.
538 * We will then get the same kind of behaviour already tested under
539 * the "well-known" other OS.
540 */
Paul Gortmaker27609842013-06-19 13:54:04 -0400541static int fixup_sgtc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 unsigned int sgtc;
544 unsigned int m;
545
546 m = fsb / 3333;
547 if ((m % 10) >= 5)
548 m += 5;
549
550 m /= 10;
551
552 sgtc = 100 * m * latency;
553 sgtc = sgtc / 3;
554 if (sgtc > 0xfffff) {
555 printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);
556 sgtc = 0xfffff;
557 }
558 return sgtc;
559}
560
561static unsigned int powernow_get(unsigned int cpu)
562{
563 union msr_fidvidstatus fidvidstatus;
564 unsigned int cfid;
565
566 if (cpu)
567 return 0;
Dave Jonesb9e76382009-01-18 00:32:26 -0500568 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 cfid = fidvidstatus.bits.CFID;
570
Dave Jonesb9e76382009-01-18 00:32:26 -0500571 return fsb * fid_codes[cfid] / 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572}
573
574
Paul Gortmaker27609842013-06-19 13:54:04 -0400575static int acer_cpufreq_pst(const struct dmi_system_id *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Dave Jonesb9e76382009-01-18 00:32:26 -0500577 printk(KERN_WARNING PFX
578 "%s laptop with broken PST tables in BIOS detected.\n",
579 d->ident);
580 printk(KERN_WARNING PFX
581 "You need to downgrade to 3A21 (09/09/2002), or try a newer "
582 "BIOS than 3A71 (01/20/2003)\n");
583 printk(KERN_WARNING PFX
584 "cpufreq scaling has been disabled as a result of this.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return 0;
586}
587
588/*
589 * Some Athlon laptops have really fucked PST tables.
590 * A BIOS update is all that can save them.
591 * Mention this, and disable cpufreq.
592 */
Paul Gortmaker27609842013-06-19 13:54:04 -0400593static struct dmi_system_id powernow_dmi_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 {
595 .callback = acer_cpufreq_pst,
596 .ident = "Acer Aspire",
597 .matches = {
598 DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
599 DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
600 },
601 },
602 { }
603};
604
Paul Gortmaker27609842013-06-19 13:54:04 -0400605static int powernow_cpu_init(struct cpufreq_policy *policy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
607 union msr_fidvidstatus fidvidstatus;
608 int result;
609
610 if (policy->cpu != 0)
611 return -ENODEV;
612
Dave Jonesb9e76382009-01-18 00:32:26 -0500613 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Dave Jones436fe7b2006-06-05 14:03:50 -0400615 recalibrate_cpu_khz();
Dave Jones91350ed2005-05-31 19:03:45 -0700616
617 fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (!fsb) {
619 printk(KERN_WARNING PFX "can not determine bus frequency\n");
620 return -EINVAL;
621 }
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200622 pr_debug("FSB: %3dMHz\n", fsb/1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624 if (dmi_check_system(powernow_dmi_table) || acpi_force) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500625 printk(KERN_INFO PFX "PSB/PST known to be broken. "
626 "Trying ACPI instead\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 result = powernow_acpi_init();
628 } else {
Dave Jonesb9e76382009-01-18 00:32:26 -0500629 result = powernow_decode_bios(fidvidstatus.bits.MFID,
630 fidvidstatus.bits.SVID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (result) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500632 printk(KERN_INFO PFX "Trying ACPI perflib\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 maximum_speed = 0;
634 minimum_speed = -1;
635 latency = 0;
636 result = powernow_acpi_init();
637 if (result) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500638 printk(KERN_INFO PFX
639 "ACPI and legacy methods failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
641 } else {
642 /* SGTC use the bus clock as timer */
643 latency = fixup_sgtc();
644 printk(KERN_INFO PFX "SGTC: %d\n", latency);
645 }
646 }
647
648 if (result)
649 return result;
650
Dave Jonesb9e76382009-01-18 00:32:26 -0500651 printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 minimum_speed/1000, maximum_speed/1000);
653
Dave Jonesb9e76382009-01-18 00:32:26 -0500654 policy->cpuinfo.transition_latency =
655 cpufreq_scale(2000000UL, fsb, latency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Viresh Kumarb1474052013-09-16 18:56:27 +0530657 return cpufreq_table_validate_and_show(policy, powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
Dave Jonesb9e76382009-01-18 00:32:26 -0500660static int powernow_cpu_exit(struct cpufreq_policy *policy)
661{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662#ifdef CONFIG_X86_POWERNOW_K7_ACPI
663 if (acpi_processor_perf) {
664 acpi_processor_unregister_performance(acpi_processor_perf, 0);
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800665 free_cpumask_var(acpi_processor_perf->shared_cpu_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 kfree(acpi_processor_perf);
667 }
668#endif
669
Jesper Juhl4ae66732005-06-25 14:58:48 -0700670 kfree(powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return 0;
672}
673
Linus Torvalds221dee22007-02-26 14:55:48 -0800674static struct cpufreq_driver powernow_driver = {
Viresh Kumard63bd272013-10-03 20:28:17 +0530675 .verify = cpufreq_generic_frequency_table_verify,
Viresh Kumar9c0ebcf2013-10-25 19:45:48 +0530676 .target_index = powernow_target,
Thomas Renningere2f74f32009-11-19 12:31:01 +0100677 .get = powernow_get,
678#ifdef CONFIG_X86_POWERNOW_K7_ACPI
679 .bios_limit = acpi_processor_get_bios_limit,
680#endif
681 .init = powernow_cpu_init,
682 .exit = powernow_cpu_exit,
683 .name = "powernow-k7",
Viresh Kumard63bd272013-10-03 20:28:17 +0530684 .attr = cpufreq_generic_attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685};
686
Dave Jonesb9e76382009-01-18 00:32:26 -0500687static int __init powernow_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
Dave Jonesb9e76382009-01-18 00:32:26 -0500689 if (check_powernow() == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return -ENODEV;
691 return cpufreq_register_driver(&powernow_driver);
692}
693
694
Dave Jonesb9e76382009-01-18 00:32:26 -0500695static void __exit powernow_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
697 cpufreq_unregister_driver(&powernow_driver);
698}
699
700module_param(acpi_force, int, 0444);
701MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
702
Dave Jonesd5e80b42014-12-19 11:20:43 -0500703MODULE_AUTHOR("Dave Jones");
Dave Jonesb9e76382009-01-18 00:32:26 -0500704MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
705MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707late_initcall(powernow_init);
708module_exit(powernow_exit);
709