Deleted Added
sdiff udiff text old ( 158651 ) new ( 166197 )
full compact
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

--- 15 unchanged lines hidden (view full) ---

24 */
25
26/*
27 * Many thanks to Nate Lawson for his helpful comments on this driver and
28 * to Jung-uk Kim for testing.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/i386/cpufreq/powernow.c 158651 2006-05-16 14:37:58Z phk $");
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/cpu.h>
37#include <sys/kernel.h>
38#include <sys/malloc.h>
39#include <sys/module.h>
40#include <sys/pcpu.h>

--- 9 unchanged lines hidden (view full) ---

50#include <vm/vm.h>
51#include <vm/pmap.h>
52
53#include "cpufreq_if.h"
54
55#define PN7_TYPE 0
56#define PN8_TYPE 1
57
58/* Legacy configuration via BIOS table PSB. */
59#define PSB_START 0
60#define PSB_STEP 0x10
61#define PSB_SIG "AMDK7PNOW!"
62#define PSB_LEN 10
63#define PSB_OFF 0
64
65struct psb_header {

--- 69 unchanged lines hidden (view full) ---

135#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03)
136#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03)
137
138
139#define WRITE_FIDVID(fid, vid, ctrl) \
140 wrmsr(MSR_AMDK7_FIDVID_CTL, \
141 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
142
143#define READ_PENDING_WAIT(status) \
144 do { \
145 (status) = rdmsr(MSR_AMDK7_FIDVID_STATUS); \
146 } while (PN8_STA_PENDING(status))
147
148#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt)))
149#define COUNT_OFF_VST(vst) DELAY(20 * (vst))
150
151#define FID_TO_VCO_FID(fid) \
152 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
153
154/*
155 * Divide each value by 10 to get the processor multiplier.
156 * Some of those tables are the same as the Linux powernow-k7
157 * implementation by Dave Jones.
158 */
159static int pn7_fid_to_mult[32] = {
160 110, 115, 120, 125, 50, 55, 60, 65,
161 70, 75, 80, 85, 90, 95, 100, 105,
162 30, 190, 40, 200, 130, 135, 140, 210,
163 150, 225, 160, 165, 170, 180, 0, 0,
164};
165
166
167static int pn8_fid_to_mult[32] = {
168 40, 50, 60, 70, 80, 90, 100, 110,
169 120, 130, 140, 150, 160, 170, 180, 190,
170 220, 230, 240, 250, 260, 270, 280, 290,
171 300, 310, 320, 330, 340, 350,
172};
173
174/*
175 * Units are in mV.
176 */
177/* Mobile VRM (K7) */
178static int pn7_mobile_vid_to_volts[] = {
179 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,

--- 34 unchanged lines hidden (view full) ---

214 u_int vst;
215 u_int mvs;
216 u_int pll;
217 u_int rvo;
218 u_int irt;
219 int low;
220 int powernow_max_states;
221 u_int powernow_state;
222 int errata_a0;
223 int *vid_to_volts;
224};
225
226/*
227 * Offsets in struct cf_setting array for private values given by
228 * acpi_perf driver.
229 */
230#define PX_SPEC_CONTROL 0

--- 49 unchanged lines hidden (view full) ---

280 return (0);
281
282 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
283
284 ctl |= PN7_CTR_FID(fid);
285 ctl |= PN7_CTR_VID(vid);
286 ctl |= PN7_CTR_SGTC(sc->sgtc);
287
288 if (sc->errata_a0)
289 disable_intr();
290
291 if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) {
292 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
293 if (vid != cvid)
294 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
295 } else {
296 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
297 if (fid != cfid)
298 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
299 }
300
301 if (sc->errata_a0)
302 enable_intr();
303
304 return (0);
305}
306
307static int
308pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
309{
310 uint64_t status;
311 int cfid, cvid;
312 int rvo;
313 u_int val;
314
315 READ_PENDING_WAIT(status);
316 cfid = PN8_STA_CFID(status);
317 cvid = PN8_STA_CVID(status);
318
319 if (fid == cfid && vid == cvid)
320 return (0);
321
322 /*
323 * Phase 1: Raise core voltage to requested VID if frequency is
324 * going up.
325 */
326 while (cvid > vid) {
327 val = cvid - (1 << sc->mvs);
328 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
329 READ_PENDING_WAIT(status);
330 cvid = PN8_STA_CVID(status);
331 COUNT_OFF_VST(sc->vst);
332 }
333
334 /* ... then raise to voltage + RVO (if required) */
335 for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) {
336 /* XXX It's not clear from spec if we have to do that
337 * in 0.25 step or in MVS. Therefore do it as it's done
338 * under Linux */
339 WRITE_FIDVID(cfid, cvid - 1, 1ULL);
340 READ_PENDING_WAIT(status);
341 cvid = PN8_STA_CVID(status);
342 COUNT_OFF_VST(sc->vst);
343 }
344
345 /* Phase 2: change to requested core frequency */
346 if (cfid != fid) {
347 u_int vco_fid, vco_cfid;
348
349 vco_fid = FID_TO_VCO_FID(fid);
350 vco_cfid = FID_TO_VCO_FID(cfid);
351
352 while (abs(vco_fid - vco_cfid) > 2) {
353 if (fid > cfid) {
354 if (cfid > 6)
355 val = cfid + 2;
356 else
357 val = FID_TO_VCO_FID(cfid) + 2;
358 } else
359 val = cfid - 2;
360 WRITE_FIDVID(val, cvid, sc->pll * (uint64_t) sc->fsb);
361 READ_PENDING_WAIT(status);
362 cfid = PN8_STA_CFID(status);
363 COUNT_OFF_IRT(sc->irt);
364
365 vco_cfid = FID_TO_VCO_FID(cfid);
366 }
367
368 WRITE_FIDVID(fid, cvid, sc->pll * (uint64_t) sc->fsb);
369 READ_PENDING_WAIT(status);
370 cfid = PN8_STA_CFID(status);
371 COUNT_OFF_IRT(sc->irt);
372 }
373
374 /* Phase 3: change to requested voltage */
375 if (cvid != vid) {
376 WRITE_FIDVID(cfid, vid, 1ULL);
377 READ_PENDING_WAIT(status);
378 cvid = PN8_STA_CVID(status);
379 COUNT_OFF_VST(sc->vst);
380 }
381
382 /* Check if transition failed. */
383 if (cfid != fid || cvid != vid)
384 return (ENXIO);
385
386 return (0);
387}
388
389static int
390pn_set(device_t dev, const struct cf_setting *cf)
391{
392 struct pn_softc *sc;
393 int fid, vid;
394 int i;
395 int rv;
396
397 if (cf == NULL)
398 return (EINVAL);
399 sc = device_get_softc(dev);
400
401 for (i = 0; i < sc->powernow_max_states; ++i)
402 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq))
403 break;
404
405 fid = sc->powernow_states[i].fid;
406 vid = sc->powernow_states[i].vid;
407
408 rv = ENODEV;

