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 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> --- 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/* 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 |
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 { --- 69 unchanged lines hidden (view full) --- 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 |
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 |
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, |
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, --- 34 unchanged lines hidden (view full) --- 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; |
230 u_int errata; |
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 --- 49 unchanged lines hidden (view full) --- 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 |
296 if (sc->errata & A0_ERRATA) |
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 |
309 if (sc->errata & A0_ERRATA) |
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 |
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; |
346 u_int val; 347 |
348 rv = pn8_read_pending_wait(&status); 349 if (rv) 350 return (rv); 351 |
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); |
364 rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status); 365 if (rv) { 366 sc->errata |= PENDING_STUCK; 367 return (rv); 368 } |
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 */ |
378 rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status); 379 if (rv) { 380 sc->errata |= PENDING_STUCK; 381 return (rv); 382 } |
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) { |
389 u_int vco_fid, vco_cfid, fid_delta; |
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; |
396 if (fid > cfid) { |
397 if (cfid > 7) 398 val = cfid + fid_delta; |
399 else |
400 val = FID_TO_VCO_FID(cfid) + fid_delta; |
401 } else |
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 } |
410 cfid = PN8_STA_CFID(status); 411 COUNT_OFF_IRT(sc->irt); 412 413 vco_cfid = FID_TO_VCO_FID(cfid); 414 } 415 |
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 } |
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) { |
429 rv = pn8_write_fidvid(cfid, vid, 1ULL, &status); |
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) |
436 rv = ENXIO; |
437 |
438 return (rv); |
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 |
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; --- 16 unchanged lines hidden (view full) --- 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); |
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; --- 71 unchanged lines hidden (view full) --- 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; |
577 if ((sc->errata & A0_ERRATA) && |
578 (pn7_fid_to_mult[state.fid] % 10) == 5) 579 continue; 580 break; 581 case PN8_TYPE: |
582 state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb; |
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 /* |
599 * Fix powernow_max_states, if errata a0 give us less states |
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; --- 39 unchanged lines hidden (view full) --- 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) |
655 sc->errata |= A0_ERRATA; |
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; --- 135 unchanged lines hidden (view full) --- 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) |
807 sc->errata |= A0_ERRATA; |
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); |
817 if ((sc->errata & A0_ERRATA) && |
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); |
825 state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb; |
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], --- 69 unchanged lines hidden (view full) --- 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); |
911 sc->errata = 0; |
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 --- 20 unchanged lines hidden (view full) --- 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; |
948 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid]; |
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); --- 32 unchanged lines hidden --- |