xref: /openbsd-src/sys/arch/i386/i386/powernow-k8.c (revision f4e7063748a2ac72b2bab4389c0a7efc72d82189)
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