powernow.c revision 144194
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 144194 2005-03-27 21:44:21Z 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			if (sc->pn_type != PN8_TYPE || psb->numpst != 1)
640				return (EINVAL);
641			sc->vst = psb->settlingtime;
642			sc->rvo = PN8_PSB_TO_RVO(psb->res1),
643			sc->irt = PN8_PSB_TO_IRT(psb->res1),
644			sc->mvs = PN8_PSB_TO_MVS(psb->res1),
645			sc->low = PN8_PSB_TO_BATT(psb->res1);
646			if (bootverbose) {
647				device_printf(dev, "PSB: VST: %d\n",
648				    psb->settlingtime);
649				device_printf(dev, "PSB: RVO %x IRT %d "
650				    "MVS %d BATT %d\n",
651				    sc->rvo,
652				    sc->irt,
653				    sc->mvs,
654				    sc->low);
655			}
656			break;
657		case 0x12:
658			if (sc->pn_type != PN7_TYPE)
659				return (EINVAL);
660			sc->sgtc = psb->settlingtime * sc->fsb;
661			if (sc->sgtc < 100 * sc->fsb)
662				sc->sgtc = 100 * sc->fsb;
663			break;
664		}
665
666		p = ((uint8_t *) psb) + sizeof(struct psb_header);
667		pst = (struct pst_header*) p;
668
669		maxpst = 200;
670
671		do {
672			struct pst_header *pst = (struct pst_header*) p;
673
674			if (cpuid == pst->cpuid &&
675			    maxfid == pst->maxfid &&
676			    startvid == pst->startvid) {
677				sc->powernow_max_states = pst->numpstates;
678				switch (sc->pn_type) {
679				case PN7_TYPE:
680					if (abs(sc->fsb - pst->fsb) > 5)
681						continue;
682					break;
683				case PN8_TYPE:
684					break;
685				}
686				return (decode_pst(sc,
687				    p + sizeof(struct pst_header),
688				    sc->powernow_max_states));
689			}
690
691			p += sizeof(struct pst_header) + (2 * pst->numpstates);
692		} while (cpuid_is_k7(pst->cpuid) && maxpst--);
693
694		device_printf(dev, "no match for extended cpuid %.3x\n", cpuid);
695	}
696
697	return (ENODEV);
698}
699
700/*
701 * TODO: this should be done in sys/ARCH/ARCH/identcpu.c
702 */
703static int
704cpu_is_powernow_capable(void)
705{
706	u_int regs[4];
707
708	if (strcmp(cpu_vendor, "AuthenticAMD") != 0 ||
709	    cpu_exthigh < 0x80000007)
710		return (FALSE);
711
712	do_cpuid(0x80000007, regs);
713	return (regs[3] & 0x6);
714}
715
716static int
717pn_decode_acpi(device_t dev, device_t perf_dev)
718{
719	int i, j, n;
720	uint64_t status;
721	uint32_t ctrl;
722	u_int cpuid;
723	u_int regs[4];
724	struct pn_softc *sc;
725	struct powernow_state state;
726	struct cf_setting sets[POWERNOW_MAX_STATES];
727	int count = POWERNOW_MAX_STATES;
728	int type;
729	int rv;
730
731	if (perf_dev == NULL)
732		return (ENXIO);
733
734	rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count);
735	if (rv)
736		return (ENXIO);
737	rv = CPUFREQ_DRV_TYPE(perf_dev, &type);
738	if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
739		return (ENXIO);
740
741	sc = device_get_softc(dev);
742
743	do_cpuid(0x80000001, regs);
744	cpuid = regs[0];
745	if ((cpuid & 0xfff) == 0x760)
746		sc->errata_a0 = TRUE;
747
748	ctrl = 0;
749	sc->sgtc = 0;
750	for (n = 0, i = 0; i < count; ++i) {
751		ctrl = sets[i].spec[PX_SPEC_CONTROL];
752		switch (sc->pn_type) {
753		case PN7_TYPE:
754			state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
755			state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
756			if (sc->errata_a0 &&
757			    (pn7_fid_to_mult[state.fid] % 10) == 5)
758				continue;
759			state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
760			break;
761		case PN8_TYPE:
762			state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
763			state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
764			state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
765			    sc->fsb;
766			break;
767		}
768
769		state.power = sets[i].power;
770
771		j = n;
772		while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
773			memcpy(&sc->powernow_states[j],
774			    &sc->powernow_states[j - 1],
775			    sizeof(struct powernow_state));
776			--j;
777		}
778		memcpy(&sc->powernow_states[j], &state,
779		    sizeof(struct powernow_state));
780		++n;
781	}
782
783	sc->powernow_max_states = n;
784	state = sc->powernow_states[0];
785	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
786
787	switch (sc->pn_type) {
788	case PN7_TYPE:
789		sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl);
790		/*
791		 * XXX Some bios forget the max frequency!
792		 * This maybe indicates we have the wrong tables.  Therefore,
793		 * don't implement a quirk, but fallback to BIOS legacy
794		 * tables instead.
795		 */
796		if (PN7_STA_MFID(status) != state.fid) {
797			device_printf(dev, "ACPI MAX frequency not found\n");
798			return (EINVAL);
799		}
800		break;
801	case PN8_TYPE:
802		sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl),
803		sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl),
804		sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl),
805		sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl),
806		sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl);
807		sc->low = 0; /* XXX */
808
809		/*
810		 * powernow k8 supports only one low frequency.
811		 */
812		if (sc->powernow_max_states >= 2 &&
813		    (sc->powernow_states[sc->powernow_max_states - 2].fid < 8))
814			return (EINVAL);
815		break;
816	}
817
818	return (0);
819}
820
821static void
822pn_identify(driver_t *driver, device_t parent)
823{
824	device_t child;
825
826	if (cpu_is_powernow_capable() == 0)
827		return;
828	switch (cpu_id & 0xf00) {
829	case 0x600:
830	case 0xf00:
831		break;
832	default:
833		return;
834	}
835	if (device_find_child(parent, "powernow", -1) != NULL)
836		return;
837	if ((child = BUS_ADD_CHILD(parent, 0, "powernow", -1)) == NULL)
838		device_printf(parent, "powernow: add child failed\n");
839}
840
841static int
842pn_probe(device_t dev)
843{
844	struct pn_softc *sc;
845	uint64_t status;
846	uint64_t rate;
847	struct pcpu *pc;
848	u_int sfid, mfid, cfid;
849
850	sc = device_get_softc(dev);
851	sc->errata_a0 = FALSE;
852	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
853
854	pc = cpu_get_pcpu(dev);
855	if (pc == NULL)
856		return (ENODEV);
857
858	cpu_est_clockrate(pc->pc_cpuid, &rate);
859
860	switch (cpu_id & 0xf00) {
861	case 0x600:
862		sfid = PN7_STA_SFID(status);
863		mfid = PN7_STA_MFID(status);
864		cfid = PN7_STA_CFID(status);
865		sc->pn_type = PN7_TYPE;
866		sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid];
867
868		/*
869		 * If start FID is different to max FID, then it is a
870		 * mobile processor.  If not, it is a low powered desktop
871		 * processor.
872		 */
873		if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) {
874			sc->vid_to_volts = pn7_mobile_vid_to_volts;
875			device_set_desc(dev, "PowerNow! K7");
876		} else {
877			sc->vid_to_volts = pn7_desktop_vid_to_volts;
878			device_set_desc(dev, "Cool`n'Quiet K7");
879		}
880		break;
881
882	case 0xf00:
883		sfid = PN8_STA_SFID(status);
884		mfid = PN8_STA_MFID(status);
885		cfid = PN8_STA_CFID(status);
886		sc->pn_type = PN8_TYPE;
887		sc->vid_to_volts = pn8_vid_to_volts;
888		sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid >> 1];
889
890		if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
891			device_set_desc(dev, "PowerNow! K8");
892		else
893			device_set_desc(dev, "Cool`n'Quiet K8");
894		break;
895	default:
896		return (ENODEV);
897	}
898
899	return (0);
900}
901
902static int
903pn_attach(device_t dev)
904{
905	int rv;
906	device_t child;
907
908	child = device_find_child(device_get_parent(dev), "acpi_perf", -1);
909	if (child) {
910		rv = pn_decode_acpi(dev, child);
911		if (rv)
912			rv = pn_decode_pst(dev);
913	} else
914		rv = pn_decode_pst(dev);
915
916	if (rv != 0)
917		return (ENXIO);
918	cpufreq_register(dev);
919	return (0);
920}
921
922static int
923pn_detach(device_t dev)
924{
925
926	cpufreq_unregister(dev);
927	return (0);
928}
929