powernow.c revision 158651
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 $"); 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/* 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 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, 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; 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 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 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; 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); 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; 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; 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) 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; 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) 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], 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); 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 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; 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); 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} 934