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