1 /*- 2 * Copyright (c) 2005 Ruslan Ermilov 3 * All rights reserved. 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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <sys/param.h> 29 #include <sys/bus.h> 30 #include <sys/kernel.h> 31 #include <sys/lock.h> 32 #include <sys/module.h> 33 #include <sys/mutex.h> 34 #include <sys/systm.h> 35 36 #include <machine/bus.h> 37 #include <machine/resource.h> 38 #include <sys/rman.h> 39 40 #include <dev/pci/pcivar.h> 41 #include <dev/pci/pcireg.h> 42 43 #include <dev/smbus/smbconf.h> 44 #include "smbus_if.h" 45 46 #define AMDSMB_DEBUG(x) if (amdsmb_debug) (x) 47 48 #ifdef DEBUG 49 static int amdsmb_debug = 1; 50 #else 51 static int amdsmb_debug = 0; 52 #endif 53 54 #define AMDSMB_VENDORID_AMD 0x1022 55 #define AMDSMB_DEVICEID_AMD8111_SMB2 0x746a 56 57 /* 58 * ACPI 3.0, Chapter 12, Embedded Controller Interface. 59 */ 60 #define EC_DATA 0x00 /* data register */ 61 #define EC_SC 0x04 /* status of controller */ 62 #define EC_CMD 0x04 /* command register */ 63 64 #define EC_SC_IBF 0x02 /* data ready for embedded controller */ 65 #define EC_SC_OBF 0x01 /* data ready for host */ 66 #define EC_CMD_WR 0x81 /* write EC */ 67 #define EC_CMD_RD 0x80 /* read EC */ 68 69 /* 70 * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 71 */ 72 #define SMB_PRTCL 0x00 /* protocol */ 73 #define SMB_STS 0x01 /* status */ 74 #define SMB_ADDR 0x02 /* address */ 75 #define SMB_CMD 0x03 /* command */ 76 #define SMB_DATA 0x04 /* 32 data registers */ 77 #define SMB_BCNT 0x24 /* number of data bytes */ 78 #define SMB_ALRM_A 0x25 /* alarm address */ 79 #define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 80 81 #define SMB_STS_DONE 0x80 82 #define SMB_STS_ALRM 0x40 83 #define SMB_STS_RES 0x20 84 #define SMB_STS_STATUS 0x1f 85 #define SMB_STS_OK 0x00 /* OK */ 86 #define SMB_STS_UF 0x07 /* Unknown Failure */ 87 #define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 88 #define SMB_STS_DED 0x11 /* Device Error Detected */ 89 #define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 90 #define SMB_STS_UE 0x13 /* Unknown Error */ 91 #define SMB_STS_DAD 0x17 /* Device Access Denied */ 92 #define SMB_STS_T 0x18 /* Timeout */ 93 #define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 94 #define SMB_STS_B 0x1a /* Busy */ 95 #define SMB_STS_PEC 0x1f /* PEC (CRC-8) Error */ 96 97 #define SMB_PRTCL_WRITE 0x00 98 #define SMB_PRTCL_READ 0x01 99 #define SMB_PRTCL_QUICK 0x02 100 #define SMB_PRTCL_BYTE 0x04 101 #define SMB_PRTCL_BYTE_DATA 0x06 102 #define SMB_PRTCL_WORD_DATA 0x08 103 #define SMB_PRTCL_BLOCK_DATA 0x0a 104 #define SMB_PRTCL_PROC_CALL 0x0c 105 #define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 106 #define SMB_PRTCL_PEC 0x80 107 108 struct amdsmb_softc { 109 int rid; 110 struct resource *res; 111 device_t smbus; 112 struct mtx lock; 113 }; 114 115 #define AMDSMB_LOCK(amdsmb) mtx_lock(&(amdsmb)->lock) 116 #define AMDSMB_UNLOCK(amdsmb) mtx_unlock(&(amdsmb)->lock) 117 #define AMDSMB_LOCK_ASSERT(amdsmb) mtx_assert(&(amdsmb)->lock, MA_OWNED) 118 119 #define AMDSMB_ECINB(amdsmb, register) \ 120 (bus_read_1(amdsmb->res, register)) 121 #define AMDSMB_ECOUTB(amdsmb, register, value) \ 122 (bus_write_1(amdsmb->res, register, value)) 123 124 static int amdsmb_detach(device_t dev); 125 126 struct pci_device_table amdsmb_devs[] = { 127 { PCI_DEV(AMDSMB_VENDORID_AMD, AMDSMB_DEVICEID_AMD8111_SMB2), 128 PCI_DESCR("AMD-8111 SMBus 2.0 Controller") } 129 }; 130 131 static int 132 amdsmb_probe(device_t dev) 133 { 134 const struct pci_device_table *tbl; 135 136 tbl = PCI_MATCH(dev, amdsmb_devs); 137 if (tbl == NULL) 138 return (ENXIO); 139 device_set_desc(dev, tbl->descr); 140 141 return (BUS_PROBE_DEFAULT); 142 } 143 144 static int 145 amdsmb_attach(device_t dev) 146 { 147 struct amdsmb_softc *amdsmb_sc = device_get_softc(dev); 148 149 /* Allocate I/O space */ 150 amdsmb_sc->rid = PCIR_BAR(0); 151 152 amdsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 153 &amdsmb_sc->rid, RF_ACTIVE); 154 155 if (amdsmb_sc->res == NULL) { 156 device_printf(dev, "could not map i/o space\n"); 157 return (ENXIO); 158 } 159 160 mtx_init(&amdsmb_sc->lock, device_get_nameunit(dev), "amdsmb", MTX_DEF); 161 162 /* Allocate a new smbus device */ 163 amdsmb_sc->smbus = device_add_child(dev, "smbus", -1); 164 if (!amdsmb_sc->smbus) { 165 amdsmb_detach(dev); 166 return (EINVAL); 167 } 168 169 bus_generic_attach(dev); 170 171 return (0); 172 } 173 174 static int 175 amdsmb_detach(device_t dev) 176 { 177 struct amdsmb_softc *amdsmb_sc = device_get_softc(dev); 178 179 if (amdsmb_sc->smbus) { 180 device_delete_child(dev, amdsmb_sc->smbus); 181 amdsmb_sc->smbus = NULL; 182 } 183 184 mtx_destroy(&amdsmb_sc->lock); 185 if (amdsmb_sc->res) 186 bus_release_resource(dev, SYS_RES_IOPORT, amdsmb_sc->rid, 187 amdsmb_sc->res); 188 189 return (0); 190 } 191 192 static int 193 amdsmb_callback(device_t dev, int index, void *data) 194 { 195 int error = 0; 196 197 switch (index) { 198 case SMB_REQUEST_BUS: 199 case SMB_RELEASE_BUS: 200 break; 201 default: 202 error = EINVAL; 203 } 204 205 return (error); 206 } 207 208 static int 209 amdsmb_ec_wait_write(struct amdsmb_softc *sc) 210 { 211 int timeout = 500; 212 213 while (timeout-- && AMDSMB_ECINB(sc, EC_SC) & EC_SC_IBF) 214 DELAY(1); 215 if (timeout == 0) { 216 device_printf(sc->smbus, "timeout waiting for IBF to clear\n"); 217 return (1); 218 } 219 return (0); 220 } 221 222 static int 223 amdsmb_ec_wait_read(struct amdsmb_softc *sc) 224 { 225 int timeout = 500; 226 227 while (timeout-- && ~AMDSMB_ECINB(sc, EC_SC) & EC_SC_OBF) 228 DELAY(1); 229 if (timeout == 0) { 230 device_printf(sc->smbus, "timeout waiting for OBF to set\n"); 231 return (1); 232 } 233 return (0); 234 } 235 236 static int 237 amdsmb_ec_read(struct amdsmb_softc *sc, u_char addr, u_char *data) 238 { 239 240 AMDSMB_LOCK_ASSERT(sc); 241 if (amdsmb_ec_wait_write(sc)) 242 return (1); 243 AMDSMB_ECOUTB(sc, EC_CMD, EC_CMD_RD); 244 245 if (amdsmb_ec_wait_write(sc)) 246 return (1); 247 AMDSMB_ECOUTB(sc, EC_DATA, addr); 248 249 if (amdsmb_ec_wait_read(sc)) 250 return (1); 251 *data = AMDSMB_ECINB(sc, EC_DATA); 252 253 return (0); 254 } 255 256 static int 257 amdsmb_ec_write(struct amdsmb_softc *sc, u_char addr, u_char data) 258 { 259 260 AMDSMB_LOCK_ASSERT(sc); 261 if (amdsmb_ec_wait_write(sc)) 262 return (1); 263 AMDSMB_ECOUTB(sc, EC_CMD, EC_CMD_WR); 264 265 if (amdsmb_ec_wait_write(sc)) 266 return (1); 267 AMDSMB_ECOUTB(sc, EC_DATA, addr); 268 269 if (amdsmb_ec_wait_write(sc)) 270 return (1); 271 AMDSMB_ECOUTB(sc, EC_DATA, data); 272 273 return (0); 274 } 275 276 static int 277 amdsmb_wait(struct amdsmb_softc *sc) 278 { 279 u_char sts, temp; 280 int error, count; 281 282 AMDSMB_LOCK_ASSERT(sc); 283 amdsmb_ec_read(sc, SMB_PRTCL, &temp); 284 if (temp != 0) 285 { 286 count = 10000; 287 do { 288 DELAY(500); 289 amdsmb_ec_read(sc, SMB_PRTCL, &temp); 290 } while (temp != 0 && count--); 291 if (count == 0) 292 return (SMB_ETIMEOUT); 293 } 294 295 amdsmb_ec_read(sc, SMB_STS, &sts); 296 sts &= SMB_STS_STATUS; 297 AMDSMB_DEBUG(printf("amdsmb: STS=0x%x\n", sts)); 298 299 switch (sts) { 300 case SMB_STS_OK: 301 error = SMB_ENOERR; 302 break; 303 case SMB_STS_DANA: 304 error = SMB_ENOACK; 305 break; 306 case SMB_STS_B: 307 error = SMB_EBUSY; 308 break; 309 case SMB_STS_T: 310 error = SMB_ETIMEOUT; 311 break; 312 case SMB_STS_DCAD: 313 case SMB_STS_DAD: 314 case SMB_STS_HUP: 315 error = SMB_ENOTSUPP; 316 break; 317 default: 318 error = SMB_EBUSERR; 319 break; 320 } 321 322 return (error); 323 } 324 325 static int 326 amdsmb_quick(device_t dev, u_char slave, int how) 327 { 328 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 329 u_char protocol; 330 int error; 331 332 protocol = SMB_PRTCL_QUICK; 333 334 switch (how) { 335 case SMB_QWRITE: 336 protocol |= SMB_PRTCL_WRITE; 337 AMDSMB_DEBUG(printf("amdsmb: QWRITE to 0x%x", slave)); 338 break; 339 case SMB_QREAD: 340 protocol |= SMB_PRTCL_READ; 341 AMDSMB_DEBUG(printf("amdsmb: QREAD to 0x%x", slave)); 342 break; 343 default: 344 panic("%s: unknown QUICK command (%x)!", __func__, how); 345 } 346 347 AMDSMB_LOCK(sc); 348 amdsmb_ec_write(sc, SMB_ADDR, slave); 349 amdsmb_ec_write(sc, SMB_PRTCL, protocol); 350 351 error = amdsmb_wait(sc); 352 353 AMDSMB_DEBUG(printf(", error=0x%x\n", error)); 354 AMDSMB_UNLOCK(sc); 355 356 return (error); 357 } 358 359 static int 360 amdsmb_sendb(device_t dev, u_char slave, char byte) 361 { 362 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 363 int error; 364 365 AMDSMB_LOCK(sc); 366 amdsmb_ec_write(sc, SMB_CMD, byte); 367 amdsmb_ec_write(sc, SMB_ADDR, slave); 368 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 369 370 error = amdsmb_wait(sc); 371 372 AMDSMB_DEBUG(printf("amdsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", 373 slave, byte, error)); 374 AMDSMB_UNLOCK(sc); 375 376 return (error); 377 } 378 379 static int 380 amdsmb_recvb(device_t dev, u_char slave, char *byte) 381 { 382 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 383 int error; 384 385 AMDSMB_LOCK(sc); 386 amdsmb_ec_write(sc, SMB_ADDR, slave); 387 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 388 389 if ((error = amdsmb_wait(sc)) == SMB_ENOERR) 390 amdsmb_ec_read(sc, SMB_DATA, byte); 391 392 AMDSMB_DEBUG(printf("amdsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", 393 slave, *byte, error)); 394 AMDSMB_UNLOCK(sc); 395 396 return (error); 397 } 398 399 static int 400 amdsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 401 { 402 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 403 int error; 404 405 AMDSMB_LOCK(sc); 406 amdsmb_ec_write(sc, SMB_CMD, cmd); 407 amdsmb_ec_write(sc, SMB_DATA, byte); 408 amdsmb_ec_write(sc, SMB_ADDR, slave); 409 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 410 411 error = amdsmb_wait(sc); 412 413 AMDSMB_DEBUG(printf("amdsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, " 414 "error=0x%x\n", slave, cmd, byte, error)); 415 AMDSMB_UNLOCK(sc); 416 417 return (error); 418 } 419 420 static int 421 amdsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 422 { 423 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 424 int error; 425 426 AMDSMB_LOCK(sc); 427 amdsmb_ec_write(sc, SMB_CMD, cmd); 428 amdsmb_ec_write(sc, SMB_ADDR, slave); 429 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 430 431 if ((error = amdsmb_wait(sc)) == SMB_ENOERR) 432 amdsmb_ec_read(sc, SMB_DATA, byte); 433 434 AMDSMB_DEBUG(printf("amdsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, " 435 "error=0x%x\n", slave, cmd, (unsigned char)*byte, error)); 436 AMDSMB_UNLOCK(sc); 437 438 return (error); 439 } 440 441 static int 442 amdsmb_writew(device_t dev, u_char slave, char cmd, short word) 443 { 444 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 445 int error; 446 447 AMDSMB_LOCK(sc); 448 amdsmb_ec_write(sc, SMB_CMD, cmd); 449 amdsmb_ec_write(sc, SMB_DATA, word); 450 amdsmb_ec_write(sc, SMB_DATA + 1, word >> 8); 451 amdsmb_ec_write(sc, SMB_ADDR, slave); 452 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 453 454 error = amdsmb_wait(sc); 455 456 AMDSMB_DEBUG(printf("amdsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, " 457 "error=0x%x\n", slave, cmd, word, error)); 458 AMDSMB_UNLOCK(sc); 459 460 return (error); 461 } 462 463 static int 464 amdsmb_readw(device_t dev, u_char slave, char cmd, short *word) 465 { 466 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 467 u_char temp[2]; 468 int error; 469 470 AMDSMB_LOCK(sc); 471 amdsmb_ec_write(sc, SMB_CMD, cmd); 472 amdsmb_ec_write(sc, SMB_ADDR, slave); 473 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 474 475 if ((error = amdsmb_wait(sc)) == SMB_ENOERR) { 476 amdsmb_ec_read(sc, SMB_DATA + 0, &temp[0]); 477 amdsmb_ec_read(sc, SMB_DATA + 1, &temp[1]); 478 *word = temp[0] | (temp[1] << 8); 479 } 480 481 AMDSMB_DEBUG(printf("amdsmb: READW from 0x%x, cmd=0x%x, word=0x%x, " 482 "error=0x%x\n", slave, cmd, (unsigned short)*word, error)); 483 AMDSMB_UNLOCK(sc); 484 485 return (error); 486 } 487 488 static int 489 amdsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 490 { 491 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 492 u_char i; 493 int error; 494 495 if (count < 1 || count > 32) 496 return (SMB_EINVAL); 497 498 AMDSMB_LOCK(sc); 499 amdsmb_ec_write(sc, SMB_CMD, cmd); 500 amdsmb_ec_write(sc, SMB_BCNT, count); 501 for (i = 0; i < count; i++) 502 amdsmb_ec_write(sc, SMB_DATA + i, buf[i]); 503 amdsmb_ec_write(sc, SMB_ADDR, slave); 504 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 505 506 error = amdsmb_wait(sc); 507 508 AMDSMB_DEBUG(printf("amdsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, " 509 "error=0x%x", slave, count, cmd, error)); 510 AMDSMB_UNLOCK(sc); 511 512 return (error); 513 } 514 515 static int 516 amdsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 517 { 518 struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 519 u_char data, len, i; 520 int error; 521 522 if (*count < 1 || *count > 32) 523 return (SMB_EINVAL); 524 525 AMDSMB_LOCK(sc); 526 amdsmb_ec_write(sc, SMB_CMD, cmd); 527 amdsmb_ec_write(sc, SMB_ADDR, slave); 528 amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 529 530 if ((error = amdsmb_wait(sc)) == SMB_ENOERR) { 531 amdsmb_ec_read(sc, SMB_BCNT, &len); 532 for (i = 0; i < len; i++) { 533 amdsmb_ec_read(sc, SMB_DATA + i, &data); 534 if (i < *count) 535 buf[i] = data; 536 } 537 *count = len; 538 } 539 540 AMDSMB_DEBUG(printf("amdsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, " 541 "error=0x%x", slave, *count, cmd, error)); 542 AMDSMB_UNLOCK(sc); 543 544 return (error); 545 } 546 547 static device_method_t amdsmb_methods[] = { 548 /* Device interface */ 549 DEVMETHOD(device_probe, amdsmb_probe), 550 DEVMETHOD(device_attach, amdsmb_attach), 551 DEVMETHOD(device_detach, amdsmb_detach), 552 553 /* SMBus interface */ 554 DEVMETHOD(smbus_callback, amdsmb_callback), 555 DEVMETHOD(smbus_quick, amdsmb_quick), 556 DEVMETHOD(smbus_sendb, amdsmb_sendb), 557 DEVMETHOD(smbus_recvb, amdsmb_recvb), 558 DEVMETHOD(smbus_writeb, amdsmb_writeb), 559 DEVMETHOD(smbus_readb, amdsmb_readb), 560 DEVMETHOD(smbus_writew, amdsmb_writew), 561 DEVMETHOD(smbus_readw, amdsmb_readw), 562 DEVMETHOD(smbus_bwrite, amdsmb_bwrite), 563 DEVMETHOD(smbus_bread, amdsmb_bread), 564 { 0, 0 } 565 }; 566 567 static driver_t amdsmb_driver = { 568 "amdsmb", 569 amdsmb_methods, 570 sizeof(struct amdsmb_softc), 571 }; 572 573 DRIVER_MODULE(amdsmb, pci, amdsmb_driver, 0, 0); 574 DRIVER_MODULE(smbus, amdsmb, smbus_driver, 0, 0); 575 576 MODULE_DEPEND(amdsmb, pci, 1, 1, 1); 577 MODULE_DEPEND(amdsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 578 MODULE_VERSION(amdsmb, 1); 579