powernow.c revision 305615
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: stable/10/sys/x86/cpufreq/powernow.c 305615 2016-09-08 15:06:28Z pfg $");
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
761static int
762pn_decode_acpi(device_t dev, device_t perf_dev)
763{
764	int i, j, n;
765	uint64_t status;
766	uint32_t ctrl;
767	u_int cpuid;
768	u_int regs[4];
769	struct pn_softc *sc;
770	struct powernow_state state;
771	struct cf_setting sets[POWERNOW_MAX_STATES];
772	int count = POWERNOW_MAX_STATES;
773	int type;
774	int rv;
775
776	if (perf_dev == NULL)
777		return (ENXIO);
778
779	rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count);
780	if (rv)
781		return (ENXIO);
782	rv = CPUFREQ_DRV_TYPE(perf_dev, &type);
783	if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
784		return (ENXIO);
785
786	sc = device_get_softc(dev);
787
788	do_cpuid(0x80000001, regs);
789	cpuid = regs[0];
790	if ((cpuid & 0xfff) == 0x760)
791		sc->errata |= A0_ERRATA;
792
793	ctrl = 0;
794	sc->sgtc = 0;
795	for (n = 0, i = 0; i < count; ++i) {
796		ctrl = sets[i].spec[PX_SPEC_CONTROL];
797		switch (sc->pn_type) {
798		case PN7_TYPE:
799			state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
800			state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
801			if ((sc->errata & A0_ERRATA) &&
802			    (pn7_fid_to_mult[state.fid] % 10) == 5)
803				continue;
804			break;
805		case PN8_TYPE:
806			state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
807			state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
808			break;
809		}
810		state.freq = sets[i].freq * 1000;
811		state.power = sets[i].power;
812
813		j = n;
814		while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
815			memcpy(&sc->powernow_states[j],
816			    &sc->powernow_states[j - 1],
817			    sizeof(struct powernow_state));
818			--j;
819		}
820		memcpy(&sc->powernow_states[j], &state,
821		    sizeof(struct powernow_state));
822		++n;
823	}
824
825	sc->powernow_max_states = n;
826	state = sc->powernow_states[0];
827	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
828
829	switch (sc->pn_type) {
830	case PN7_TYPE:
831		sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl);
832		/*
833		 * XXX Some bios forget the max frequency!
834		 * This maybe indicates we have the wrong tables.  Therefore,
835		 * don't implement a quirk, but fallback to BIOS legacy
836		 * tables instead.
837		 */
838		if (PN7_STA_MFID(status) != state.fid) {
839			device_printf(dev, "ACPI MAX frequency not found\n");
840			return (EINVAL);
841		}
842		sc->fsb = state.freq / 100 / pn7_fid_to_mult[state.fid];
843		break;
844	case PN8_TYPE:
845		sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl),
846		sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl),
847		sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl),
848		sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl),
849		sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl);
850		sc->low = 0; /* XXX */
851
852		/*
853		 * powernow k8 supports only one low frequency.
854		 */
855		if (sc->powernow_max_states >= 2 &&
856		    (sc->powernow_states[sc->powernow_max_states - 2].fid < 8))
857			return (EINVAL);
858		sc->fsb = state.freq / 100 / pn8_fid_to_mult[state.fid];
859		break;
860	}
861
862	return (0);
863}
864
865static void
866pn_identify(driver_t *driver, device_t parent)
867{
868
869	if ((amd_pminfo & AMDPM_FID) == 0 || (amd_pminfo & AMDPM_VID) == 0)
870		return;
871	switch (cpu_id & 0xf00) {
872	case 0x600:
873	case 0xf00:
874		break;
875	default:
876		return;
877	}
878	if (device_find_child(parent, "powernow", -1) != NULL)
879		return;
880	if (BUS_ADD_CHILD(parent, 10, "powernow", -1) == NULL)
881		device_printf(parent, "powernow: add child failed\n");
882}
883
884static int
885pn_probe(device_t dev)
886{
887	struct pn_softc *sc;
888	uint64_t status;
889	uint64_t rate;
890	struct pcpu *pc;
891	u_int sfid, mfid, cfid;
892
893	sc = device_get_softc(dev);
894	sc->errata = 0;
895	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
896
897	pc = cpu_get_pcpu(dev);
898	if (pc == NULL)
899		return (ENODEV);
900
901	cpu_est_clockrate(pc->pc_cpuid, &rate);
902
903	switch (cpu_id & 0xf00) {
904	case 0x600:
905		sfid = PN7_STA_SFID(status);
906		mfid = PN7_STA_MFID(status);
907		cfid = PN7_STA_CFID(status);
908		sc->pn_type = PN7_TYPE;
909		sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid];
910
911		/*
912		 * If start FID is different to max FID, then it is a
913		 * mobile processor.  If not, it is a low powered desktop
914		 * processor.
915		 */
916		if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) {
917			sc->vid_to_volts = pn7_mobile_vid_to_volts;
918			device_set_desc(dev, "PowerNow! K7");
919		} else {
920			sc->vid_to_volts = pn7_desktop_vid_to_volts;
921			device_set_desc(dev, "Cool`n'Quiet K7");
922		}
923		break;
924
925	case 0xf00:
926		sfid = PN8_STA_SFID(status);
927		mfid = PN8_STA_MFID(status);
928		cfid = PN8_STA_CFID(status);
929		sc->pn_type = PN8_TYPE;
930		sc->vid_to_volts = pn8_vid_to_volts;
931		sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
932
933		if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
934			device_set_desc(dev, "PowerNow! K8");
935		else
936			device_set_desc(dev, "Cool`n'Quiet K8");
937		break;
938	default:
939		return (ENODEV);
940	}
941
942	return (0);
943}
944
945static int
946pn_attach(device_t dev)
947{
948	int rv;
949	device_t child;
950
951	child = device_find_child(device_get_parent(dev), "acpi_perf", -1);
952	if (child) {
953		rv = pn_decode_acpi(dev, child);
954		if (rv)
955			rv = pn_decode_pst(dev);
956	} else
957		rv = pn_decode_pst(dev);
958
959	if (rv != 0)
960		return (ENXIO);
961	cpufreq_register(dev);
962	return (0);
963}
964
965static int
966pn_detach(device_t dev)
967{
968
969	return (cpufreq_unregister(dev));
970}
971