amdpm.c revision 116192
1/*- 2 * Copyright (c) 2000 Matthew C. Forman 3 * 4 * Based (heavily) on alpm.c which is: 5 * 6 * Copyright (c) 1998, 1999 Nicolas Souchu 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* 32 * Power management function/SMBus function support for the AMD 756 chip. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/pci/amdpm.c 116192 2003-06-11 06:34:30Z obrien $"); 37 38#include <sys/param.h> 39#include <sys/kernel.h> 40#include <sys/systm.h> 41#include <sys/module.h> 42#include <sys/bus.h> 43#include <sys/uio.h> 44 45#include <machine/bus_pio.h> 46#include <machine/bus_memio.h> 47#include <machine/bus.h> 48#include <machine/clock.h> 49#include <machine/resource.h> 50#include <sys/rman.h> 51 52#include <pci/pcivar.h> 53#include <pci/pcireg.h> 54 55#include <dev/iicbus/iiconf.h> 56#include <dev/smbus/smbconf.h> 57#include "smbus_if.h" 58 59#define AMDPM_DEBUG(x) if (amdpm_debug) (x) 60 61#ifdef DEBUG 62static int amdpm_debug = 1; 63#else 64static int amdpm_debug = 0; 65#endif 66 67#define AMDPM_VENDORID_AMD 0x1022 68#define AMDPM_DEVICEID_AMD756PM 0x740b 69 70/* nVidia nForce chipset */ 71#define AMDPM_VENDORID_NVIDIA 0x10de 72#define AMDPM_DEVICEID_NF_SMB 0x01b4 73 74/* PCI Configuration space registers */ 75#define AMDPCI_PMBASE 0x58 76#define NFPCI_PMBASE 0x14 77 78#define AMDPCI_GEN_CONFIG_PM 0x41 79#define AMDPCI_PMIOEN (1<<7) 80 81#define AMDPCI_SCIINT_CONFIG_PM 0x42 82#define AMDPCI_SCISEL_IRQ11 11 83 84#define AMDPCI_REVID 0x08 85 86/* 87 * I/O registers. 88 * Base address programmed via AMDPCI_PMBASE. 89 */ 90 91static u_int32_t pm_reg_offset = 0xE0; 92 93#define AMDSMB_GLOBAL_STATUS (0x00 + pm_reg_offset) 94#define AMDSMB_GS_TO_STS (1<<5) 95#define AMDSMB_GS_HCYC_STS (1<<4) 96#define AMDSMB_GS_HST_STS (1<<3) 97#define AMDSMB_GS_PRERR_STS (1<<2) 98#define AMDSMB_GS_COL_STS (1<<1) 99#define AMDSMB_GS_ABRT_STS (1<<0) 100#define AMDSMB_GS_CLEAR_STS (AMDSMB_GS_TO_STS|AMDSMB_GS_HCYC_STS|AMDSMB_GS_PRERR_STS|AMDSMB_GS_COL_STS|AMDSMB_GS_ABRT_STS) 101 102#define AMDSMB_GLOBAL_ENABLE (0x02 + pm_reg_offset) 103#define AMDSMB_GE_ABORT (1<<5) 104#define AMDSMB_GE_HCYC_EN (1<<4) 105#define AMDSMB_GE_HOST_STC (1<<3) 106#define AMDSMB_GE_CYC_QUICK 0 107#define AMDSMB_GE_CYC_BYTE 1 108#define AMDSMB_GE_CYC_BDATA 2 109#define AMDSMB_GE_CYC_WDATA 3 110#define AMDSMB_GE_CYC_PROCCALL 4 111#define AMDSMB_GE_CYC_BLOCK 5 112 113#define AMDSMB_HSTADDR (0x04 + pm_reg_offset) 114#define AMDSMB_HSTDATA (0x06 + pm_reg_offset) 115#define AMDSMB_HSTCMD (0x08 + pm_reg_offset) 116#define AMDSMB_HSTDFIFO (0x09 + pm_reg_offset) 117#define AMDSMB_HSLVDATA (0x0A + pm_reg_offset) 118#define AMDSMB_HSLVDA (0x0C + pm_reg_offset) 119#define AMDSMB_HSLVDDR (0x0E + pm_reg_offset) 120#define AMDSMB_SNPADDR (0x0F + pm_reg_offset) 121 122struct amdpm_softc { 123 int base; 124 int rid; 125 struct resource *res; 126 bus_space_tag_t smbst; 127 bus_space_handle_t smbsh; 128 129 device_t smbus; 130}; 131 132#define AMDPM_SMBINB(amdpm,register) \ 133 (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register)) 134#define AMDPM_SMBOUTB(amdpm,register,value) \ 135 (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value)) 136#define AMDPM_SMBINW(amdpm,register) \ 137 (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register)) 138#define AMDPM_SMBOUTW(amdpm,register,value) \ 139 (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value)) 140 141static int 142amdpm_probe(device_t dev) 143{ 144 u_long base; 145 146 if ((pci_get_vendor(dev) == AMDPM_VENDORID_AMD) && 147 (pci_get_device(dev) == AMDPM_DEVICEID_AMD756PM)) { 148 device_set_desc(dev, "AMD 756 Power Management Controller"); 149 150 /* 151 * We have to do this, since the BIOS won't give us the 152 * resource info (not mine, anyway). 153 */ 154 base = pci_read_config(dev, AMDPCI_PMBASE, 4); 155 base &= 0xff00; 156 bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, base, 256); 157 return (0); 158 } 159 return ENXIO; 160} 161 162static int 163amdpm_attach(device_t dev) 164{ 165 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 166 u_char val_b; 167 168 /* Enable I/O block access */ 169 val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 170 pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 171 172 /* Allocate I/O space */ 173 amdpm_sc->rid = AMDPCI_PMBASE; 174 amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE); 175 176 if (amdpm_sc->res == NULL) { 177 device_printf(dev, "could not map i/o space\n"); 178 return (ENXIO); 179 } 180 181 amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res); 182 amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res); 183 184 /* Allocate a new smbus device */ 185 amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 186 if (!amdpm_sc->smbus) 187 return (EINVAL); 188 189 bus_generic_attach(dev); 190 191 return (0); 192} 193 194static int 195amdpm_detach(device_t dev) 196{ 197 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 198 199 if (amdpm_sc->smbus) { 200 device_delete_child(dev, amdpm_sc->smbus); 201 amdpm_sc->smbus = NULL; 202 } 203 204 if (amdpm_sc->res) 205 bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, 206 amdpm_sc->res); 207 208 return (0); 209} 210 211static int 212nfpm_probe(device_t dev) 213{ 214 u_long base; 215 216 if ((pci_get_vendor(dev) == AMDPM_VENDORID_NVIDIA) && 217 (pci_get_device(dev) == AMDPM_DEVICEID_NF_SMB)) { 218 device_set_desc(dev, "nForce SMBus Controller"); 219 220 /* 221 * We have to do this, since the BIOS won't give us the 222 * resource info (not mine, anyway). 223 */ 224 base = pci_read_config(dev, NFPCI_PMBASE, 4); 225 base &= 0xff00; 226 bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, base, 256); 227 228 pm_reg_offset = 0x00; 229 230 return (0); 231 } 232 return ENXIO; 233} 234 235static int 236nfpm_attach(device_t dev) 237{ 238 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 239 u_char val_b; 240 241 /* Enable I/O block access */ 242 val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 243 pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 244 245 /* Allocate I/O space */ 246 amdpm_sc->rid = NFPCI_PMBASE; 247 amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE); 248 249 if (amdpm_sc->res == NULL) { 250 device_printf(dev, "could not map i/o space\n"); 251 return (ENXIO); 252 } 253 254 amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res); 255 amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res); 256 257 /* Allocate a new smbus device */ 258 amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 259 if (!amdpm_sc->smbus) 260 return (EINVAL); 261 262 bus_generic_attach(dev); 263 264 return (0); 265} 266 267static int 268amdpm_callback(device_t dev, int index, caddr_t *data) 269{ 270 int error = 0; 271 272 switch (index) { 273 case SMB_REQUEST_BUS: 274 case SMB_RELEASE_BUS: 275 break; 276 default: 277 error = EINVAL; 278 } 279 280 return (error); 281} 282 283static int 284amdpm_clear(struct amdpm_softc *sc) 285{ 286 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); 287 DELAY(10); 288 289 return (0); 290} 291 292#if 0 293static int 294amdpm_abort(struct amdpm_softc *sc) 295{ 296 u_short l; 297 298 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 299 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); 300 301 return (0); 302} 303#endif 304 305static int 306amdpm_idle(struct amdpm_softc *sc) 307{ 308 u_short sts; 309 310 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 311 312 AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts)); 313 314 return (~(sts & AMDSMB_GS_HST_STS)); 315} 316 317/* 318 * Poll the SMBus controller 319 */ 320static int 321amdpm_wait(struct amdpm_softc *sc) 322{ 323 int count = 10000; 324 u_short sts = 0; 325 int error; 326 327 /* Wait for command to complete (SMBus controller is idle) */ 328 while(count--) { 329 DELAY(10); 330 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 331 if (!(sts & AMDSMB_GS_HST_STS)) 332 break; 333 } 334 335 AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count)); 336 337 error = SMB_ENOERR; 338 339 if (!count) 340 error |= SMB_ETIMEOUT; 341 342 if (sts & AMDSMB_GS_ABRT_STS) 343 error |= SMB_EABORT; 344 345 if (sts & AMDSMB_GS_COL_STS) 346 error |= SMB_ENOACK; 347 348 if (sts & AMDSMB_GS_PRERR_STS) 349 error |= SMB_EBUSERR; 350 351 if (error != SMB_ENOERR) 352 amdpm_clear(sc); 353 354 return (error); 355} 356 357static int 358amdpm_quick(device_t dev, u_char slave, int how) 359{ 360 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 361 int error; 362 u_short l; 363 364 amdpm_clear(sc); 365 if (!amdpm_idle(sc)) 366 return (EBUSY); 367 368 switch (how) { 369 case SMB_QWRITE: 370 AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave)); 371 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 372 break; 373 case SMB_QREAD: 374 AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave)); 375 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 376 break; 377 default: 378 panic("%s: unknown QUICK command (%x)!", __func__, how); 379 } 380 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 381 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC); 382 383 error = amdpm_wait(sc); 384 385 AMDPM_DEBUG(printf(", error=0x%x\n", error)); 386 387 return (error); 388} 389 390static int 391amdpm_sendb(device_t dev, u_char slave, char byte) 392{ 393 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 394 int error; 395 u_short l; 396 397 amdpm_clear(sc); 398 if (!amdpm_idle(sc)) 399 return (SMB_EBUSY); 400 401 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 402 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 403 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 404 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 405 406 error = amdpm_wait(sc); 407 408 AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 409 410 return (error); 411} 412 413static int 414amdpm_recvb(device_t dev, u_char slave, char *byte) 415{ 416 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 417 int error; 418 u_short l; 419 420 amdpm_clear(sc); 421 if (!amdpm_idle(sc)) 422 return (SMB_EBUSY); 423 424 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 425 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 426 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 427 428 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 429 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 430 431 AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 432 433 return (error); 434} 435 436static int 437amdpm_writeb(device_t dev, u_char slave, char cmd, char byte) 438{ 439 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 440 int error; 441 u_short l; 442 443 amdpm_clear(sc); 444 if (!amdpm_idle(sc)) 445 return (SMB_EBUSY); 446 447 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 448 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 449 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 450 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 451 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 452 453 error = amdpm_wait(sc); 454 455 AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 456 457 return (error); 458} 459 460static int 461amdpm_readb(device_t dev, u_char slave, char cmd, char *byte) 462{ 463 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 464 int error; 465 u_short l; 466 467 amdpm_clear(sc); 468 if (!amdpm_idle(sc)) 469 return (SMB_EBUSY); 470 471 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 472 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 473 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 474 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 475 476 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 477 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 478 479 AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 480 481 return (error); 482} 483 484static int 485amdpm_writew(device_t dev, u_char slave, char cmd, short word) 486{ 487 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 488 int error; 489 u_short l; 490 491 amdpm_clear(sc); 492 if (!amdpm_idle(sc)) 493 return (SMB_EBUSY); 494 495 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 496 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word); 497 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 498 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 499 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 500 501 error = amdpm_wait(sc); 502 503 AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 504 505 return (error); 506} 507 508static int 509amdpm_readw(device_t dev, u_char slave, char cmd, short *word) 510{ 511 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 512 int error; 513 u_short l; 514 515 amdpm_clear(sc); 516 if (!amdpm_idle(sc)) 517 return (SMB_EBUSY); 518 519 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 520 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 521 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 522 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 523 524 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 525 *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 526 527 AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 528 529 return (error); 530} 531 532static int 533amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 534{ 535 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 536 u_char remain, len, i; 537 int error = SMB_ENOERR; 538 u_short l; 539 540 amdpm_clear(sc); 541 if(!amdpm_idle(sc)) 542 return (SMB_EBUSY); 543 544 remain = count; 545 while (remain) { 546 len = min(remain, 32); 547 548 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 549 550 /* 551 * Do we have to reset the internal 32-byte buffer? 552 * Can't see how to do this from the data sheet. 553 */ 554 555 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len); 556 557 /* Fill the 32-byte internal buffer */ 558 for (i=0; i<len; i++) { 559 AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]); 560 DELAY(2); 561 } 562 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 563 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 564 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 565 566 if ((error = amdpm_wait(sc)) != SMB_ENOERR) 567 goto error; 568 569 remain -= len; 570 } 571 572error: 573 AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 574 575 return (error); 576} 577 578static int 579amdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 580{ 581 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 582 u_char remain, len, i; 583 int error = SMB_ENOERR; 584 u_short l; 585 586 amdpm_clear(sc); 587 if (!amdpm_idle(sc)) 588 return (SMB_EBUSY); 589 590 remain = count; 591 while (remain) { 592 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 593 594 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 595 596 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 597 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 598 599 if ((error = amdpm_wait(sc)) != SMB_ENOERR) 600 goto error; 601 602 len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 603 604 /* Read the 32-byte internal buffer */ 605 for (i=0; i<len; i++) { 606 buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO); 607 DELAY(2); 608 } 609 610 remain -= len; 611 } 612error: 613 AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 614 615 return (error); 616} 617 618static devclass_t amdpm_devclass; 619 620static device_method_t amdpm_methods[] = { 621 /* Device interface */ 622 DEVMETHOD(device_probe, amdpm_probe), 623 DEVMETHOD(device_attach, amdpm_attach), 624 DEVMETHOD(device_detach, amdpm_detach), 625 626 /* SMBus interface */ 627 DEVMETHOD(smbus_callback, amdpm_callback), 628 DEVMETHOD(smbus_quick, amdpm_quick), 629 DEVMETHOD(smbus_sendb, amdpm_sendb), 630 DEVMETHOD(smbus_recvb, amdpm_recvb), 631 DEVMETHOD(smbus_writeb, amdpm_writeb), 632 DEVMETHOD(smbus_readb, amdpm_readb), 633 DEVMETHOD(smbus_writew, amdpm_writew), 634 DEVMETHOD(smbus_readw, amdpm_readw), 635 DEVMETHOD(smbus_bwrite, amdpm_bwrite), 636 DEVMETHOD(smbus_bread, amdpm_bread), 637 638 { 0, 0 } 639}; 640 641static driver_t amdpm_driver = { 642 "amdpm", 643 amdpm_methods, 644 sizeof(struct amdpm_softc), 645}; 646 647static devclass_t nfpm_devclass; 648 649static device_method_t nfpm_methods[] = { 650 /* Device interface */ 651 DEVMETHOD(device_probe, nfpm_probe), 652 DEVMETHOD(device_attach, nfpm_attach), 653 DEVMETHOD(device_detach, amdpm_detach), 654 655 /* SMBus interface */ 656 DEVMETHOD(smbus_callback, amdpm_callback), 657 DEVMETHOD(smbus_quick, amdpm_quick), 658 DEVMETHOD(smbus_sendb, amdpm_sendb), 659 DEVMETHOD(smbus_recvb, amdpm_recvb), 660 DEVMETHOD(smbus_writeb, amdpm_writeb), 661 DEVMETHOD(smbus_readb, amdpm_readb), 662 DEVMETHOD(smbus_writew, amdpm_writew), 663 DEVMETHOD(smbus_readw, amdpm_readw), 664 DEVMETHOD(smbus_bwrite, amdpm_bwrite), 665 DEVMETHOD(smbus_bread, amdpm_bread), 666 667 { 0, 0 } 668}; 669 670static driver_t nfpm_driver = { 671 "nfpm", 672 nfpm_methods, 673 sizeof(struct amdpm_softc), 674}; 675 676DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0); 677DRIVER_MODULE(nfpm, pci, nfpm_driver, nfpm_devclass, 0, 0); 678 679MODULE_DEPEND(amdpm, pci, 1, 1, 1); 680MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 681MODULE_VERSION(amdpm, 1); 682 683