--- 16 unchanged lines hidden (view full) ---

425 struct pn_softc *sc;
426 u_int cfid = 0, cvid = 0;
427 int i;
428 uint64_t status;
429
430 if (cf == NULL)
431 return (EINVAL);
432 sc = device_get_softc(dev);
433
434 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
435
436 switch (sc->pn_type) {
437 case PN7_TYPE:
438 cfid = PN7_STA_CFID(status);
439 cvid = PN7_STA_CVID(status);
440 break;

--- 71 unchanged lines hidden (view full) ---

512 for (n = 0, i = 0; i < npstates; ++i) {
513 state.fid = *p++;
514 state.vid = *p++;
515 state.power = CPUFREQ_VAL_UNKNOWN;
516
517 switch (sc->pn_type) {
518 case PN7_TYPE:
519 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
520 if (sc->errata_a0 &&
521 (pn7_fid_to_mult[state.fid] % 10) == 5)
522 continue;
523 break;
524 case PN8_TYPE:
525 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
526 sc->fsb;
527 break;
528 }
529
530 j = n;
531 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
532 memcpy(&sc->powernow_states[j],
533 &sc->powernow_states[j - 1],
534 sizeof(struct powernow_state));
535 --j;
536 }
537 memcpy(&sc->powernow_states[j], &state,
538 sizeof(struct powernow_state));
539 ++n;
540 }
541
542 /*
543 * Fix powernow_max_states, if errata_a0 give us less states
544 * than expected.
545 */
546 sc->powernow_max_states = n;
547
548 if (bootverbose)
549 for (i = 0; i < sc->powernow_max_states; ++i) {
550 int fid = sc->powernow_states[i].fid;
551 int vid = sc->powernow_states[i].vid;

--- 39 unchanged lines hidden (view full) ---

591 uint64_t status;
592
593 sc = device_get_softc(dev);
594
595 do_cpuid(0x80000001, regs);
596 cpuid = regs[0];
597
598 if ((cpuid & 0xfff) == 0x760)
599 sc->errata_a0 = TRUE;
600
601 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
602
603 switch (sc->pn_type) {
604 case PN7_TYPE:
605 maxfid = PN7_STA_MFID(status);
606 startvid = PN7_STA_SVID(status);
607 break;

--- 135 unchanged lines hidden (view full) ---

743 if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
744 return (ENXIO);
745
746 sc = device_get_softc(dev);
747
748 do_cpuid(0x80000001, regs);
749 cpuid = regs[0];
750 if ((cpuid & 0xfff) == 0x760)
751 sc->errata_a0 = TRUE;
752
753 ctrl = 0;
754 sc->sgtc = 0;
755 for (n = 0, i = 0; i < count; ++i) {
756 ctrl = sets[i].spec[PX_SPEC_CONTROL];
757 switch (sc->pn_type) {
758 case PN7_TYPE:
759 state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
760 state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
761 if (sc->errata_a0 &&
762 (pn7_fid_to_mult[state.fid] % 10) == 5)
763 continue;
764 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
765 break;
766 case PN8_TYPE:
767 state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
768 state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
769 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
770 sc->fsb;
771 break;
772 }
773
774 state.power = sets[i].power;
775
776 j = n;
777 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
778 memcpy(&sc->powernow_states[j],

--- 69 unchanged lines hidden (view full) ---

848{
849 struct pn_softc *sc;
850 uint64_t status;
851 uint64_t rate;
852 struct pcpu *pc;
853 u_int sfid, mfid, cfid;
854
855 sc = device_get_softc(dev);
856 sc->errata_a0 = FALSE;
857 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
858
859 pc = cpu_get_pcpu(dev);
860 if (pc == NULL)
861 return (ENODEV);
862
863 cpu_est_clockrate(pc->pc_cpuid, &rate);
864

--- 20 unchanged lines hidden (view full) ---

885 break;
886
887 case 0xf00:
888 sfid = PN8_STA_SFID(status);
889 mfid = PN8_STA_MFID(status);
890 cfid = PN8_STA_CFID(status);
891 sc->pn_type = PN8_TYPE;
892 sc->vid_to_volts = pn8_vid_to_volts;
893 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid >> 1];
894
895 if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
896 device_set_desc(dev, "PowerNow! K8");
897 else
898 device_set_desc(dev, "Cool`n'Quiet K8");
899 break;
900 default:
901 return (ENODEV);

--- 32 unchanged lines hidden ---