Deleted Added
full compact
powernow.c (158651) powernow.c (166197)
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>
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 $");
32__FBSDID("$FreeBSD: head/sys/i386/cpufreq/powernow.c 166197 2007-01-23 19:20:30Z bruno $");
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
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
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
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
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
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
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,
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,
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;
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;
222 int errata_a0;
230 u_int errata;
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
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
288 if (sc->errata_a0)
296 if (sc->errata & A0_ERRATA)
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
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
301 if (sc->errata_a0)
309 if (sc->errata & A0_ERRATA)
302 enable_intr();
303
304 return (0);
305}
306
307static int
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
308pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
309{
310 uint64_t status;
311 int cfid, cvid;
312 int rvo;
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;
313 u_int val;
314
346 u_int val;
347
315 READ_PENDING_WAIT(status);
348 rv = pn8_read_pending_wait(&status);
349 if (rv)
350 return (rv);
351
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);
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);
328 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
329 READ_PENDING_WAIT(status);
364 rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status);
365 if (rv) {
366 sc->errata |= PENDING_STUCK;
367 return (rv);
368 }
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 */
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 */
339 WRITE_FIDVID(cfid, cvid - 1, 1ULL);
340 READ_PENDING_WAIT(status);
378 rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status);
379 if (rv) {
380 sc->errata |= PENDING_STUCK;
381 return (rv);
382 }
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) {
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) {
347 u_int vco_fid, vco_cfid;
389 u_int vco_fid, vco_cfid, fid_delta;
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) {
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;
353 if (fid > cfid) {
396 if (fid > cfid) {
354 if (cfid > 6)
355 val = cfid + 2;
397 if (cfid > 7)
398 val = cfid + fid_delta;
356 else
399 else
357 val = FID_TO_VCO_FID(cfid) + 2;
400 val = FID_TO_VCO_FID(cfid) + fid_delta;
358 } else
401 } else
359 val = cfid - 2;
360 WRITE_FIDVID(val, cvid, sc->pll * (uint64_t) sc->fsb);
361 READ_PENDING_WAIT(status);
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 }
362 cfid = PN8_STA_CFID(status);
363 COUNT_OFF_IRT(sc->irt);
364
365 vco_cfid = FID_TO_VCO_FID(cfid);
366 }
367
410 cfid = PN8_STA_CFID(status);
411 COUNT_OFF_IRT(sc->irt);
412
413 vco_cfid = FID_TO_VCO_FID(cfid);
414 }
415
368 WRITE_FIDVID(fid, cvid, sc->pll * (uint64_t) sc->fsb);
369 READ_PENDING_WAIT(status);
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 }
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) {
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) {
376 WRITE_FIDVID(cfid, vid, 1ULL);
377 READ_PENDING_WAIT(status);
429 rv = pn8_write_fidvid(cfid, vid, 1ULL, &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)
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)
384 return (ENXIO);
436 rv = ENXIO;
385
437
386 return (0);
438 return (rv);
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
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
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);
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);
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;
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;
520 if (sc->errata_a0 &&
577 if ((sc->errata & A0_ERRATA) &&
521 (pn7_fid_to_mult[state.fid] % 10) == 5)
522 continue;
523 break;
524 case PN8_TYPE:
578 (pn7_fid_to_mult[state.fid] % 10) == 5)
579 continue;
580 break;
581 case PN8_TYPE:
525 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
526 sc->fsb;
582 state.freq = 100 * pn8_fid_to_mult[state.fid] * 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 /*
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 /*
543 * Fix powernow_max_states, if errata_a0 give us less states
599 * 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)
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)
599 sc->errata_a0 = TRUE;
655 sc->errata |= A0_ERRATA;
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)
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)
751 sc->errata_a0 = TRUE;
807 sc->errata |= A0_ERRATA;
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);
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);
761 if (sc->errata_a0 &&
817 if ((sc->errata & A0_ERRATA) &&
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);
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);
769 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
770 sc->fsb;
825 state.freq = 100 * pn8_fid_to_mult[state.fid] * 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);
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, 0, "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);
856 sc->errata_a0 = FALSE;
911 sc->errata = 0;
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;
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;
893 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid >> 1];
948 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
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}
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 cpufreq_unregister(dev);
987 return (0);
988}