amdpm.c revision 153419
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 153419 2005-12-14 17:49:45Z jhb $"); 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.h> 46#include <machine/clock.h> 47#include <machine/resource.h> 48#include <sys/rman.h> 49 50#include <dev/pci/pcivar.h> 51#include <dev/pci/pcireg.h> 52 53#include <dev/iicbus/iiconf.h> 54#include <dev/smbus/smbconf.h> 55#include "smbus_if.h" 56 57#define AMDPM_DEBUG(x) if (amdpm_debug) (x) 58 59#ifdef DEBUG 60static int amdpm_debug = 1; 61#else 62static int amdpm_debug = 0; 63#endif 64 65#define AMDPM_VENDORID_AMD 0x1022 66#define AMDPM_DEVICEID_AMD756PM 0x740b 67#define AMDPM_DEVICEID_AMD766PM 0x7413 68#define AMDPM_DEVICEID_AMD768PM 0x7443 69#define AMDPM_DEVICEID_AMD8111PM 0x746A 70 71/* nVidia nForce chipset */ 72#define AMDPM_VENDORID_NVIDIA 0x10de 73#define AMDPM_DEVICEID_NF_SMB 0x01b4 74#define AMDPM_DEVICEID_NF2_SMB 0x0064 75#define AMDPM_DEVICEID_NF2_ULTRA_SMB 0x0084 76#define AMDPM_DEVICEID_NF3_PRO150_SMB 0x00D4 77#define AMDPM_DEVICEID_NF3_250GB_SMB 0x00E4 78#define AMDPM_DEVICEID_NF4_SMB 0x0052 79 80/* PCI Configuration space registers */ 81#define AMDPCI_PMBASE 0x58 82#define NFPCI_PMBASE 0x14 83#define NF2PCI_PMBASE_1 0x50 84#define NF2PCI_PMBASE_2 0x54 85 86#define AMDPCI_GEN_CONFIG_PM 0x41 87#define AMDPCI_PMIOEN (1<<7) 88 89#define AMDPCI_SCIINT_CONFIG_PM 0x42 90#define AMDPCI_SCISEL_IRQ11 11 91 92#define AMDPCI_REVID 0x08 93 94/* 95 * I/O registers. 96 * Base address programmed via AMDPCI_PMBASE. 97 */ 98 99#define AMDSMB_GLOBAL_STATUS (0x00) 100#define AMDSMB_GS_TO_STS (1<<5) 101#define AMDSMB_GS_HCYC_STS (1<<4) 102#define AMDSMB_GS_HST_STS (1<<3) 103#define AMDSMB_GS_PRERR_STS (1<<2) 104#define AMDSMB_GS_COL_STS (1<<1) 105#define AMDSMB_GS_ABRT_STS (1<<0) 106#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) 107 108#define AMDSMB_GLOBAL_ENABLE (0x02) 109#define AMDSMB_GE_ABORT (1<<5) 110#define AMDSMB_GE_HCYC_EN (1<<4) 111#define AMDSMB_GE_HOST_STC (1<<3) 112#define AMDSMB_GE_CYC_QUICK 0 113#define AMDSMB_GE_CYC_BYTE 1 114#define AMDSMB_GE_CYC_BDATA 2 115#define AMDSMB_GE_CYC_WDATA 3 116#define AMDSMB_GE_CYC_PROCCALL 4 117#define AMDSMB_GE_CYC_BLOCK 5 118 119#define AMDSMB_HSTADDR (0x04) 120#define AMDSMB_HSTDATA (0x06) 121#define AMDSMB_HSTCMD (0x08) 122#define AMDSMB_HSTDFIFO (0x09) 123#define AMDSMB_HSLVDATA (0x0A) 124#define AMDSMB_HSLVDA (0x0C) 125#define AMDSMB_HSLVDDR (0x0E) 126#define AMDSMB_SNPADDR (0x0F) 127 128struct amdpm_softc { 129 int base; 130 int rid; 131 struct resource *res; 132 bus_space_tag_t smbst; 133 bus_space_handle_t smbsh; 134 135 device_t smbus; 136 device_t subdev; 137}; 138 139#define AMDPM_SMBINB(amdpm,register) \ 140 (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register)) 141#define AMDPM_SMBOUTB(amdpm,register,value) \ 142 (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value)) 143#define AMDPM_SMBINW(amdpm,register) \ 144 (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register)) 145#define AMDPM_SMBOUTW(amdpm,register,value) \ 146 (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value)) 147 148static int 149amdpmsub_probe(device_t dev) 150{ 151 152 device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 153 return (0); 154} 155 156static int 157amdpm_probe(device_t dev) 158{ 159 u_long base; 160 u_int16_t vid; 161 u_int16_t did; 162 163 vid = pci_get_vendor(dev); 164 did = pci_get_device(dev); 165 if ((vid == AMDPM_VENDORID_AMD) && 166 ((did == AMDPM_DEVICEID_AMD756PM) || 167 (did == AMDPM_DEVICEID_AMD766PM) || 168 (did == AMDPM_DEVICEID_AMD768PM) || 169 (did == AMDPM_DEVICEID_AMD8111PM))) { 170 device_set_desc(dev, "AMD 756/766/768/8111 Power Management Controller"); 171 172 /* 173 * We have to do this, since the BIOS won't give us the 174 * resource info (not mine, anyway). 175 */ 176 base = pci_read_config(dev, AMDPCI_PMBASE, 4); 177 base &= 0xff00; 178 bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, 179 base+0xe0, 32); 180 return (BUS_PROBE_DEFAULT); 181 } 182 183 if (vid == AMDPM_VENDORID_NVIDIA) { 184 switch(did) { 185 case AMDPM_DEVICEID_NF_SMB: 186 device_set_desc(dev, "nForce SMBus Controller"); 187 188 /* 189 * We have to do this, since the BIOS won't give us the 190 * resource info (not mine, anyway). 191 */ 192 base = pci_read_config(dev, NFPCI_PMBASE, 4); 193 base &= 0xff00; 194 bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, 195 base, 32); 196 197 return (BUS_PROBE_DEFAULT); 198 case AMDPM_DEVICEID_NF2_SMB: 199 case AMDPM_DEVICEID_NF2_ULTRA_SMB: 200 case AMDPM_DEVICEID_NF3_PRO150_SMB: 201 case AMDPM_DEVICEID_NF3_250GB_SMB: 202 case AMDPM_DEVICEID_NF4_SMB: 203 device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 204 base = pci_read_config(dev, NF2PCI_PMBASE_1, 4); 205 base &= 0xff00; 206 bus_set_resource(dev, SYS_RES_IOPORT, NF2PCI_PMBASE_1, 207 base, 32); 208 209 return (BUS_PROBE_DEFAULT); 210 default: 211 break; 212 } 213 } 214 215 return ENXIO; 216} 217 218static int 219amdpmsub_attach(device_t dev) 220{ 221 device_t parent; 222 int base; 223 struct amdpm_softc *amdpmsub_sc = device_get_softc(dev); 224 225 parent = device_get_parent(dev); 226 227 amdpmsub_sc->rid = NF2PCI_PMBASE_2; 228 229 base = pci_read_config(parent, NF2PCI_PMBASE_2, 4); 230 base &= 0xff00; 231 bus_set_resource(parent, SYS_RES_IOPORT, NF2PCI_PMBASE_2, base, 32); 232 233 amdpmsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT, 234 &amdpmsub_sc->rid, RF_ACTIVE); 235 if (amdpmsub_sc->res == NULL) { 236 device_printf(dev, "could not map i/o space\n"); 237 return (ENXIO); 238 } 239 amdpmsub_sc->smbst = rman_get_bustag(amdpmsub_sc->res); 240 amdpmsub_sc->smbsh = rman_get_bushandle(amdpmsub_sc->res); 241 242 amdpmsub_sc->smbus = device_add_child(dev, "smbus", -1); 243 if (amdpmsub_sc->smbus == NULL) 244 return (EINVAL); 245 246 bus_generic_attach(dev); 247 248 return (0); 249} 250 251static int 252amdpm_attach(device_t dev) 253{ 254 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 255 u_char val_b; 256 257 /* Enable I/O block access */ 258 val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 259 pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 260 261 /* Allocate I/O space */ 262 if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD) 263 amdpm_sc->rid = AMDPCI_PMBASE; 264 else if (pci_get_device(dev) == AMDPM_DEVICEID_NF_SMB) 265 amdpm_sc->rid = NFPCI_PMBASE; 266 else 267 amdpm_sc->rid = NF2PCI_PMBASE_1; 268 amdpm_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 269 &amdpm_sc->rid, RF_ACTIVE); 270 271 if (amdpm_sc->res == NULL) { 272 device_printf(dev, "could not map i/o space\n"); 273 return (ENXIO); 274 } 275 276 amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res); 277 amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res); 278 279 /* Allocate a new smbus device */ 280 amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 281 if (!amdpm_sc->smbus) 282 return (EINVAL); 283 284 amdpm_sc->subdev = NULL; 285 if (pci_get_vendor(dev) == AMDPM_VENDORID_NVIDIA) 286 switch (pci_get_device(dev)) { 287 case AMDPM_DEVICEID_NF2_SMB: 288 case AMDPM_DEVICEID_NF2_ULTRA_SMB: 289 case AMDPM_DEVICEID_NF3_PRO150_SMB: 290 case AMDPM_DEVICEID_NF3_250GB_SMB: 291 case AMDPM_DEVICEID_NF4_SMB: 292 /* Trying to add secondary device as slave */ 293 amdpm_sc->subdev = device_add_child(dev, "amdpm", -1); 294 if (!amdpm_sc->subdev) return (EINVAL); 295 break; 296 default: 297 break; 298 } 299 300 bus_generic_attach(dev); 301 302 return (0); 303} 304 305static int 306amdpmsub_detach(device_t dev) 307{ 308 device_t parent; 309 struct amdpm_softc *amdpmsub_sc = device_get_softc(dev); 310 311 parent = device_get_parent(dev); 312 313 if (amdpmsub_sc->smbus) { 314 device_delete_child(dev, amdpmsub_sc->smbus); 315 amdpmsub_sc->smbus = NULL; 316 } 317 if (amdpmsub_sc->res) 318 bus_release_resource(parent, SYS_RES_IOPORT, amdpmsub_sc->rid, 319 amdpmsub_sc->res); 320 return 0; 321} 322 323static int 324amdpm_detach(device_t dev) 325{ 326 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 327 328 if (amdpm_sc->subdev) { 329 device_delete_child(dev, amdpm_sc->subdev); 330 amdpm_sc->subdev = NULL; 331 } 332 333 if (amdpm_sc->smbus) { 334 device_delete_child(dev, amdpm_sc->smbus); 335 amdpm_sc->smbus = NULL; 336 } 337 338 if (amdpm_sc->res) 339 bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, 340 amdpm_sc->res); 341 342 return (0); 343} 344 345static int 346amdpm_callback(device_t dev, int index, caddr_t *data) 347{ 348 int error = 0; 349 350 switch (index) { 351 case SMB_REQUEST_BUS: 352 case SMB_RELEASE_BUS: 353 break; 354 default: 355 error = EINVAL; 356 } 357 358 return (error); 359} 360 361static int 362amdpm_clear(struct amdpm_softc *sc) 363{ 364 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); 365 DELAY(10); 366 367 return (0); 368} 369 370#if 0 371static int 372amdpm_abort(struct amdpm_softc *sc) 373{ 374 u_short l; 375 376 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 377 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); 378 379 return (0); 380} 381#endif 382 383static int 384amdpm_idle(struct amdpm_softc *sc) 385{ 386 u_short sts; 387 388 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 389 390 AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts)); 391 392 return (~(sts & AMDSMB_GS_HST_STS)); 393} 394 395/* 396 * Poll the SMBus controller 397 */ 398static int 399amdpm_wait(struct amdpm_softc *sc) 400{ 401 int count = 10000; 402 u_short sts = 0; 403 int error; 404 405 /* Wait for command to complete (SMBus controller is idle) */ 406 while(count--) { 407 DELAY(10); 408 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 409 if (!(sts & AMDSMB_GS_HST_STS)) 410 break; 411 } 412 413 AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count)); 414 415 error = SMB_ENOERR; 416 417 if (!count) 418 error |= SMB_ETIMEOUT; 419 420 if (sts & AMDSMB_GS_ABRT_STS) 421 error |= SMB_EABORT; 422 423 if (sts & AMDSMB_GS_COL_STS) 424 error |= SMB_ENOACK; 425 426 if (sts & AMDSMB_GS_PRERR_STS) 427 error |= SMB_EBUSERR; 428 429 if (error != SMB_ENOERR) 430 amdpm_clear(sc); 431 432 return (error); 433} 434 435static int 436amdpm_quick(device_t dev, u_char slave, int how) 437{ 438 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 439 int error; 440 u_short l; 441 442 amdpm_clear(sc); 443 if (!amdpm_idle(sc)) 444 return (EBUSY); 445 446 switch (how) { 447 case SMB_QWRITE: 448 AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave)); 449 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 450 break; 451 case SMB_QREAD: 452 AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave)); 453 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 454 break; 455 default: 456 panic("%s: unknown QUICK command (%x)!", __func__, how); 457 } 458 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 459 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC); 460 461 error = amdpm_wait(sc); 462 463 AMDPM_DEBUG(printf(", error=0x%x\n", error)); 464 465 return (error); 466} 467 468static int 469amdpm_sendb(device_t dev, u_char slave, char byte) 470{ 471 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 472 int error; 473 u_short l; 474 475 amdpm_clear(sc); 476 if (!amdpm_idle(sc)) 477 return (SMB_EBUSY); 478 479 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 480 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 481 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 482 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 483 484 error = amdpm_wait(sc); 485 486 AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 487 488 return (error); 489} 490 491static int 492amdpm_recvb(device_t dev, u_char slave, char *byte) 493{ 494 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 495 int error; 496 u_short l; 497 498 amdpm_clear(sc); 499 if (!amdpm_idle(sc)) 500 return (SMB_EBUSY); 501 502 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 503 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 504 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 505 506 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 507 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 508 509 AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 510 511 return (error); 512} 513 514static int 515amdpm_writeb(device_t dev, u_char slave, char cmd, char byte) 516{ 517 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 518 int error; 519 u_short l; 520 521 amdpm_clear(sc); 522 if (!amdpm_idle(sc)) 523 return (SMB_EBUSY); 524 525 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 526 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 527 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 528 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 529 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 530 531 error = amdpm_wait(sc); 532 533 AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 534 535 return (error); 536} 537 538static int 539amdpm_readb(device_t dev, u_char slave, char cmd, char *byte) 540{ 541 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 542 int error; 543 u_short l; 544 545 amdpm_clear(sc); 546 if (!amdpm_idle(sc)) 547 return (SMB_EBUSY); 548 549 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 550 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 551 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 552 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 553 554 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 555 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 556 557 AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 558 559 return (error); 560} 561 562static int 563amdpm_writew(device_t dev, u_char slave, char cmd, short word) 564{ 565 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 566 int error; 567 u_short l; 568 569 amdpm_clear(sc); 570 if (!amdpm_idle(sc)) 571 return (SMB_EBUSY); 572 573 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 574 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word); 575 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 576 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 577 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 578 579 error = amdpm_wait(sc); 580 581 AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 582 583 return (error); 584} 585 586static int 587amdpm_readw(device_t dev, u_char slave, char cmd, short *word) 588{ 589 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 590 int error; 591 u_short l; 592 593 amdpm_clear(sc); 594 if (!amdpm_idle(sc)) 595 return (SMB_EBUSY); 596 597 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 598 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 599 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 600 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 601 602 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 603 *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 604 605 AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 606 607 return (error); 608} 609 610static int 611amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 612{ 613 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 614 u_char remain, len, i; 615 int error = SMB_ENOERR; 616 u_short l; 617 618 amdpm_clear(sc); 619 if(!amdpm_idle(sc)) 620 return (SMB_EBUSY); 621 622 remain = count; 623 while (remain) { 624 len = min(remain, 32); 625 626 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 627 628 /* 629 * Do we have to reset the internal 32-byte buffer? 630 * Can't see how to do this from the data sheet. 631 */ 632 633 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len); 634 635 /* Fill the 32-byte internal buffer */ 636 for (i=0; i<len; i++) { 637 AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]); 638 DELAY(2); 639 } 640 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 641 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 642 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 643 644 if ((error = amdpm_wait(sc)) != SMB_ENOERR) 645 goto error; 646 647 remain -= len; 648 } 649 650error: 651 AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 652 653 return (error); 654} 655 656static int 657amdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 658{ 659 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 660 u_char remain, len, i; 661 int error = SMB_ENOERR; 662 u_short l; 663 664 amdpm_clear(sc); 665 if (!amdpm_idle(sc)) 666 return (SMB_EBUSY); 667 668 remain = count; 669 while (remain) { 670 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 671 672 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 673 674 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 675 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 676 677 if ((error = amdpm_wait(sc)) != SMB_ENOERR) 678 goto error; 679 680 len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 681 682 /* Read the 32-byte internal buffer */ 683 for (i=0; i<len; i++) { 684 buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO); 685 DELAY(2); 686 } 687 688 remain -= len; 689 } 690error: 691 AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 692 693 return (error); 694} 695 696 697static device_method_t amdpm_methods[] = { 698 /* Device interface */ 699 DEVMETHOD(device_probe, amdpm_probe), 700 DEVMETHOD(device_attach, amdpm_attach), 701 DEVMETHOD(device_detach, amdpm_detach), 702 703 /* SMBus interface */ 704 DEVMETHOD(smbus_callback, amdpm_callback), 705 DEVMETHOD(smbus_quick, amdpm_quick), 706 DEVMETHOD(smbus_sendb, amdpm_sendb), 707 DEVMETHOD(smbus_recvb, amdpm_recvb), 708 DEVMETHOD(smbus_writeb, amdpm_writeb), 709 DEVMETHOD(smbus_readb, amdpm_readb), 710 DEVMETHOD(smbus_writew, amdpm_writew), 711 DEVMETHOD(smbus_readw, amdpm_readw), 712 DEVMETHOD(smbus_bwrite, amdpm_bwrite), 713 DEVMETHOD(smbus_bread, amdpm_bread), 714 715 { 0, 0 } 716}; 717 718static device_method_t amdpmsub_methods[] = { 719 /* Device interface */ 720 DEVMETHOD(device_probe, amdpmsub_probe), 721 DEVMETHOD(device_attach, amdpmsub_attach), 722 DEVMETHOD(device_detach, amdpmsub_detach), 723 724 /* SMBus interface */ 725 DEVMETHOD(smbus_callback, amdpm_callback), 726 DEVMETHOD(smbus_quick, amdpm_quick), 727 DEVMETHOD(smbus_sendb, amdpm_sendb), 728 DEVMETHOD(smbus_recvb, amdpm_recvb), 729 DEVMETHOD(smbus_writeb, amdpm_writeb), 730 DEVMETHOD(smbus_readb, amdpm_readb), 731 DEVMETHOD(smbus_writew, amdpm_writew), 732 DEVMETHOD(smbus_readw, amdpm_readw), 733 DEVMETHOD(smbus_bwrite, amdpm_bwrite), 734 DEVMETHOD(smbus_bread, amdpm_bread), 735 736 { 0, 0 } 737}; 738 739static devclass_t amdpm_devclass; 740 741static driver_t amdpm_driver = { 742 "amdpm", 743 amdpm_methods, 744 sizeof(struct amdpm_softc), 745}; 746 747static driver_t amdpmsub_driver = { 748 "amdpm", 749 amdpmsub_methods, 750 sizeof(struct amdpm_softc), 751}; 752 753DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0); 754DRIVER_MODULE(amdpm, amdpm, amdpmsub_driver, amdpm_devclass, 0, 0); 755 756MODULE_DEPEND(amdpm, pci, 1, 1, 1); 757MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 758MODULE_VERSION(amdpm, 1); 759 760