blob: e61e224475ad457fd71b6934b2a5256a2d96fcc0 [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
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530180 powernow_table = kzalloc((sizeof(*powernow_table) *
Dave Jonesb9e76382009-01-18 00:32:26 -0500181 (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;
Viresh Kumar50701582013-03-30 16:25:15 +0530189 powernow_table[j].driver_data = fid; /* lower 8 bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
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++;
Viresh Kumar50701582013-03-30 16:25:15 +0530206 powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
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;
Viresh Kumar50701582013-03-30 16:25:15 +0530215 powernow_table[number_scales].driver_data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
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
Viresh Kumar9c0ebcf2013-10-25 19:45:48 +0530251static int powernow_target(struct cpufreq_policy *policy, 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
Viresh Kumar50701582013-03-30 16:25:15 +0530263 fid = powernow_table[index].driver_data & 0xFF;
264 vid = (powernow_table[index].driver_data & 0xFF00) >> 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Dave Jonesb9e76382009-01-18 00:32:26 -0500266 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 cfid = fidvidstatus.bits.CFID;
268 freqs.old = fsb * fid_codes[cfid] / 10;
269
270 freqs.new = powernow_table[index].frequency;
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 /* Now do the magic poking into the MSRs. */
273
274 if (have_a0 == 1) /* A0 errata 5 */
275 local_irq_disable();
276
277 if (freqs.old > freqs.new) {
278 /* Going down, so change FID first */
279 change_FID(fid);
280 change_VID(vid);
281 } else {
282 /* Going up, so change VID first */
283 change_VID(vid);
284 change_FID(fid);
285 }
286
287
288 if (have_a0 == 1)
289 local_irq_enable();
290
Viresh Kumar9c0ebcf2013-10-25 19:45:48 +0530291 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
294
295#ifdef CONFIG_X86_POWERNOW_K7_ACPI
296
297static struct acpi_processor_performance *acpi_processor_perf;
298
299static int powernow_acpi_init(void)
300{
301 int i;
302 int retval = 0;
303 union powernow_acpi_control_t pc;
304
305 if (acpi_processor_perf != NULL && powernow_table != NULL) {
306 retval = -EINVAL;
307 goto err0;
308 }
309
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530310 acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (!acpi_processor_perf) {
312 retval = -ENOMEM;
313 goto err0;
314 }
315
Yinghai Lueaa95842009-06-06 14:51:36 -0700316 if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map,
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800317 GFP_KERNEL)) {
318 retval = -ENOMEM;
319 goto err05;
320 }
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
323 retval = -EIO;
324 goto err1;
325 }
326
Dave Jonesb9e76382009-01-18 00:32:26 -0500327 if (acpi_processor_perf->control_register.space_id !=
328 ACPI_ADR_SPACE_FIXED_HARDWARE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 retval = -ENODEV;
330 goto err2;
331 }
332
Dave Jonesb9e76382009-01-18 00:32:26 -0500333 if (acpi_processor_perf->status_register.space_id !=
334 ACPI_ADR_SPACE_FIXED_HARDWARE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 retval = -ENODEV;
336 goto err2;
337 }
338
339 number_scales = acpi_processor_perf->state_count;
340
341 if (number_scales < 2) {
342 retval = -ENODEV;
343 goto err2;
344 }
345
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530346 powernow_table = kzalloc((sizeof(*powernow_table) *
Dave Jonesb9e76382009-01-18 00:32:26 -0500347 (number_scales + 1)), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (!powernow_table) {
349 retval = -ENOMEM;
350 goto err2;
351 }
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 pc.val = (unsigned long) acpi_processor_perf->states[0].control;
354 for (i = 0; i < number_scales; i++) {
355 u8 fid, vid;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100356 struct acpi_processor_px *state =
357 &acpi_processor_perf->states[i];
358 unsigned int speed, speed_mhz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Daniel Drakedc2585e2007-05-02 23:19:05 +0100360 pc.val = (unsigned long) state->control;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200361 pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 i,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100363 (u32) state->core_frequency,
364 (u32) state->power,
365 (u32) state->transition_latency,
366 (u32) state->control,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 pc.bits.sgtc);
368
369 vid = pc.bits.vid;
370 fid = pc.bits.fid;
371
372 powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
Viresh Kumar50701582013-03-30 16:25:15 +0530373 powernow_table[i].driver_data = fid; /* lower 8 bits */
374 powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 speed = powernow_table[i].frequency;
Daniel Drakedc2585e2007-05-02 23:19:05 +0100377 speed_mhz = speed / 1000;
378
379 /* processor_perflib will multiply the MHz value by 1000 to
380 * get a KHz value (e.g. 1266000). However, powernow-k7 works
381 * with true KHz values (e.g. 1266768). To ensure that all
382 * powernow frequencies are available, we must ensure that
383 * ACPI doesn't restrict them, so we round up the MHz value
384 * to ensure that perflib's computed KHz value is greater than
385 * or equal to powernow's KHz value.
386 */
387 if (speed % 1000 > 0)
388 speed_mhz++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Dave Jonesb9e76382009-01-18 00:32:26 -0500390 if ((fid_codes[fid] % 10) == 5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (have_a0 == 1)
Dave Jonesb9e76382009-01-18 00:32:26 -0500392 invalidate_entry(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 }
394
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200395 pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
Dave Jones32ee8c32006-02-28 00:43:23 -0500396 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
Daniel Drakedc2585e2007-05-02 23:19:05 +0100397 fid_codes[fid] % 10, speed_mhz, vid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 mobile_vid_table[vid]/1000,
399 mobile_vid_table[vid]%1000);
400
Daniel Drakedc2585e2007-05-02 23:19:05 +0100401 if (state->core_frequency != speed_mhz) {
402 state->core_frequency = speed_mhz;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200403 pr_debug(" Corrected ACPI frequency to %d\n",
Daniel Drakedc2585e2007-05-02 23:19:05 +0100404 speed_mhz);
405 }
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if (latency < pc.bits.sgtc)
408 latency = pc.bits.sgtc;
409
410 if (speed < minimum_speed)
411 minimum_speed = speed;
412 if (speed > maximum_speed)
413 maximum_speed = speed;
414 }
415
416 powernow_table[i].frequency = CPUFREQ_TABLE_END;
Viresh Kumar50701582013-03-30 16:25:15 +0530417 powernow_table[i].driver_data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* notify BIOS that we exist */
420 acpi_processor_notify_smm(THIS_MODULE);
421
422 return 0;
423
424err2:
425 acpi_processor_unregister_performance(acpi_processor_perf, 0);
426err1:
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800427 free_cpumask_var(acpi_processor_perf->shared_cpu_map);
428err05:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 kfree(acpi_processor_perf);
430err0:
Dave Jonesb9e76382009-01-18 00:32:26 -0500431 printk(KERN_WARNING PFX "ACPI perflib can not be used on "
432 "this platform\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 acpi_processor_perf = NULL;
434 return retval;
435}
436#else
437static int powernow_acpi_init(void)
438{
439 printk(KERN_INFO PFX "no support for ACPI processor found."
440 " Please recompile your kernel with ACPI processor\n");
441 return -EINVAL;
442}
443#endif
444
Dave Jonesb9e76382009-01-18 00:32:26 -0500445static void print_pst_entry(struct pst_s *pst, unsigned int j)
446{
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200447 pr_debug("PST:%d (@%p)\n", j, pst);
448 pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
Dave Jonesb9e76382009-01-18 00:32:26 -0500449 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
450}
451
452static int powernow_decode_bios(int maxfid, int startvid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
454 struct psb_s *psb;
455 struct pst_s *pst;
456 unsigned int i, j;
457 unsigned char *p;
458 unsigned int etuple;
459 unsigned int ret;
460
461 etuple = cpuid_eax(0x80000001);
462
Dave Jonesb9e76382009-01-18 00:32:26 -0500463 for (i = 0xC0000; i < 0xffff0 ; i += 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 p = phys_to_virt(i);
466
Dave Jonesb9e76382009-01-18 00:32:26 -0500467 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200468 pr_debug("Found PSB header at %p\n", p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 psb = (struct psb_s *) p;
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200470 pr_debug("Table version: 0x%x\n", psb->tableversion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (psb->tableversion != 0x12) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500472 printk(KERN_INFO PFX "Sorry, only v1.2 tables"
473 " supported right now\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 return -ENODEV;
475 }
476
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200477 pr_debug("Flags: 0x%x\n", psb->flags);
Dave Jonesb9e76382009-01-18 00:32:26 -0500478 if ((psb->flags & 1) == 0)
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200479 pr_debug("Mobile voltage regulator\n");
Dave Jonesb9e76382009-01-18 00:32:26 -0500480 else
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200481 pr_debug("Desktop voltage regulator\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 latency = psb->settlingtime;
484 if (latency < 100) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500485 printk(KERN_INFO PFX "BIOS set settling time "
486 "to %d microseconds. "
487 "Should be at least 100. "
488 "Correcting.\n", latency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 latency = 100;
490 }
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200491 pr_debug("Settling Time: %d microseconds.\n",
Dave Jonesb9e76382009-01-18 00:32:26 -0500492 psb->settlingtime);
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200493 pr_debug("Has %d PST tables. (Only dumping ones "
Dave Jonesb9e76382009-01-18 00:32:26 -0500494 "relevant to this CPU).\n",
495 psb->numpst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530497 p += sizeof(*psb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 pst = (struct pst_s *) p;
500
Dave Jonesb9e76382009-01-18 00:32:26 -0500501 for (j = 0; j < psb->numpst; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 pst = (struct pst_s *) p;
503 number_scales = pst->numpstates;
504
Dave Jonesb9e76382009-01-18 00:32:26 -0500505 if ((etuple == pst->cpuid) &&
506 check_fsb(pst->fsbspeed) &&
507 (maxfid == pst->maxfid) &&
508 (startvid == pst->startvid)) {
509 print_pst_entry(pst, j);
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530510 p = (char *)pst + sizeof(*pst);
Dave Jonesb9e76382009-01-18 00:32:26 -0500511 ret = get_ranges(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 } else {
Dave Jones8cbe0162006-05-30 17:26:08 -0400514 unsigned int k;
Viresh Kumard5b73cd2013-08-06 22:53:06 +0530515 p = (char *)pst + sizeof(*pst);
Dave Jonesb9e76382009-01-18 00:32:26 -0500516 for (k = 0; k < number_scales; k++)
517 p += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 }
519 }
Dave Jonesb9e76382009-01-18 00:32:26 -0500520 printk(KERN_INFO PFX "No PST tables match this cpuid "
521 "(0x%x)\n", etuple);
522 printk(KERN_INFO PFX "This is indicative of a broken "
523 "BIOS.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 return -EINVAL;
526 }
527 p++;
528 }
529
530 return -ENODEV;
531}
532
533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534/*
535 * We use the fact that the bus frequency is somehow
536 * a multiple of 100000/3 khz, then we compute sgtc according
537 * to this multiple.
538 * That way, we match more how AMD thinks all of that work.
539 * We will then get the same kind of behaviour already tested under
540 * the "well-known" other OS.
541 */
Paul Gortmaker27609842013-06-19 13:54:04 -0400542static int fixup_sgtc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
544 unsigned int sgtc;
545 unsigned int m;
546
547 m = fsb / 3333;
548 if ((m % 10) >= 5)
549 m += 5;
550
551 m /= 10;
552
553 sgtc = 100 * m * latency;
554 sgtc = sgtc / 3;
555 if (sgtc > 0xfffff) {
556 printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);
557 sgtc = 0xfffff;
558 }
559 return sgtc;
560}
561
562static unsigned int powernow_get(unsigned int cpu)
563{
564 union msr_fidvidstatus fidvidstatus;
565 unsigned int cfid;
566
567 if (cpu)
568 return 0;
Dave Jonesb9e76382009-01-18 00:32:26 -0500569 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 cfid = fidvidstatus.bits.CFID;
571
Dave Jonesb9e76382009-01-18 00:32:26 -0500572 return fsb * fid_codes[cfid] / 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
575
Paul Gortmaker27609842013-06-19 13:54:04 -0400576static int acer_cpufreq_pst(const struct dmi_system_id *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
Dave Jonesb9e76382009-01-18 00:32:26 -0500578 printk(KERN_WARNING PFX
579 "%s laptop with broken PST tables in BIOS detected.\n",
580 d->ident);
581 printk(KERN_WARNING PFX
582 "You need to downgrade to 3A21 (09/09/2002), or try a newer "
583 "BIOS than 3A71 (01/20/2003)\n");
584 printk(KERN_WARNING PFX
585 "cpufreq scaling has been disabled as a result of this.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 return 0;
587}
588
589/*
590 * Some Athlon laptops have really fucked PST tables.
591 * A BIOS update is all that can save them.
592 * Mention this, and disable cpufreq.
593 */
Paul Gortmaker27609842013-06-19 13:54:04 -0400594static struct dmi_system_id powernow_dmi_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 {
596 .callback = acer_cpufreq_pst,
597 .ident = "Acer Aspire",
598 .matches = {
599 DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
600 DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
601 },
602 },
603 { }
604};
605
Paul Gortmaker27609842013-06-19 13:54:04 -0400606static int powernow_cpu_init(struct cpufreq_policy *policy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 union msr_fidvidstatus fidvidstatus;
609 int result;
610
611 if (policy->cpu != 0)
612 return -ENODEV;
613
Dave Jonesb9e76382009-01-18 00:32:26 -0500614 rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Dave Jones436fe7b2006-06-05 14:03:50 -0400616 recalibrate_cpu_khz();
Dave Jones91350ed2005-05-31 19:03:45 -0700617
618 fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (!fsb) {
620 printk(KERN_WARNING PFX "can not determine bus frequency\n");
621 return -EINVAL;
622 }
Dominik Brodowski2d06d8c2011-03-27 15:04:46 +0200623 pr_debug("FSB: %3dMHz\n", fsb/1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 if (dmi_check_system(powernow_dmi_table) || acpi_force) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500626 printk(KERN_INFO PFX "PSB/PST known to be broken. "
627 "Trying ACPI instead\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 result = powernow_acpi_init();
629 } else {
Dave Jonesb9e76382009-01-18 00:32:26 -0500630 result = powernow_decode_bios(fidvidstatus.bits.MFID,
631 fidvidstatus.bits.SVID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (result) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500633 printk(KERN_INFO PFX "Trying ACPI perflib\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 maximum_speed = 0;
635 minimum_speed = -1;
636 latency = 0;
637 result = powernow_acpi_init();
638 if (result) {
Dave Jonesb9e76382009-01-18 00:32:26 -0500639 printk(KERN_INFO PFX
640 "ACPI and legacy methods failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 }
642 } else {
643 /* SGTC use the bus clock as timer */
644 latency = fixup_sgtc();
645 printk(KERN_INFO PFX "SGTC: %d\n", latency);
646 }
647 }
648
649 if (result)
650 return result;
651
Dave Jonesb9e76382009-01-18 00:32:26 -0500652 printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 minimum_speed/1000, maximum_speed/1000);
654
Dave Jonesb9e76382009-01-18 00:32:26 -0500655 policy->cpuinfo.transition_latency =
656 cpufreq_scale(2000000UL, fsb, latency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Viresh Kumarb1474052013-09-16 18:56:27 +0530658 return cpufreq_table_validate_and_show(policy, powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659}
660
Dave Jonesb9e76382009-01-18 00:32:26 -0500661static int powernow_cpu_exit(struct cpufreq_policy *policy)
662{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663#ifdef CONFIG_X86_POWERNOW_K7_ACPI
664 if (acpi_processor_perf) {
665 acpi_processor_unregister_performance(acpi_processor_perf, 0);
Rusty Russell2fdf66b2008-12-31 18:08:47 -0800666 free_cpumask_var(acpi_processor_perf->shared_cpu_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 kfree(acpi_processor_perf);
668 }
669#endif
670
Jesper Juhl4ae66732005-06-25 14:58:48 -0700671 kfree(powernow_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 return 0;
673}
674
Linus Torvalds221dee22007-02-26 14:55:48 -0800675static struct cpufreq_driver powernow_driver = {
Viresh Kumard63bd272013-10-03 20:28:17 +0530676 .verify = cpufreq_generic_frequency_table_verify,
Viresh Kumar9c0ebcf2013-10-25 19:45:48 +0530677 .target_index = powernow_target,
Thomas Renningere2f74f32009-11-19 12:31:01 +0100678 .get = powernow_get,
679#ifdef CONFIG_X86_POWERNOW_K7_ACPI
680 .bios_limit = acpi_processor_get_bios_limit,
681#endif
682 .init = powernow_cpu_init,
683 .exit = powernow_cpu_exit,
684 .name = "powernow-k7",
Viresh Kumard63bd272013-10-03 20:28:17 +0530685 .attr = cpufreq_generic_attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686};
687
Dave Jonesb9e76382009-01-18 00:32:26 -0500688static int __init powernow_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Dave Jonesb9e76382009-01-18 00:32:26 -0500690 if (check_powernow() == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return -ENODEV;
692 return cpufreq_register_driver(&powernow_driver);
693}
694
695
Dave Jonesb9e76382009-01-18 00:32:26 -0500696static void __exit powernow_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697{
698 cpufreq_unregister_driver(&powernow_driver);
699}
700
701module_param(acpi_force, int, 0444);
702MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
703
Dave Jonesb9e76382009-01-18 00:32:26 -0500704MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
705MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
706MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708late_initcall(powernow_init);
709module_exit(powernow_exit);
710