powernow.c revision 144194
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 144194 2005-03-27 21:44:21Z njl $"); 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/clock.h> 48#include <machine/vmparam.h> 49#include <sys/rman.h> 50 51#include <vm/vm.h> 52#include <vm/pmap.h> 53 54#include "cpufreq_if.h" 55 56#define PN7_TYPE 0 57#define PN8_TYPE 1 58 59/* Legacy configuration via BIOS table PSB. */ 60#define PSB_START 0 61#define PSB_STEP 0x10 62#define PSB_SIG "AMDK7PNOW!" 63#define PSB_LEN 10 64#define PSB_OFF 0 65 66struct psb_header { 67 char signature[10]; 68 uint8_t version; 69 uint8_t flags; 70 uint16_t settlingtime; 71 uint8_t res1; 72 uint8_t numpst; 73} __packed; 74 75struct pst_header { 76 uint32_t cpuid; 77 uint8_t fsb; 78 uint8_t maxfid; 79 uint8_t startvid; 80 uint8_t numpstates; 81} __packed; 82 83/* 84 * MSRs and bits used by Powernow technology 85 */ 86#define MSR_AMDK7_FIDVID_CTL 0xc0010041 87#define MSR_AMDK7_FIDVID_STATUS 0xc0010042 88 89/* Bitfields used by K7 */ 90 91#define PN7_CTR_FID(x) ((x) & 0x1f) 92#define PN7_CTR_VID(x) (((x) & 0x1f) << 8) 93#define PN7_CTR_FIDC 0x00010000 94#define PN7_CTR_VIDC 0x00020000 95#define PN7_CTR_FIDCHRATIO 0x00100000 96#define PN7_CTR_SGTC(x) (((uint64_t)(x) & 0x000fffff) << 32) 97 98#define PN7_STA_CFID(x) ((x) & 0x1f) 99#define PN7_STA_SFID(x) (((x) >> 8) & 0x1f) 100#define PN7_STA_MFID(x) (((x) >> 16) & 0x1f) 101#define PN7_STA_CVID(x) (((x) >> 32) & 0x1f) 102#define PN7_STA_SVID(x) (((x) >> 40) & 0x1f) 103#define PN7_STA_MVID(x) (((x) >> 48) & 0x1f) 104 105/* ACPI ctr_val status register to powernow k7 configuration */ 106#define ACPI_PN7_CTRL_TO_FID(x) ((x) & 0x1f) 107#define ACPI_PN7_CTRL_TO_VID(x) (((x) >> 5) & 0x1f) 108#define ACPI_PN7_CTRL_TO_SGTC(x) (((x) >> 10) & 0xffff) 109 110/* Bitfields used by K8 */ 111 112#define PN8_CTR_FID(x) ((x) & 0x3f) 113#define PN8_CTR_VID(x) (((x) & 0x1f) << 8) 114#define PN8_CTR_PENDING(x) (((x) & 1) << 32) 115 116#define PN8_STA_CFID(x) ((x) & 0x3f) 117#define PN8_STA_SFID(x) (((x) >> 8) & 0x3f) 118#define PN8_STA_MFID(x) (((x) >> 16) & 0x3f) 119#define PN8_STA_PENDING(x) (((x) >> 31) & 0x01) 120#define PN8_STA_CVID(x) (((x) >> 32) & 0x1f) 121#define PN8_STA_SVID(x) (((x) >> 40) & 0x1f) 122#define PN8_STA_MVID(x) (((x) >> 48) & 0x1f) 123 124/* Reserved1 to powernow k8 configuration */ 125#define PN8_PSB_TO_RVO(x) ((x) & 0x03) 126#define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03) 127#define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03) 128#define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03) 129 130/* ACPI ctr_val status register to powernow k8 configuration */ 131#define ACPI_PN8_CTRL_TO_FID(x) ((x) & 0x3f) 132#define ACPI_PN8_CTRL_TO_VID(x) (((x) >> 6) & 0x1f) 133#define ACPI_PN8_CTRL_TO_VST(x) (((x) >> 11) & 0x1f) 134#define ACPI_PN8_CTRL_TO_MVS(x) (((x) >> 18) & 0x03) 135#define ACPI_PN8_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f) 136#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03) 137#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03) 138 139 140#define WRITE_FIDVID(fid, vid, ctrl) \ 141 wrmsr(MSR_AMDK7_FIDVID_CTL, \ 142 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) 143 144#define READ_PENDING_WAIT(status) \ 145 do { \ 146 (status) = rdmsr(MSR_AMDK7_FIDVID_STATUS); \ 147 } while (PN8_STA_PENDING(status)) 148 149#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt))) 150#define COUNT_OFF_VST(vst) DELAY(20 * (vst)) 151 152#define FID_TO_VCO_FID(fid) \ 153 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) 154 155/* 156 * Divide each value by 10 to get the processor multiplier. 157 * Some of those tables are the same as the Linux powernow-k7 158 * implementation by Dave Jones. 159 */ 160static int pn7_fid_to_mult[32] = { 161 110, 115, 120, 125, 50, 55, 60, 65, 162 70, 75, 80, 85, 90, 95, 100, 105, 163 30, 190, 40, 200, 130, 135, 140, 210, 164 150, 225, 160, 165, 170, 180, 0, 0, 165}; 166 167 168static int pn8_fid_to_mult[32] = { 169 40, 50, 60, 70, 80, 90, 100, 110, 170 120, 130, 140, 150, 160, 170, 180, 190, 171 220, 230, 240, 250, 260, 270, 280, 290, 172 300, 310, 320, 330, 340, 350, 173}; 174 175/* 176 * Units are in mV. 177 */ 178/* Mobile VRM (K7) */ 179static int pn7_mobile_vid_to_volts[] = { 180 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 181 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 182 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 183 1075, 1050, 1025, 1000, 975, 950, 925, 0, 184}; 185/* Desktop VRM (K7) */ 186static int pn7_desktop_vid_to_volts[] = { 187 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 188 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 189 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 190 1075, 1050, 1025, 1000, 975, 950, 925, 0, 191}; 192/* Desktop and Mobile VRM (K8) */ 193static int pn8_vid_to_volts[] = { 194 1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375, 195 1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175, 196 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, 197 950, 925, 900, 875, 850, 825, 800, 0, 198}; 199 200#define POWERNOW_MAX_STATES 16 201 202struct powernow_state { 203 int freq; 204 int power; 205 int fid; 206 int vid; 207}; 208 209struct pn_softc { 210 device_t dev; 211 int pn_type; 212 struct powernow_state powernow_states[POWERNOW_MAX_STATES]; 213 u_int fsb; 214 u_int sgtc; 215 u_int vst; 216 u_int mvs; 217 u_int pll; 218 u_int rvo; 219 u_int irt; 220 int low; 221 int powernow_max_states; 222 u_int powernow_state; 223 int errata_a0; 224 int *vid_to_volts; 225}; 226 227/* 228 * Offsets in struct cf_setting array for private values given by 229 * acpi_perf driver. 230 */ 231#define PX_SPEC_CONTROL 0 232#define PX_SPEC_STATUS 1 233 234static void pn_identify(driver_t *driver, device_t parent); 235static int pn_probe(device_t dev); 236static int pn_attach(device_t dev); 237static int pn_detach(device_t dev); 238static int pn_set(device_t dev, const struct cf_setting *cf); 239static int pn_get(device_t dev, struct cf_setting *cf); 240static int pn_settings(device_t dev, struct cf_setting *sets, 241 int *count); 242static int pn_type(device_t dev, int *type); 243 244static device_method_t pn_methods[] = { 245 /* Device interface */ 246 DEVMETHOD(device_identify, pn_identify), 247 DEVMETHOD(device_probe, pn_probe), 248 DEVMETHOD(device_attach, pn_attach), 249 DEVMETHOD(device_detach, pn_detach), 250 251 /* cpufreq interface */ 252 DEVMETHOD(cpufreq_drv_set, pn_set), 253 DEVMETHOD(cpufreq_drv_get, pn_get), 254 DEVMETHOD(cpufreq_drv_settings, pn_settings), 255 DEVMETHOD(cpufreq_drv_type, pn_type), 256 257 {0, 0} 258}; 259 260static devclass_t pn_devclass; 261static driver_t pn_driver = { 262 "powernow", 263 pn_methods, 264 sizeof(struct pn_softc), 265}; 266 267DRIVER_MODULE(powernow, cpu, pn_driver, pn_devclass, 0, 0); 268 269static int 270pn7_setfidvid(struct pn_softc *sc, int fid, int vid) 271{ 272 int cfid, cvid; 273 uint64_t status, ctl; 274 275 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 276 cfid = PN7_STA_CFID(status); 277 cvid = PN7_STA_CVID(status); 278 279 /* We're already at the requested level. */ 280 if (fid == cfid && vid == cvid) 281 return (0); 282 283 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO; 284 285 ctl |= PN7_CTR_FID(fid); 286 ctl |= PN7_CTR_VID(vid); 287 ctl |= PN7_CTR_SGTC(sc->sgtc); 288 289 if (sc->errata_a0) 290 disable_intr(); 291 292 if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) { 293 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 294 if (vid != cvid) 295 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 296 } else { 297 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 298 if (fid != cfid) 299 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 300 } 301 302 if (sc->errata_a0) 303 enable_intr(); 304 305 return (0); 306} 307 308static int 309pn8_setfidvid(struct pn_softc *sc, int fid, int vid) 310{ 311 uint64_t status; 312 int cfid, cvid; 313 int rvo; 314 u_int val; 315 316 READ_PENDING_WAIT(status); 317 cfid = PN8_STA_CFID(status); 318 cvid = PN8_STA_CVID(status); 319 320 if (fid == cfid && vid == cvid) 321 return (0); 322 323 /* 324 * Phase 1: Raise core voltage to requested VID if frequency is 325 * going up. 326 */ 327 while (cvid > vid) { 328 val = cvid - (1 << sc->mvs); 329 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL); 330 READ_PENDING_WAIT(status); 331 cvid = PN8_STA_CVID(status); 332 COUNT_OFF_VST(sc->vst); 333 } 334 335 /* ... then raise to voltage + RVO (if required) */ 336 for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) { 337 /* XXX It's not clear from spec if we have to do that 338 * in 0.25 step or in MVS. Therefore do it as it's done 339 * under Linux */ 340 WRITE_FIDVID(cfid, cvid - 1, 1ULL); 341 READ_PENDING_WAIT(status); 342 cvid = PN8_STA_CVID(status); 343 COUNT_OFF_VST(sc->vst); 344 } 345 346 /* Phase 2: change to requested core frequency */ 347 if (cfid != fid) { 348 u_int vco_fid, vco_cfid; 349 350 vco_fid = FID_TO_VCO_FID(fid); 351 vco_cfid = FID_TO_VCO_FID(cfid); 352 353 while (abs(vco_fid - vco_cfid) > 2) { 354 if (fid > cfid) { 355 if (cfid > 6) 356 val = cfid + 2; 357 else 358 val = FID_TO_VCO_FID(cfid) + 2; 359 } else 360 val = cfid - 2; 361 WRITE_FIDVID(val, cvid, sc->pll * (uint64_t) sc->fsb); 362 READ_PENDING_WAIT(status); 363 cfid = PN8_STA_CFID(status); 364 COUNT_OFF_IRT(sc->irt); 365 366 vco_cfid = FID_TO_VCO_FID(cfid); 367 } 368 369 WRITE_FIDVID(fid, cvid, sc->pll * (uint64_t) sc->fsb); 370 READ_PENDING_WAIT(status); 371 cfid = PN8_STA_CFID(status); 372 COUNT_OFF_IRT(sc->irt); 373 } 374 375 /* Phase 3: change to requested voltage */ 376 if (cvid != vid) { 377 WRITE_FIDVID(cfid, vid, 1ULL); 378 READ_PENDING_WAIT(status); 379 cvid = PN8_STA_CVID(status); 380 COUNT_OFF_VST(sc->vst); 381 } 382 383 /* Check if transition failed. */ 384 if (cfid != fid || cvid != vid) 385 return (ENXIO); 386 387 return (0); 388} 389 390static int 391pn_set(device_t dev, const struct cf_setting *cf) 392{ 393 struct pn_softc *sc; 394 int fid, vid; 395 int i; 396 int rv; 397 398 if (cf == NULL) 399 return (EINVAL); 400 sc = device_get_softc(dev); 401 402 for (i = 0; i < sc->powernow_max_states; ++i) 403 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq)) 404 break; 405 406 fid = sc->powernow_states[i].fid; 407 vid = sc->powernow_states[i].vid; 408 409 rv = ENODEV; 410 411 switch (sc->pn_type) { 412 case PN7_TYPE: 413 rv = pn7_setfidvid(sc, fid, vid); 414 break; 415 case PN8_TYPE: 416 rv = pn8_setfidvid(sc, fid, vid); 417 break; 418 } 419 420 return (rv); 421} 422 423static int 424pn_get(device_t dev, struct cf_setting *cf) 425{ 426 struct pn_softc *sc; 427 u_int cfid = 0, cvid = 0; 428 int i; 429 uint64_t status; 430 431 if (cf == NULL) 432 return (EINVAL); 433 sc = device_get_softc(dev); 434 435 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 436 437 switch (sc->pn_type) { 438 case PN7_TYPE: 439 cfid = PN7_STA_CFID(status); 440 cvid = PN7_STA_CVID(status); 441 break; 442 case PN8_TYPE: 443 cfid = PN8_STA_CFID(status); 444 cvid = PN8_STA_CVID(status); 445 break; 446 } 447 for (i = 0; i < sc->powernow_max_states; ++i) 448 if (cfid == sc->powernow_states[i].fid && 449 cvid == sc->powernow_states[i].vid) 450 break; 451 452 if (i < sc->powernow_max_states) { 453 cf->freq = sc->powernow_states[i].freq / 1000; 454 cf->power = sc->powernow_states[i].power; 455 cf->lat = 200; 456 cf->volts = sc->vid_to_volts[cvid]; 457 cf->dev = dev; 458 } else { 459 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 460 cf->dev = NULL; 461 } 462 463 return (0); 464} 465 466static int 467pn_settings(device_t dev, struct cf_setting *sets, int *count) 468{ 469 struct pn_softc *sc; 470 int i; 471 472 if (sets == NULL|| count == NULL) 473 return (EINVAL); 474 sc = device_get_softc(dev); 475 if (*count < sc->powernow_max_states) 476 return (E2BIG); 477 for (i = 0; i < sc->powernow_max_states; ++i) { 478 sets[i].freq = sc->powernow_states[i].freq / 1000; 479 sets[i].power = sc->powernow_states[i].power; 480 sets[i].lat = 200; 481 sets[i].volts = sc->vid_to_volts[sc->powernow_states[i].vid]; 482 sets[i].dev = dev; 483 } 484 *count = sc->powernow_max_states; 485 486 return (0); 487} 488 489static int 490pn_type(device_t dev, int *type) 491{ 492 if (type == NULL) 493 return (EINVAL); 494 495 *type = CPUFREQ_TYPE_ABSOLUTE; 496 497 return (0); 498} 499 500/* 501 * Given a set of pair of fid/vid, and number of performance states, 502 * compute powernow_states via an insertion sort. 503 */ 504static int 505decode_pst(struct pn_softc *sc, uint8_t *p, int npstates) 506{ 507 int i, j, n; 508 struct powernow_state state; 509 510 for (i = 0; i < POWERNOW_MAX_STATES; ++i) 511 sc->powernow_states[i].freq = CPUFREQ_VAL_UNKNOWN; 512 513 for (n = 0, i = 0; i < npstates; ++i) { 514 state.fid = *p++; 515 state.vid = *p++; 516 state.power = CPUFREQ_VAL_UNKNOWN; 517 518 switch (sc->pn_type) { 519 case PN7_TYPE: 520 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb; 521 if (sc->errata_a0 && 522 (pn7_fid_to_mult[state.fid] % 10) == 5) 523 continue; 524 break; 525 case PN8_TYPE: 526 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] * 527 sc->fsb; 528 break; 529 } 530 531 j = n; 532 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) { 533 memcpy(&sc->powernow_states[j], 534 &sc->powernow_states[j - 1], 535 sizeof(struct powernow_state)); 536 --j; 537 } 538 memcpy(&sc->powernow_states[j], &state, 539 sizeof(struct powernow_state)); 540 ++n; 541 } 542 543 /* 544 * Fix powernow_max_states, if errata_a0 give us less states 545 * than expected. 546 */ 547 sc->powernow_max_states = n; 548 549 if (bootverbose) 550 for (i = 0; i < sc->powernow_max_states; ++i) { 551 int fid = sc->powernow_states[i].fid; 552 int vid = sc->powernow_states[i].vid; 553 554 printf("powernow: %2i %8dkHz FID %02x VID %02x\n", 555 i, 556 sc->powernow_states[i].freq, 557 fid, 558 vid); 559 } 560 561 return (0); 562} 563 564static int 565cpuid_is_k7(u_int cpuid) 566{ 567 568 switch (cpuid) { 569 case 0x760: 570 case 0x761: 571 case 0x762: 572 case 0x770: 573 case 0x771: 574 case 0x780: 575 case 0x781: 576 case 0x7a0: 577 return (TRUE); 578 } 579 return (FALSE); 580} 581 582static int 583pn_decode_pst(device_t dev) 584{ 585 int maxpst; 586 struct pn_softc *sc; 587 u_int cpuid, maxfid, startvid; 588 u_long sig; 589 struct psb_header *psb; 590 uint8_t *p; 591 u_int regs[4]; 592 uint64_t status; 593 594 sc = device_get_softc(dev); 595 596 do_cpuid(0x80000001, regs); 597 cpuid = regs[0]; 598 599 if ((cpuid & 0xfff) == 0x760) 600 sc->errata_a0 = TRUE; 601 602 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 603 604 switch (sc->pn_type) { 605 case PN7_TYPE: 606 maxfid = PN7_STA_MFID(status); 607 startvid = PN7_STA_SVID(status); 608 break; 609 case PN8_TYPE: 610 maxfid = PN8_STA_MFID(status); 611 /* 612 * we should actually use a variable named 'maxvid' if K8, 613 * but why introducing a new variable for that? 614 */ 615 startvid = PN8_STA_MVID(status); 616 break; 617 default: 618 return (ENODEV); 619 } 620 621 if (bootverbose) { 622 device_printf(dev, "STATUS: 0x%jx\n", status); 623 device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid); 624 device_printf(dev, "STATUS: %s: 0x%02x\n", 625 sc->pn_type == PN7_TYPE ? "startvid" : "maxvid", 626 startvid); 627 } 628 629 sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF); 630 if (sig) { 631 struct pst_header *pst; 632 633 psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig); 634 635 switch (psb->version) { 636 default: 637 return (ENODEV); 638 case 0x14: 639 if (sc->pn_type != PN8_TYPE || psb->numpst != 1) 640 return (EINVAL); 641 sc->vst = psb->settlingtime; 642 sc->rvo = PN8_PSB_TO_RVO(psb->res1), 643 sc->irt = PN8_PSB_TO_IRT(psb->res1), 644 sc->mvs = PN8_PSB_TO_MVS(psb->res1), 645 sc->low = PN8_PSB_TO_BATT(psb->res1); 646 if (bootverbose) { 647 device_printf(dev, "PSB: VST: %d\n", 648 psb->settlingtime); 649 device_printf(dev, "PSB: RVO %x IRT %d " 650 "MVS %d BATT %d\n", 651 sc->rvo, 652 sc->irt, 653 sc->mvs, 654 sc->low); 655 } 656 break; 657 case 0x12: 658 if (sc->pn_type != PN7_TYPE) 659 return (EINVAL); 660 sc->sgtc = psb->settlingtime * sc->fsb; 661 if (sc->sgtc < 100 * sc->fsb) 662 sc->sgtc = 100 * sc->fsb; 663 break; 664 } 665 666 p = ((uint8_t *) psb) + sizeof(struct psb_header); 667 pst = (struct pst_header*) p; 668 669 maxpst = 200; 670 671 do { 672 struct pst_header *pst = (struct pst_header*) p; 673 674 if (cpuid == pst->cpuid && 675 maxfid == pst->maxfid && 676 startvid == pst->startvid) { 677 sc->powernow_max_states = pst->numpstates; 678 switch (sc->pn_type) { 679 case PN7_TYPE: 680 if (abs(sc->fsb - pst->fsb) > 5) 681 continue; 682 break; 683 case PN8_TYPE: 684 break; 685 } 686 return (decode_pst(sc, 687 p + sizeof(struct pst_header), 688 sc->powernow_max_states)); 689 } 690 691 p += sizeof(struct pst_header) + (2 * pst->numpstates); 692 } while (cpuid_is_k7(pst->cpuid) && maxpst--); 693 694 device_printf(dev, "no match for extended cpuid %.3x\n", cpuid); 695 } 696 697 return (ENODEV); 698} 699 700/* 701 * TODO: this should be done in sys/ARCH/ARCH/identcpu.c 702 */ 703static int 704cpu_is_powernow_capable(void) 705{ 706 u_int regs[4]; 707 708 if (strcmp(cpu_vendor, "AuthenticAMD") != 0 || 709 cpu_exthigh < 0x80000007) 710 return (FALSE); 711 712 do_cpuid(0x80000007, regs); 713 return (regs[3] & 0x6); 714} 715 716static int 717pn_decode_acpi(device_t dev, device_t perf_dev) 718{ 719 int i, j, n; 720 uint64_t status; 721 uint32_t ctrl; 722 u_int cpuid; 723 u_int regs[4]; 724 struct pn_softc *sc; 725 struct powernow_state state; 726 struct cf_setting sets[POWERNOW_MAX_STATES]; 727 int count = POWERNOW_MAX_STATES; 728 int type; 729 int rv; 730 731 if (perf_dev == NULL) 732 return (ENXIO); 733 734 rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count); 735 if (rv) 736 return (ENXIO); 737 rv = CPUFREQ_DRV_TYPE(perf_dev, &type); 738 if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0) 739 return (ENXIO); 740 741 sc = device_get_softc(dev); 742 743 do_cpuid(0x80000001, regs); 744 cpuid = regs[0]; 745 if ((cpuid & 0xfff) == 0x760) 746 sc->errata_a0 = TRUE; 747 748 ctrl = 0; 749 sc->sgtc = 0; 750 for (n = 0, i = 0; i < count; ++i) { 751 ctrl = sets[i].spec[PX_SPEC_CONTROL]; 752 switch (sc->pn_type) { 753 case PN7_TYPE: 754 state.fid = ACPI_PN7_CTRL_TO_FID(ctrl); 755 state.vid = ACPI_PN7_CTRL_TO_VID(ctrl); 756 if (sc->errata_a0 && 757 (pn7_fid_to_mult[state.fid] % 10) == 5) 758 continue; 759 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb; 760 break; 761 case PN8_TYPE: 762 state.fid = ACPI_PN8_CTRL_TO_FID(ctrl); 763 state.vid = ACPI_PN8_CTRL_TO_VID(ctrl); 764 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] * 765 sc->fsb; 766 break; 767 } 768 769 state.power = sets[i].power; 770 771 j = n; 772 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) { 773 memcpy(&sc->powernow_states[j], 774 &sc->powernow_states[j - 1], 775 sizeof(struct powernow_state)); 776 --j; 777 } 778 memcpy(&sc->powernow_states[j], &state, 779 sizeof(struct powernow_state)); 780 ++n; 781 } 782 783 sc->powernow_max_states = n; 784 state = sc->powernow_states[0]; 785 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 786 787 switch (sc->pn_type) { 788 case PN7_TYPE: 789 sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl); 790 /* 791 * XXX Some bios forget the max frequency! 792 * This maybe indicates we have the wrong tables. Therefore, 793 * don't implement a quirk, but fallback to BIOS legacy 794 * tables instead. 795 */ 796 if (PN7_STA_MFID(status) != state.fid) { 797 device_printf(dev, "ACPI MAX frequency not found\n"); 798 return (EINVAL); 799 } 800 break; 801 case PN8_TYPE: 802 sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl), 803 sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl), 804 sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl), 805 sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl), 806 sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl); 807 sc->low = 0; /* XXX */ 808 809 /* 810 * powernow k8 supports only one low frequency. 811 */ 812 if (sc->powernow_max_states >= 2 && 813 (sc->powernow_states[sc->powernow_max_states - 2].fid < 8)) 814 return (EINVAL); 815 break; 816 } 817 818 return (0); 819} 820 821static void 822pn_identify(driver_t *driver, device_t parent) 823{ 824 device_t child; 825 826 if (cpu_is_powernow_capable() == 0) 827 return; 828 switch (cpu_id & 0xf00) { 829 case 0x600: 830 case 0xf00: 831 break; 832 default: 833 return; 834 } 835 if (device_find_child(parent, "powernow", -1) != NULL) 836 return; 837 if ((child = BUS_ADD_CHILD(parent, 0, "powernow", -1)) == NULL) 838 device_printf(parent, "powernow: add child failed\n"); 839} 840 841static int 842pn_probe(device_t dev) 843{ 844 struct pn_softc *sc; 845 uint64_t status; 846 uint64_t rate; 847 struct pcpu *pc; 848 u_int sfid, mfid, cfid; 849 850 sc = device_get_softc(dev); 851 sc->errata_a0 = FALSE; 852 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 853 854 pc = cpu_get_pcpu(dev); 855 if (pc == NULL) 856 return (ENODEV); 857 858 cpu_est_clockrate(pc->pc_cpuid, &rate); 859 860 switch (cpu_id & 0xf00) { 861 case 0x600: 862 sfid = PN7_STA_SFID(status); 863 mfid = PN7_STA_MFID(status); 864 cfid = PN7_STA_CFID(status); 865 sc->pn_type = PN7_TYPE; 866 sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid]; 867 868 /* 869 * If start FID is different to max FID, then it is a 870 * mobile processor. If not, it is a low powered desktop 871 * processor. 872 */ 873 if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) { 874 sc->vid_to_volts = pn7_mobile_vid_to_volts; 875 device_set_desc(dev, "PowerNow! K7"); 876 } else { 877 sc->vid_to_volts = pn7_desktop_vid_to_volts; 878 device_set_desc(dev, "Cool`n'Quiet K7"); 879 } 880 break; 881 882 case 0xf00: 883 sfid = PN8_STA_SFID(status); 884 mfid = PN8_STA_MFID(status); 885 cfid = PN8_STA_CFID(status); 886 sc->pn_type = PN8_TYPE; 887 sc->vid_to_volts = pn8_vid_to_volts; 888 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid >> 1]; 889 890 if (PN8_STA_SFID(status) != PN8_STA_MFID(status)) 891 device_set_desc(dev, "PowerNow! K8"); 892 else 893 device_set_desc(dev, "Cool`n'Quiet K8"); 894 break; 895 default: 896 return (ENODEV); 897 } 898 899 return (0); 900} 901 902static int 903pn_attach(device_t dev) 904{ 905 int rv; 906 device_t child; 907 908 child = device_find_child(device_get_parent(dev), "acpi_perf", -1); 909 if (child) { 910 rv = pn_decode_acpi(dev, child); 911 if (rv) 912 rv = pn_decode_pst(dev); 913 } else 914 rv = pn_decode_pst(dev); 915 916 if (rv != 0) 917 return (ENXIO); 918 cpufreq_register(dev); 919 return (0); 920} 921 922static int 923pn_detach(device_t dev) 924{ 925 926 cpufreq_unregister(dev); 927 return (0); 928} 929