1 /* $OpenBSD: powernow-k8.c,v 1.35 2023/01/30 10:49:05 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2004 Martin V�giard.
5 * Copyright (c) 2004-2005 Bruno Ducrot
6 * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 /* AMD POWERNOW K8 driver */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/sysctl.h>
34
35 #include <dev/isa/isareg.h>
36 #include <i386/isa/isa_machdep.h>
37
38 #include <machine/cpufunc.h>
39 #include <machine/bus.h>
40
41 #include "acpicpu.h"
42
43 #if NACPICPU > 0
44 #include <dev/acpi/acpidev.h>
45 #endif
46
47 #define BIOS_START 0xe0000
48 #define BIOS_LEN 0x20000
49 #define BIOS_STEP 16
50
51 /*
52 * MSRs and bits used by PowerNow! technology
53 */
54 #define MSR_AMDK7_FIDVID_CTL 0xc0010041
55 #define MSR_AMDK7_FIDVID_STATUS 0xc0010042
56 #define AMD_PN_FID_VID 0x06
57
58 /* Bitfields used by K8 */
59
60 #define PN8_CTR_FID(x) ((x) & 0x3f)
61 #define PN8_CTR_VID(x) (((x) & 0x1f) << 8)
62 #define PN8_CTR_PENDING(x) (((x) & 1) << 32)
63
64 #define PN8_STA_CFID(x) ((x) & 0x3f)
65 #define PN8_STA_SFID(x) (((x) >> 8) & 0x3f)
66 #define PN8_STA_MFID(x) (((x) >> 16) & 0x3f)
67 #define PN8_STA_PENDING(x) (((x) >> 31) & 0x01)
68 #define PN8_STA_CVID(x) (((x) >> 32) & 0x1f)
69 #define PN8_STA_SVID(x) (((x) >> 40) & 0x1f)
70 #define PN8_STA_MVID(x) (((x) >> 48) & 0x1f)
71
72 /* Reserved1 to powernow k8 configuration */
73 #define PN8_PSB_VERSION 0x14
74 #define PN8_PSB_TO_RVO(x) ((x) & 0x03)
75 #define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03)
76 #define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03)
77 #define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03)
78
79 /* ACPI ctr_val status register to powernow k8 configuration */
80 #define PN8_ACPI_CTRL_TO_FID(x) ((x) & 0x3f)
81 #define PN8_ACPI_CTRL_TO_VID(x) (((x) >> 6) & 0x1f)
82 #define PN8_ACPI_CTRL_TO_VST(x) (((x) >> 11) & 0x1f)
83 #define PN8_ACPI_CTRL_TO_MVS(x) (((x) >> 18) & 0x03)
84 #define PN8_ACPI_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f)
85 #define PN8_ACPI_CTRL_TO_RVO(x) (((x) >> 28) & 0x03)
86 #define PN8_ACPI_CTRL_TO_IRT(x) (((x) >> 30) & 0x03)
87
88 #define PN8_PSS_CFID(x) ((x) & 0x3f)
89 #define PN8_PSS_CVID(x) (((x) >> 6) & 0x1f)
90
91 #define PN8_PLL_LOCK(x) ((x) * 1000/5)
92 #define WRITE_FIDVID(fid, vid, ctrl) \
93 wrmsr(MSR_AMDK7_FIDVID_CTL, \
94 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
95
96 #define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt)))
97 #define COUNT_OFF_VST(vst) DELAY(20 * (vst))
98
99 #define FID_TO_VCO_FID(fid) \
100 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
101
102 #define POWERNOW_MAX_STATES 16
103
104 struct k8pnow_state {
105 int freq;
106 uint8_t fid;
107 uint8_t vid;
108 };
109
110 struct k8pnow_cpu_state {
111 struct k8pnow_state state_table[POWERNOW_MAX_STATES];
112 unsigned int n_states;
113 unsigned int sgtc;
114 unsigned int vst;
115 unsigned int mvs;
116 unsigned int pll;
117 unsigned int rvo;
118 unsigned int irt;
119 int low;
120 };
121
122 struct psb_s {
123 char signature[10]; /* AMDK7PNOW! */
124 uint8_t version;
125 uint8_t flags;
126 uint16_t ttime; /* Min Settling time */
127 uint8_t reserved;
128 uint8_t n_pst;
129 };
130
131 struct pst_s {
132 uint32_t cpuid;
133 uint8_t pll;
134 uint8_t fid;
135 uint8_t vid;
136 uint8_t n_states;
137 };
138
139 struct k8pnow_cpu_state *k8pnow_current_state = NULL;
140 extern int setperf_prio;
141 extern int perflevel;
142
143 int k8pnow_read_pending_wait(uint64_t *);
144 int k8pnow_decode_pst(struct k8pnow_cpu_state *, uint8_t *);
145 int k8pnow_states(struct k8pnow_cpu_state *, uint32_t, unsigned int, unsigned int);
146 void k8pnow_transition(struct k8pnow_cpu_state *e, int);
147
148 #if NACPICPU > 0
149 int k8pnow_acpi_init(struct k8pnow_cpu_state *, uint64_t);
150 void k8pnow_acpi_pss_changed(struct acpicpu_pss *, int);
151 int k8pnow_acpi_states(struct k8pnow_cpu_state *, struct acpicpu_pss *, int,
152 uint64_t);
153 #endif
154
155 int
k8pnow_read_pending_wait(uint64_t * status)156 k8pnow_read_pending_wait(uint64_t *status)
157 {
158 unsigned int i = 100000;
159
160 while (i--) {
161 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
162 if (!PN8_STA_PENDING(*status))
163 return 0;
164
165 }
166 printf("k8pnow_read_pending_wait: change pending stuck.\n");
167 return 1;
168 }
169
170 void
k8_powernow_setperf(int level)171 k8_powernow_setperf(int level)
172 {
173 unsigned int i;
174 struct k8pnow_cpu_state *cstate;
175
176 cstate = k8pnow_current_state;
177
178 i = ((level * cstate->n_states) + 1) / 101;
179 if (i >= cstate->n_states)
180 i = cstate->n_states - 1;
181
182 k8pnow_transition(cstate, i);
183 }
184
185 void
k8pnow_transition(struct k8pnow_cpu_state * cstate,int level)186 k8pnow_transition(struct k8pnow_cpu_state *cstate, int level)
187 {
188 uint64_t status;
189 int cfid, cvid, fid = 0, vid = 0;
190 int rvo;
191 u_int val;
192
193 /*
194 * We dont do a k8pnow_read_pending_wait here, need to ensure that the
195 * change pending bit isn't stuck,
196 */
197 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
198 if (PN8_STA_PENDING(status))
199 return;
200 cfid = PN8_STA_CFID(status);
201 cvid = PN8_STA_CVID(status);
202
203 fid = cstate->state_table[level].fid;
204 vid = cstate->state_table[level].vid;
205
206 if (fid == cfid && vid == cvid)
207 return;
208
209 /*
210 * Phase 1: Raise core voltage to requested VID if frequency is
211 * going up.
212 */
213 while (cvid > vid) {
214 val = cvid - (1 << cstate->mvs);
215 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
216 if (k8pnow_read_pending_wait(&status))
217 return;
218 cvid = PN8_STA_CVID(status);
219 COUNT_OFF_VST(cstate->vst);
220 }
221
222 /* ... then raise to voltage + RVO (if required) */
223 for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) {
224 /* XXX It's not clear from spec if we have to do that
225 * in 0.25 step or in MVS. Therefore do it as it's done
226 * under Linux */
227 WRITE_FIDVID(cfid, cvid - 1, 1ULL);
228 if (k8pnow_read_pending_wait(&status))
229 return;
230 cvid = PN8_STA_CVID(status);
231 COUNT_OFF_VST(cstate->vst);
232 }
233
234 /* Phase 2: change to requested core frequency */
235 if (cfid != fid) {
236 u_int vco_fid, vco_cfid;
237
238 vco_fid = FID_TO_VCO_FID(fid);
239 vco_cfid = FID_TO_VCO_FID(cfid);
240
241 while (abs(vco_fid - vco_cfid) > 2) {
242 if (fid > cfid) {
243 if (cfid > 6)
244 val = cfid + 2;
245 else
246 val = FID_TO_VCO_FID(cfid) + 2;
247 } else
248 val = cfid - 2;
249 WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5);
250
251 if (k8pnow_read_pending_wait(&status))
252 return;
253 cfid = PN8_STA_CFID(status);
254 COUNT_OFF_IRT(cstate->irt);
255
256 vco_cfid = FID_TO_VCO_FID(cfid);
257 }
258
259 WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5);
260 if (k8pnow_read_pending_wait(&status))
261 return;
262 cfid = PN8_STA_CFID(status);
263 COUNT_OFF_IRT(cstate->irt);
264 }
265
266 /* Phase 3: change to requested voltage */
267 if (cvid != vid) {
268 WRITE_FIDVID(cfid, vid, 1ULL);
269 if (k8pnow_read_pending_wait(&status))
270 return;
271 cvid = PN8_STA_CVID(status);
272 COUNT_OFF_VST(cstate->vst);
273 }
274
275 if (cfid == fid || cvid == vid)
276 cpuspeed = cstate->state_table[level].freq;
277 }
278
279 /*
280 * Given a set of pair of fid/vid, and number of performance states,
281 * compute state_table via an insertion sort.
282 */
283 int
k8pnow_decode_pst(struct k8pnow_cpu_state * cstate,uint8_t * p)284 k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p)
285 {
286 int i, j, n;
287 struct k8pnow_state state;
288
289 for (n = 0, i = 0; i < cstate->n_states; i++) {
290 state.fid = *p++;
291 state.vid = *p++;
292
293 /*
294 * The minimum supported frequency per the data sheet is 800MHz
295 * The maximum supported frequency is 5000MHz.
296 */
297 state.freq = 800 + state.fid * 100;
298 j = n;
299 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
300 memcpy(&cstate->state_table[j],
301 &cstate->state_table[j - 1],
302 sizeof(struct k8pnow_state));
303 --j;
304 }
305 memcpy(&cstate->state_table[j], &state,
306 sizeof(struct k8pnow_state));
307 n++;
308 }
309 return 1;
310 }
311
312 int
k8pnow_states(struct k8pnow_cpu_state * cstate,uint32_t cpusig,unsigned int fid,unsigned int vid)313 k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig,
314 unsigned int fid, unsigned int vid)
315 {
316 struct psb_s *psb;
317 struct pst_s *pst;
318 uint8_t *p;
319 int i;
320
321 /*
322 * Look in the 0xe0000 - 0x100000 physical address
323 * range for the pst tables; 16 byte blocks. End 10 bytes
324 * before the end of the range to avoid memcmp across a
325 * page boundary into unmapped memory.
326 */
327 for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
328 p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN) - 10;
329 p += BIOS_STEP) {
330 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
331 psb = (struct psb_s *)p;
332 if (psb->version != PN8_PSB_VERSION)
333 return 0;
334
335 cstate->vst = psb->ttime;
336 cstate->rvo = PN8_PSB_TO_RVO(psb->reserved);
337 cstate->irt = PN8_PSB_TO_IRT(psb->reserved);
338 cstate->mvs = PN8_PSB_TO_MVS(psb->reserved);
339 cstate->low = PN8_PSB_TO_BATT(psb->reserved);
340 p+= sizeof(struct psb_s);
341
342 for (i = 0; i < psb->n_pst; ++i) {
343 pst = (struct pst_s *) p;
344
345 cstate->pll = pst->pll;
346 cstate->n_states = pst->n_states;
347 if (cpusig == pst->cpuid &&
348 pst->fid == fid && pst->vid == vid) {
349 return (k8pnow_decode_pst(cstate,
350 p+= sizeof (struct pst_s)));
351 }
352 p += sizeof(struct pst_s) + 2
353 * cstate->n_states;
354 }
355 }
356 }
357
358 return 0;
359
360 }
361
362 #if NACPICPU > 0
363
364 int
k8pnow_acpi_states(struct k8pnow_cpu_state * cstate,struct acpicpu_pss * pss,int nstates,uint64_t status)365 k8pnow_acpi_states(struct k8pnow_cpu_state * cstate, struct acpicpu_pss * pss,
366 int nstates, uint64_t status)
367 {
368 struct k8pnow_state state;
369 int j, k, n;
370 uint32_t ctrl;
371
372 k = -1;
373
374 for (n = 0; n < cstate->n_states; n++) {
375 if ((PN8_STA_CFID(status) == PN8_PSS_CFID(pss[n].pss_status)) &&
376 (PN8_STA_CVID(status) == PN8_PSS_CVID(pss[n].pss_status)))
377 k = n;
378 ctrl = pss[n].pss_ctrl;
379 state.fid = PN8_ACPI_CTRL_TO_FID(ctrl);
380 state.vid = PN8_ACPI_CTRL_TO_VID(ctrl);
381
382 state.freq = pss[n].pss_core_freq;
383 j = n;
384 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
385 memcpy(&cstate->state_table[j],
386 &cstate->state_table[j - 1],
387 sizeof(struct k8pnow_state));
388 --j;
389 }
390 memcpy(&cstate->state_table[j], &state,
391 sizeof(struct k8pnow_state));
392 }
393
394 return k;
395 }
396
397 void
k8pnow_acpi_pss_changed(struct acpicpu_pss * pss,int npss)398 k8pnow_acpi_pss_changed(struct acpicpu_pss * pss, int npss)
399 {
400 int curs;
401 struct k8pnow_cpu_state * cstate;
402 uint32_t ctrl;
403 uint64_t status;
404
405 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
406 cstate = k8pnow_current_state;
407
408 curs = k8pnow_acpi_states(cstate, pss, npss, status);
409 ctrl = pss[curs].pss_ctrl;
410
411 cstate->rvo = PN8_ACPI_CTRL_TO_RVO(ctrl);
412 cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl);
413 cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl);
414 cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl);
415 cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl);
416 cstate->low = 0;
417 cstate->n_states = npss;
418 }
419
420 int
k8pnow_acpi_init(struct k8pnow_cpu_state * cstate,uint64_t status)421 k8pnow_acpi_init(struct k8pnow_cpu_state * cstate, uint64_t status)
422 {
423 int curs;
424 uint32_t ctrl;
425 struct acpicpu_pss *pss;
426
427 cstate->n_states = acpicpu_fetch_pss(&pss);
428 if (cstate->n_states == 0)
429 return 0;
430 acpicpu_set_notify(k8pnow_acpi_pss_changed);
431
432 curs = k8pnow_acpi_states(cstate, pss, cstate->n_states, status);
433 ctrl = pss[curs].pss_ctrl;
434
435 cstate->rvo = PN8_ACPI_CTRL_TO_RVO(ctrl);
436 cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl);
437 cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl);
438 cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl);
439 cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl);
440 cstate->low = 0;
441
442 return 1;
443 }
444
445 #endif /* NACPICPU */
446
447 void
k8_powernow_init(void)448 k8_powernow_init(void)
449 {
450 uint64_t status;
451 u_int maxfid, maxvid, i;
452 struct k8pnow_cpu_state *cstate;
453 struct k8pnow_state *state;
454 struct cpu_info * ci;
455 char * techname = NULL;
456 u_int32_t regs[4];
457
458 ci = curcpu();
459
460 if (setperf_prio > 1)
461 return;
462
463 if (k8pnow_current_state)
464 return;
465
466 cpuid(0x80000000, regs);
467 if (regs[0] < 0x80000007)
468 return;
469
470 cpuid(0x80000007, regs);
471 if (!(regs[3] & AMD_PN_FID_VID))
472 return;
473
474 /* Extended CPUID signature value */
475 cpuid(0x80000001, regs);
476
477 cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT);
478 if (!cstate)
479 return;
480
481 cstate->n_states = 0;
482 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
483 maxfid = PN8_STA_MFID(status);
484 maxvid = PN8_STA_MVID(status);
485
486 /*
487 * If start FID is different to max FID, then it is a
488 * mobile processor. If not, it is a low powered desktop
489 * processor.
490 */
491 if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
492 techname = "PowerNow! K8";
493 else
494 techname = "Cool'n'Quiet K8";
495
496 #if NACPICPU > 0
497 /* If we have acpi check acpi first */
498 if (!k8pnow_acpi_init(cstate, status))
499 #endif
500 {
501 if (!k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid))
502 k8pnow_states(cstate, regs[0], maxfid, maxvid);
503 }
504 if (cstate->n_states) {
505 printf("%s: %s %d MHz: speeds:",
506 ci->ci_dev->dv_xname, techname, cpuspeed);
507 for (i = cstate->n_states; i > 0; i--) {
508 state = &cstate->state_table[i-1];
509 printf(" %d", state->freq);
510 }
511 printf(" MHz\n");
512 k8pnow_current_state = cstate;
513 cpu_setperf = k8_powernow_setperf;
514 setperf_prio = 1;
515 return;
516 }
517 free(cstate, M_DEVBUF, sizeof(*cstate));
518 }
519