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