Deleted Added
full compact
1/*-
2 * Copyright (c) 2004-2005 Bruno Ducrot
3 * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26/*
27 * Many thanks to Nate Lawson for his helpful comments on this driver and
28 * to Jung-uk Kim for testing.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/i386/cpufreq/powernow.c 181691 2008-08-13 16:09:40Z jhb $");
32__FBSDID("$FreeBSD: head/sys/i386/cpufreq/powernow.c 182401 2008-08-28 19:55:18Z jhb $");
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/cpu.h>
37#include <sys/kernel.h>
38#include <sys/malloc.h>
39#include <sys/module.h>
40#include <sys/pcpu.h>
41#include <sys/systm.h>
42
43#include <machine/pc/bios.h>
44#include <machine/md_var.h>
45#include <machine/specialreg.h>
46#include <machine/cputypes.h>
47#include <machine/vmparam.h>
48#include <sys/rman.h>
49
50#include <vm/vm.h>
51#include <vm/pmap.h>
52
53#include "cpufreq_if.h"
54
55#define PN7_TYPE 0
56#define PN8_TYPE 1
57
58/* Flags for some hardware bugs. */
59#define A0_ERRATA 0x1 /* Bugs for the rev. A0 of Athlon (K7):
60 * Interrupts must be disabled and no half
61 * multipliers are allowed */
62#define PENDING_STUCK 0x2 /* With some buggy chipset and some newer AMD64
63 * processor (Rev. G?):
64 * the pending bit from the msr FIDVID_STATUS
65 * is set forever. No workaround :( */
66
67/* Legacy configuration via BIOS table PSB. */
68#define PSB_START 0
69#define PSB_STEP 0x10
70#define PSB_SIG "AMDK7PNOW!"
71#define PSB_LEN 10
72#define PSB_OFF 0
73
74struct psb_header {
75 char signature[10];
76 uint8_t version;
77 uint8_t flags;
78 uint16_t settlingtime;
79 uint8_t res1;
80 uint8_t numpst;
81} __packed;
82
83struct pst_header {
84 uint32_t cpuid;
85 uint8_t fsb;
86 uint8_t maxfid;
87 uint8_t startvid;
88 uint8_t numpstates;
89} __packed;
90
91/*
92 * MSRs and bits used by Powernow technology
93 */
94#define MSR_AMDK7_FIDVID_CTL 0xc0010041
95#define MSR_AMDK7_FIDVID_STATUS 0xc0010042
96
97/* Bitfields used by K7 */
98
99#define PN7_CTR_FID(x) ((x) & 0x1f)
100#define PN7_CTR_VID(x) (((x) & 0x1f) << 8)
101#define PN7_CTR_FIDC 0x00010000
102#define PN7_CTR_VIDC 0x00020000
103#define PN7_CTR_FIDCHRATIO 0x00100000
104#define PN7_CTR_SGTC(x) (((uint64_t)(x) & 0x000fffff) << 32)
105
106#define PN7_STA_CFID(x) ((x) & 0x1f)
107#define PN7_STA_SFID(x) (((x) >> 8) & 0x1f)
108#define PN7_STA_MFID(x) (((x) >> 16) & 0x1f)
109#define PN7_STA_CVID(x) (((x) >> 32) & 0x1f)
110#define PN7_STA_SVID(x) (((x) >> 40) & 0x1f)
111#define PN7_STA_MVID(x) (((x) >> 48) & 0x1f)
112
113/* ACPI ctr_val status register to powernow k7 configuration */
114#define ACPI_PN7_CTRL_TO_FID(x) ((x) & 0x1f)
115#define ACPI_PN7_CTRL_TO_VID(x) (((x) >> 5) & 0x1f)
116#define ACPI_PN7_CTRL_TO_SGTC(x) (((x) >> 10) & 0xffff)
117
118/* Bitfields used by K8 */
119
120#define PN8_CTR_FID(x) ((x) & 0x3f)
121#define PN8_CTR_VID(x) (((x) & 0x1f) << 8)
122#define PN8_CTR_PENDING(x) (((x) & 1) << 32)
123
124#define PN8_STA_CFID(x) ((x) & 0x3f)
125#define PN8_STA_SFID(x) (((x) >> 8) & 0x3f)
126#define PN8_STA_MFID(x) (((x) >> 16) & 0x3f)
127#define PN8_STA_PENDING(x) (((x) >> 31) & 0x01)
128#define PN8_STA_CVID(x) (((x) >> 32) & 0x1f)
129#define PN8_STA_SVID(x) (((x) >> 40) & 0x1f)
130#define PN8_STA_MVID(x) (((x) >> 48) & 0x1f)
131
132/* Reserved1 to powernow k8 configuration */
133#define PN8_PSB_TO_RVO(x) ((x) & 0x03)
134#define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03)
135#define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03)
136#define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03)
137
138/* ACPI ctr_val status register to powernow k8 configuration */
139#define ACPI_PN8_CTRL_TO_FID(x) ((x) & 0x3f)
140#define ACPI_PN8_CTRL_TO_VID(x) (((x) >> 6) & 0x1f)
141#define ACPI_PN8_CTRL_TO_VST(x) (((x) >> 11) & 0x1f)
142#define ACPI_PN8_CTRL_TO_MVS(x) (((x) >> 18) & 0x03)
143#define ACPI_PN8_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f)
144#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03)
145#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03)
146
147
148#define WRITE_FIDVID(fid, vid, ctrl) \
149 wrmsr(MSR_AMDK7_FIDVID_CTL, \
150 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
151
152#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt)))
153#define COUNT_OFF_VST(vst) DELAY(20 * (vst))
154
155#define FID_TO_VCO_FID(fid) \
156 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
157
158/*
159 * Divide each value by 10 to get the processor multiplier.
160 * Some of those tables are the same as the Linux powernow-k7
161 * implementation by Dave Jones.
162 */
163static int pn7_fid_to_mult[32] = {
164 110, 115, 120, 125, 50, 55, 60, 65,
165 70, 75, 80, 85, 90, 95, 100, 105,
166 30, 190, 40, 200, 130, 135, 140, 210,
167 150, 225, 160, 165, 170, 180, 0, 0,
168};
169
170
171static int pn8_fid_to_mult[64] = {
172 40, 45, 50, 55, 60, 65, 70, 75,
173 80, 85, 90, 95, 100, 105, 110, 115,
174 120, 125, 130, 135, 140, 145, 150, 155,
175 160, 165, 170, 175, 180, 185, 190, 195,
176 200, 205, 210, 215, 220, 225, 230, 235,
177 240, 245, 250, 255, 260, 265, 270, 275,
178 280, 285, 290, 295, 300, 305, 310, 315,
179 320, 325, 330, 335, 340, 345, 350, 355,
180};
181
182/*
183 * Units are in mV.
184 */
185/* Mobile VRM (K7) */
186static int pn7_mobile_vid_to_volts[] = {
187 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
188 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
189 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
190 1075, 1050, 1025, 1000, 975, 950, 925, 0,
191};
192/* Desktop VRM (K7) */
193static int pn7_desktop_vid_to_volts[] = {
194 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
195 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
196 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
197 1075, 1050, 1025, 1000, 975, 950, 925, 0,
198};
199/* Desktop and Mobile VRM (K8) */
200static int pn8_vid_to_volts[] = {
201 1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375,
202 1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175,
203 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975,
204 950, 925, 900, 875, 850, 825, 800, 0,
205};
206
207#define POWERNOW_MAX_STATES 16
208
209struct powernow_state {
210 int freq;
211 int power;
212 int fid;
213 int vid;
214};
215
216struct pn_softc {
217 device_t dev;
218 int pn_type;
219 struct powernow_state powernow_states[POWERNOW_MAX_STATES];
220 u_int fsb;
221 u_int sgtc;
222 u_int vst;
223 u_int mvs;
224 u_int pll;
225 u_int rvo;
226 u_int irt;
227 int low;
228 int powernow_max_states;
229 u_int powernow_state;
230 u_int errata;
231 int *vid_to_volts;
232};
233
234/*
235 * Offsets in struct cf_setting array for private values given by
236 * acpi_perf driver.
237 */
238#define PX_SPEC_CONTROL 0
239#define PX_SPEC_STATUS 1
240
241static void pn_identify(driver_t *driver, device_t parent);
242static int pn_probe(device_t dev);
243static int pn_attach(device_t dev);
244static int pn_detach(device_t dev);
245static int pn_set(device_t dev, const struct cf_setting *cf);
246static int pn_get(device_t dev, struct cf_setting *cf);
247static int pn_settings(device_t dev, struct cf_setting *sets,
248 int *count);
249static int pn_type(device_t dev, int *type);
250
251static device_method_t pn_methods[] = {
252 /* Device interface */
253 DEVMETHOD(device_identify, pn_identify),
254 DEVMETHOD(device_probe, pn_probe),
255 DEVMETHOD(device_attach, pn_attach),
256 DEVMETHOD(device_detach, pn_detach),
257
258 /* cpufreq interface */
259 DEVMETHOD(cpufreq_drv_set, pn_set),
260 DEVMETHOD(cpufreq_drv_get, pn_get),
261 DEVMETHOD(cpufreq_drv_settings, pn_settings),
262 DEVMETHOD(cpufreq_drv_type, pn_type),
263
264 {0, 0}
265};
266
267static devclass_t pn_devclass;
268static driver_t pn_driver = {
269 "powernow",
270 pn_methods,
271 sizeof(struct pn_softc),
272};
273
274DRIVER_MODULE(powernow, cpu, pn_driver, pn_devclass, 0, 0);
275
276static int
277pn7_setfidvid(struct pn_softc *sc, int fid, int vid)
278{
279 int cfid, cvid;
280 uint64_t status, ctl;
281
282 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
283 cfid = PN7_STA_CFID(status);
284 cvid = PN7_STA_CVID(status);
285
286 /* We're already at the requested level. */
287 if (fid == cfid && vid == cvid)
288 return (0);
289
290 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
291
292 ctl |= PN7_CTR_FID(fid);
293 ctl |= PN7_CTR_VID(vid);
294 ctl |= PN7_CTR_SGTC(sc->sgtc);
295
296 if (sc->errata & A0_ERRATA)
297 disable_intr();
298
299 if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) {
300 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
301 if (vid != cvid)
302 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
303 } else {
304 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
305 if (fid != cfid)
306 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
307 }
308
309 if (sc->errata & A0_ERRATA)
310 enable_intr();
311
312 return (0);
313}
314
315static int
316pn8_read_pending_wait(uint64_t *status)
317{
318 int i = 10000;
319
320 do
321 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
322 while (PN8_STA_PENDING(*status) && --i);
323
324 return (i == 0 ? ENXIO : 0);
325}
326
327static int
328pn8_write_fidvid(u_int fid, u_int vid, uint64_t ctrl, uint64_t *status)
329{
330 int i = 100;
331
332 do
333 WRITE_FIDVID(fid, vid, ctrl);
334 while (pn8_read_pending_wait(status) && --i);
335
336 return (i == 0 ? ENXIO : 0);
337}
338
339static int
340pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
341{
342 uint64_t status;
343 int cfid, cvid;
344 int rvo;
345 int rv;
346 u_int val;
347
348 rv = pn8_read_pending_wait(&status);
349 if (rv)
350 return (rv);
351
352 cfid = PN8_STA_CFID(status);
353 cvid = PN8_STA_CVID(status);
354
355 if (fid == cfid && vid == cvid)
356 return (0);
357
358 /*
359 * Phase 1: Raise core voltage to requested VID if frequency is
360 * going up.
361 */
362 while (cvid > vid) {
363 val = cvid - (1 << sc->mvs);
364 rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status);
365 if (rv) {
366 sc->errata |= PENDING_STUCK;
367 return (rv);
368 }
369 cvid = PN8_STA_CVID(status);
370 COUNT_OFF_VST(sc->vst);
371 }
372
373 /* ... then raise to voltage + RVO (if required) */
374 for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) {
375 /* XXX It's not clear from spec if we have to do that
376 * in 0.25 step or in MVS. Therefore do it as it's done
377 * under Linux */
378 rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status);
379 if (rv) {
380 sc->errata |= PENDING_STUCK;
381 return (rv);
382 }
383 cvid = PN8_STA_CVID(status);
384 COUNT_OFF_VST(sc->vst);
385 }
386
387 /* Phase 2: change to requested core frequency */
388 if (cfid != fid) {
389 u_int vco_fid, vco_cfid, fid_delta;
390
391 vco_fid = FID_TO_VCO_FID(fid);
392 vco_cfid = FID_TO_VCO_FID(cfid);
393
394 while (abs(vco_fid - vco_cfid) > 2) {
395 fid_delta = (vco_cfid & 1) ? 1 : 2;
396 if (fid > cfid) {
397 if (cfid > 7)
398 val = cfid + fid_delta;
399 else
400 val = FID_TO_VCO_FID(cfid) + fid_delta;
401 } else
402 val = cfid - fid_delta;
403 rv = pn8_write_fidvid(val, cvid,
404 sc->pll * (uint64_t) sc->fsb,
405 &status);
406 if (rv) {
407 sc->errata |= PENDING_STUCK;
408 return (rv);
409 }
410 cfid = PN8_STA_CFID(status);
411 COUNT_OFF_IRT(sc->irt);
412
413 vco_cfid = FID_TO_VCO_FID(cfid);
414 }
415
416 rv = pn8_write_fidvid(fid, cvid,
417 sc->pll * (uint64_t) sc->fsb,
418 &status);
419 if (rv) {
420 sc->errata |= PENDING_STUCK;
421 return (rv);
422 }
423 cfid = PN8_STA_CFID(status);
424 COUNT_OFF_IRT(sc->irt);
425 }
426
427 /* Phase 3: change to requested voltage */
428 if (cvid != vid) {
429 rv = pn8_write_fidvid(cfid, vid, 1ULL, &status);
430 cvid = PN8_STA_CVID(status);
431 COUNT_OFF_VST(sc->vst);
432 }
433
434 /* Check if transition failed. */
435 if (cfid != fid || cvid != vid)
436 rv = ENXIO;
437
438 return (rv);
439}
440
441static int
442pn_set(device_t dev, const struct cf_setting *cf)
443{
444 struct pn_softc *sc;
445 int fid, vid;
446 int i;
447 int rv;
448
449 if (cf == NULL)
450 return (EINVAL);
451 sc = device_get_softc(dev);
452
453 if (sc->errata & PENDING_STUCK)
454 return (ENXIO);
455
456 for (i = 0; i < sc->powernow_max_states; ++i)
457 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq))
458 break;
459
460 fid = sc->powernow_states[i].fid;
461 vid = sc->powernow_states[i].vid;
462
463 rv = ENODEV;
464
465 switch (sc->pn_type) {
466 case PN7_TYPE:
467 rv = pn7_setfidvid(sc, fid, vid);
468 break;
469 case PN8_TYPE:
470 rv = pn8_setfidvid(sc, fid, vid);
471 break;
472 }
473
474 return (rv);
475}
476
477static int
478pn_get(device_t dev, struct cf_setting *cf)
479{
480 struct pn_softc *sc;
481 u_int cfid = 0, cvid = 0;
482 int i;
483 uint64_t status;
484
485 if (cf == NULL)
486 return (EINVAL);
487 sc = device_get_softc(dev);
488 if (sc->errata & PENDING_STUCK)
489 return (ENXIO);
490
491 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
492
493 switch (sc->pn_type) {
494 case PN7_TYPE:
495 cfid = PN7_STA_CFID(status);
496 cvid = PN7_STA_CVID(status);
497 break;
498 case PN8_TYPE:
499 cfid = PN8_STA_CFID(status);
500 cvid = PN8_STA_CVID(status);
501 break;
502 }
503 for (i = 0; i < sc->powernow_max_states; ++i)
504 if (cfid == sc->powernow_states[i].fid &&
505 cvid == sc->powernow_states[i].vid)
506 break;
507
508 if (i < sc->powernow_max_states) {
509 cf->freq = sc->powernow_states[i].freq / 1000;
510 cf->power = sc->powernow_states[i].power;
511 cf->lat = 200;
512 cf->volts = sc->vid_to_volts[cvid];
513 cf->dev = dev;
514 } else {
515 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
516 cf->dev = NULL;
517 }
518
519 return (0);
520}
521
522static int
523pn_settings(device_t dev, struct cf_setting *sets, int *count)
524{
525 struct pn_softc *sc;
526 int i;
527
528 if (sets == NULL|| count == NULL)
529 return (EINVAL);
530 sc = device_get_softc(dev);
531 if (*count < sc->powernow_max_states)
532 return (E2BIG);
533 for (i = 0; i < sc->powernow_max_states; ++i) {
534 sets[i].freq = sc->powernow_states[i].freq / 1000;
535 sets[i].power = sc->powernow_states[i].power;
536 sets[i].lat = 200;
537 sets[i].volts = sc->vid_to_volts[sc->powernow_states[i].vid];
538 sets[i].dev = dev;
539 }
540 *count = sc->powernow_max_states;
541
542 return (0);
543}
544
545static int
546pn_type(device_t dev, int *type)
547{
548 if (type == NULL)
549 return (EINVAL);
550
551 *type = CPUFREQ_TYPE_ABSOLUTE;
552
553 return (0);
554}
555
556/*
557 * Given a set of pair of fid/vid, and number of performance states,
558 * compute powernow_states via an insertion sort.
559 */
560static int
561decode_pst(struct pn_softc *sc, uint8_t *p, int npstates)
562{
563 int i, j, n;
564 struct powernow_state state;
565
566 for (i = 0; i < POWERNOW_MAX_STATES; ++i)
567 sc->powernow_states[i].freq = CPUFREQ_VAL_UNKNOWN;
568
569 for (n = 0, i = 0; i < npstates; ++i) {
570 state.fid = *p++;
571 state.vid = *p++;
572 state.power = CPUFREQ_VAL_UNKNOWN;
573
574 switch (sc->pn_type) {
575 case PN7_TYPE:
576 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
577 if ((sc->errata & A0_ERRATA) &&
578 (pn7_fid_to_mult[state.fid] % 10) == 5)
579 continue;
580 break;
581 case PN8_TYPE:
582 state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
583 break;
584 }
585
586 j = n;
587 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
588 memcpy(&sc->powernow_states[j],
589 &sc->powernow_states[j - 1],
590 sizeof(struct powernow_state));
591 --j;
592 }
593 memcpy(&sc->powernow_states[j], &state,
594 sizeof(struct powernow_state));
595 ++n;
596 }
597
598 /*
599 * Fix powernow_max_states, if errata a0 give us less states
600 * than expected.
601 */
602 sc->powernow_max_states = n;
603
604 if (bootverbose)
605 for (i = 0; i < sc->powernow_max_states; ++i) {
606 int fid = sc->powernow_states[i].fid;
607 int vid = sc->powernow_states[i].vid;
608
609 printf("powernow: %2i %8dkHz FID %02x VID %02x\n",
610 i,
611 sc->powernow_states[i].freq,
612 fid,
613 vid);
614 }
615
616 return (0);
617}
618
619static int
620cpuid_is_k7(u_int cpuid)
621{
622
623 switch (cpuid) {
624 case 0x760:
625 case 0x761:
626 case 0x762:
627 case 0x770:
628 case 0x771:
629 case 0x780:
630 case 0x781:
631 case 0x7a0:
632 return (TRUE);
633 }
634 return (FALSE);
635}
636
637static int
638pn_decode_pst(device_t dev)
639{
640 int maxpst;
641 struct pn_softc *sc;
642 u_int cpuid, maxfid, startvid;
643 u_long sig;
644 struct psb_header *psb;
645 uint8_t *p;
646 u_int regs[4];
647 uint64_t status;
648
649 sc = device_get_softc(dev);
650
651 do_cpuid(0x80000001, regs);
652 cpuid = regs[0];
653
654 if ((cpuid & 0xfff) == 0x760)
655 sc->errata |= A0_ERRATA;
656
657 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
658
659 switch (sc->pn_type) {
660 case PN7_TYPE:
661 maxfid = PN7_STA_MFID(status);
662 startvid = PN7_STA_SVID(status);
663 break;
664 case PN8_TYPE:
665 maxfid = PN8_STA_MFID(status);
666 /*
667 * we should actually use a variable named 'maxvid' if K8,
668 * but why introducing a new variable for that?
669 */
670 startvid = PN8_STA_MVID(status);
671 break;
672 default:
673 return (ENODEV);
674 }
675
676 if (bootverbose) {
677 device_printf(dev, "STATUS: 0x%jx\n", status);
678 device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid);
679 device_printf(dev, "STATUS: %s: 0x%02x\n",
680 sc->pn_type == PN7_TYPE ? "startvid" : "maxvid",
681 startvid);
682 }
683
684 sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF);
685 if (sig) {
686 struct pst_header *pst;
687
688 psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig);
689
690 switch (psb->version) {
691 default:
692 return (ENODEV);
693 case 0x14:
694 /*
695 * We can't be picky about numpst since at least
696 * some systems have a value of 1 and some have 2.
697 * We trust that cpuid_is_k7() will be better at
698 * catching that we're on a K8 anyway.
699 */
700 if (sc->pn_type != PN8_TYPE)
701 return (EINVAL);
702 sc->vst = psb->settlingtime;
703 sc->rvo = PN8_PSB_TO_RVO(psb->res1),
704 sc->irt = PN8_PSB_TO_IRT(psb->res1),
705 sc->mvs = PN8_PSB_TO_MVS(psb->res1),
706 sc->low = PN8_PSB_TO_BATT(psb->res1);
707 if (bootverbose) {
708 device_printf(dev, "PSB: VST: %d\n",
709 psb->settlingtime);
710 device_printf(dev, "PSB: RVO %x IRT %d "
711 "MVS %d BATT %d\n",
712 sc->rvo,
713 sc->irt,
714 sc->mvs,
715 sc->low);
716 }
717 break;
718 case 0x12:
719 if (sc->pn_type != PN7_TYPE)
720 return (EINVAL);
721 sc->sgtc = psb->settlingtime * sc->fsb;
722 if (sc->sgtc < 100 * sc->fsb)
723 sc->sgtc = 100 * sc->fsb;
724 break;
725 }
726
727 p = ((uint8_t *) psb) + sizeof(struct psb_header);
728 pst = (struct pst_header*) p;
729
730 maxpst = 200;
731
732 do {
733 struct pst_header *pst = (struct pst_header*) p;
734
735 if (cpuid == pst->cpuid &&
736 maxfid == pst->maxfid &&
737 startvid == pst->startvid) {
738 sc->powernow_max_states = pst->numpstates;
739 switch (sc->pn_type) {
740 case PN7_TYPE:
741 if (abs(sc->fsb - pst->fsb) > 5)
742 continue;
743 break;
744 case PN8_TYPE:
745 break;
746 }
747 return (decode_pst(sc,
748 p + sizeof(struct pst_header),
749 sc->powernow_max_states));
750 }
751
752 p += sizeof(struct pst_header) + (2 * pst->numpstates);
753 } while (cpuid_is_k7(pst->cpuid) && maxpst--);
754
755 device_printf(dev, "no match for extended cpuid %.3x\n", cpuid);
756 }
757
758 return (ENODEV);
759}
760
761/*
762 * TODO: this should be done in sys/ARCH/ARCH/identcpu.c
763 */
764static int
765cpu_is_powernow_capable(void)
766{
767 u_int regs[4];
768
769 if (strcmp(cpu_vendor, "AuthenticAMD") != 0 ||
770 cpu_exthigh < 0x80000007)
771 return (FALSE);
772
773 do_cpuid(0x80000007, regs);
774 return (regs[3] & 0x6);
775}
776
777static int
778pn_decode_acpi(device_t dev, device_t perf_dev)
779{
780 int i, j, n;
781 uint64_t status;
782 uint32_t ctrl;
783 u_int cpuid;
784 u_int regs[4];
785 struct pn_softc *sc;
786 struct powernow_state state;
787 struct cf_setting sets[POWERNOW_MAX_STATES];
788 int count = POWERNOW_MAX_STATES;
789 int type;
790 int rv;
791
792 if (perf_dev == NULL)
793 return (ENXIO);
794
795 rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count);
796 if (rv)
797 return (ENXIO);
798 rv = CPUFREQ_DRV_TYPE(perf_dev, &type);
799 if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
800 return (ENXIO);
801
802 sc = device_get_softc(dev);
803
804 do_cpuid(0x80000001, regs);
805 cpuid = regs[0];
806 if ((cpuid & 0xfff) == 0x760)
807 sc->errata |= A0_ERRATA;
808
809 ctrl = 0;
810 sc->sgtc = 0;
811 for (n = 0, i = 0; i < count; ++i) {
812 ctrl = sets[i].spec[PX_SPEC_CONTROL];
813 switch (sc->pn_type) {
814 case PN7_TYPE:
815 state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
816 state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
817 if ((sc->errata & A0_ERRATA) &&
818 (pn7_fid_to_mult[state.fid] % 10) == 5)
819 continue;
820 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
821 break;
822 case PN8_TYPE:
823 state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
824 state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
825 state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
826 break;
827 }
828
829 state.power = sets[i].power;
830
831 j = n;
832 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
833 memcpy(&sc->powernow_states[j],
834 &sc->powernow_states[j - 1],
835 sizeof(struct powernow_state));
836 --j;
837 }
838 memcpy(&sc->powernow_states[j], &state,
839 sizeof(struct powernow_state));
840 ++n;
841 }
842
843 sc->powernow_max_states = n;
844 state = sc->powernow_states[0];
845 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
846
847 switch (sc->pn_type) {
848 case PN7_TYPE:
849 sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl);
850 /*
851 * XXX Some bios forget the max frequency!
852 * This maybe indicates we have the wrong tables. Therefore,
853 * don't implement a quirk, but fallback to BIOS legacy
854 * tables instead.
855 */
856 if (PN7_STA_MFID(status) != state.fid) {
857 device_printf(dev, "ACPI MAX frequency not found\n");
858 return (EINVAL);
859 }
860 break;
861 case PN8_TYPE:
862 sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl),
863 sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl),
864 sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl),
865 sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl),
866 sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl);
867 sc->low = 0; /* XXX */
868
869 /*
870 * powernow k8 supports only one low frequency.
871 */
872 if (sc->powernow_max_states >= 2 &&
873 (sc->powernow_states[sc->powernow_max_states - 2].fid < 8))
874 return (EINVAL);
875 break;
876 }
877
878 return (0);
879}
880
881static void
882pn_identify(driver_t *driver, device_t parent)
883{
884 device_t child;
885
886 if (cpu_is_powernow_capable() == 0)
887 return;
888 switch (cpu_id & 0xf00) {
889 case 0x600:
890 case 0xf00:
891 break;
892 default:
893 return;
894 }
895 if (device_find_child(parent, "powernow", -1) != NULL)
896 return;
897 if ((child = BUS_ADD_CHILD(parent, 10, "powernow", -1)) == NULL)
898 device_printf(parent, "powernow: add child failed\n");
899}
900
901static int
902pn_probe(device_t dev)
903{
904 struct pn_softc *sc;
905 uint64_t status;
906 uint64_t rate;
907 struct pcpu *pc;
908 u_int sfid, mfid, cfid;
909
910 sc = device_get_softc(dev);
911 sc->errata = 0;
912 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
913
914 pc = cpu_get_pcpu(dev);
915 if (pc == NULL)
916 return (ENODEV);
917
918 cpu_est_clockrate(pc->pc_cpuid, &rate);
919
920 switch (cpu_id & 0xf00) {
921 case 0x600:
922 sfid = PN7_STA_SFID(status);
923 mfid = PN7_STA_MFID(status);
924 cfid = PN7_STA_CFID(status);
925 sc->pn_type = PN7_TYPE;
926 sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid];
927
928 /*
929 * If start FID is different to max FID, then it is a
930 * mobile processor. If not, it is a low powered desktop
931 * processor.
932 */
933 if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) {
934 sc->vid_to_volts = pn7_mobile_vid_to_volts;
935 device_set_desc(dev, "PowerNow! K7");
936 } else {
937 sc->vid_to_volts = pn7_desktop_vid_to_volts;
938 device_set_desc(dev, "Cool`n'Quiet K7");
939 }
940 break;
941
942 case 0xf00:
943 sfid = PN8_STA_SFID(status);
944 mfid = PN8_STA_MFID(status);
945 cfid = PN8_STA_CFID(status);
946 sc->pn_type = PN8_TYPE;
947 sc->vid_to_volts = pn8_vid_to_volts;
948 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
949
950 if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
951 device_set_desc(dev, "PowerNow! K8");
952 else
953 device_set_desc(dev, "Cool`n'Quiet K8");
954 break;
955 default:
956 return (ENODEV);
957 }
958
959 return (0);
960}
961
962static int
963pn_attach(device_t dev)
964{
965 int rv;
966 device_t child;
967
968 child = device_find_child(device_get_parent(dev), "acpi_perf", -1);
969 if (child) {
970 rv = pn_decode_acpi(dev, child);
971 if (rv)
972 rv = pn_decode_pst(dev);
973 } else
974 rv = pn_decode_pst(dev);
975
976 if (rv != 0)
977 return (ENXIO);
978 cpufreq_register(dev);
979 return (0);
980}
981
982static int
983pn_detach(device_t dev)
984{
985
986 cpufreq_unregister(dev);
987 return (0);
986 return (cpufreq_unregister(dev));
987}