powernow.c revision 182401
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 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	return (cpufreq_unregister(dev));
987}
988