1 /*- 2 * Copyright (c) 2001 Alcove - Nicolas Souchu 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 __FBSDID("$FreeBSD$"); 29 30 #include "opt_isa.h" 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/module.h> 37 #include <sys/mutex.h> 38 #include <sys/systm.h> 39 40 #include <machine/bus.h> 41 #include <machine/resource.h> 42 #include <sys/rman.h> 43 44 #ifdef DEV_ISA 45 #include <isa/isavar.h> 46 #include <isa/isa_common.h> 47 #endif 48 #include <dev/pci/pcivar.h> 49 #include <dev/pci/pcireg.h> 50 51 #include <dev/iicbus/iiconf.h> 52 53 #include <dev/smbus/smbconf.h> 54 55 #include "iicbb_if.h" 56 #include "smbus_if.h" 57 58 #define VIAPM_DEBUG(x) if (viapm_debug) (x) 59 60 #ifdef DEBUG 61 static int viapm_debug = 1; 62 #else 63 static int viapm_debug = 0; 64 #endif 65 66 #define VIA_586B_PMU_ID 0x30401106 67 #define VIA_596A_PMU_ID 0x30501106 68 #define VIA_596B_PMU_ID 0x30511106 69 #define VIA_686A_PMU_ID 0x30571106 70 #define VIA_8233_PMU_ID 0x30741106 71 #define VIA_8233A_PMU_ID 0x31471106 72 #define VIA_8235_PMU_ID 0x31771106 73 #define VIA_8237_PMU_ID 0x32271106 74 #define VIA_CX700_PMU_ID 0x83241106 75 76 #define VIAPM_INB(port) \ 77 ((u_char)bus_read_1(viapm->iores, port)) 78 #define VIAPM_OUTB(port,val) \ 79 (bus_write_1(viapm->iores, port, (u_char)(val))) 80 81 #define VIAPM_TYP_UNKNOWN 0 82 #define VIAPM_TYP_586B_3040E 1 83 #define VIAPM_TYP_586B_3040F 2 84 #define VIAPM_TYP_596B 3 85 #define VIAPM_TYP_686A 4 86 #define VIAPM_TYP_8233 5 87 88 #define VIAPM_LOCK(sc) mtx_lock(&(sc)->lock) 89 #define VIAPM_UNLOCK(sc) mtx_unlock(&(sc)->lock) 90 #define VIAPM_LOCK_ASSERT(sc) mtx_assert(&(sc)->lock, MA_OWNED) 91 92 struct viapm_softc { 93 int type; 94 u_int32_t base; 95 int iorid; 96 int irqrid; 97 struct resource *iores; 98 struct resource *irqres; 99 void *irqih; 100 device_t iicbb; 101 device_t smbus; 102 struct mtx lock; 103 }; 104 105 static devclass_t viapm_devclass; 106 static devclass_t viapropm_devclass; 107 108 /* 109 * VT82C586B definitions 110 */ 111 112 #define VIAPM_586B_REVID 0x08 113 114 #define VIAPM_586B_3040E_BASE 0x20 115 #define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */ 116 117 #define VIAPM_586B_3040F_BASE 0x48 118 #define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */ 119 120 #define VIAPM_586B_OEM_REV_E 0x00 121 #define VIAPM_586B_OEM_REV_F 0x01 122 #define VIAPM_586B_PROD_REV_A 0x10 123 124 #define VIAPM_586B_BA_MASK 0x0000ff00 125 126 #define GPIO_DIR 0x40 127 #define GPIO_VAL 0x42 128 #define EXTSMI_VAL 0x44 129 130 #define VIAPM_SCL 0x02 /* GPIO1_VAL */ 131 #define VIAPM_SDA 0x04 /* GPIO2_VAL */ 132 133 /* 134 * VIAPRO common definitions 135 */ 136 137 #define VIAPM_PRO_BA_MASK 0x0000fff0 138 #define VIAPM_PRO_SMBCTRL 0xd2 139 #define VIAPM_PRO_REVID 0xd6 140 141 /* 142 * VT82C686A definitions 143 */ 144 145 #define VIAPM_PRO_BASE 0x90 146 147 #define SMBHST 0x0 148 #define SMBHSL 0x1 149 #define SMBHCTRL 0x2 150 #define SMBHCMD 0x3 151 #define SMBHADDR 0x4 152 #define SMBHDATA0 0x5 153 #define SMBHDATA1 0x6 154 #define SMBHBLOCK 0x7 155 156 #define SMBSST 0x1 157 #define SMBSCTRL 0x8 158 #define SMBSSDWCMD 0x9 159 #define SMBSEVENT 0xa 160 #define SMBSDATA 0xc 161 162 #define SMBHST_RESERVED 0xef /* reserved bits */ 163 #define SMBHST_FAILED 0x10 /* failed bus transaction */ 164 #define SMBHST_COLLID 0x08 /* bus collision */ 165 #define SMBHST_ERROR 0x04 /* device error */ 166 #define SMBHST_INTR 0x02 /* command completed */ 167 #define SMBHST_BUSY 0x01 /* host busy */ 168 169 #define SMBHCTRL_START 0x40 /* start command */ 170 #define SMBHCTRL_PROTO 0x1c /* command protocol mask */ 171 #define SMBHCTRL_QUICK 0x00 172 #define SMBHCTRL_SENDRECV 0x04 173 #define SMBHCTRL_BYTE 0x08 174 #define SMBHCTRL_WORD 0x0c 175 #define SMBHCTRL_BLOCK 0x14 176 #define SMBHCTRL_KILL 0x02 /* stop the current transaction */ 177 #define SMBHCTRL_ENABLE 0x01 /* enable interrupts */ 178 179 #define SMBSCTRL_ENABLE 0x01 /* enable slave */ 180 181 /* 182 * VIA8233 definitions 183 */ 184 185 #define VIAPM_8233_BASE 0xD0 186 187 static int 188 viapm_586b_probe(device_t dev) 189 { 190 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 191 u_int32_t l; 192 u_int16_t s; 193 u_int8_t c; 194 195 switch (pci_get_devid(dev)) { 196 case VIA_586B_PMU_ID: 197 198 bzero(viapm, sizeof(struct viapm_softc)); 199 200 l = pci_read_config(dev, VIAPM_586B_REVID, 1); 201 switch (l) { 202 case VIAPM_586B_OEM_REV_E: 203 viapm->type = VIAPM_TYP_586B_3040E; 204 viapm->iorid = VIAPM_586B_3040E_BASE; 205 206 /* Activate IO block access */ 207 s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2); 208 pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2); 209 break; 210 211 case VIAPM_586B_OEM_REV_F: 212 case VIAPM_586B_PROD_REV_A: 213 default: 214 viapm->type = VIAPM_TYP_586B_3040F; 215 viapm->iorid = VIAPM_586B_3040F_BASE; 216 217 /* Activate IO block access */ 218 c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1); 219 pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1); 220 break; 221 } 222 223 viapm->base = pci_read_config(dev, viapm->iorid, 4) & 224 VIAPM_586B_BA_MASK; 225 226 /* 227 * We have to set the I/O resources by hand because it is 228 * described outside the viapmope of the traditional maps 229 */ 230 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 231 viapm->base, 256)) { 232 device_printf(dev, "could not set bus resource\n"); 233 return ENXIO; 234 } 235 device_set_desc(dev, "VIA VT82C586B Power Management Unit"); 236 return (BUS_PROBE_DEFAULT); 237 238 default: 239 break; 240 } 241 242 return ENXIO; 243 } 244 245 static int 246 viapm_pro_probe(device_t dev) 247 { 248 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 249 #ifdef VIAPM_BASE_ADDR 250 u_int32_t l; 251 #endif 252 u_int32_t base_cfgreg; 253 char *desc; 254 255 switch (pci_get_devid(dev)) { 256 case VIA_596A_PMU_ID: 257 desc = "VIA VT82C596A Power Management Unit"; 258 viapm->type = VIAPM_TYP_596B; 259 base_cfgreg = VIAPM_PRO_BASE; 260 goto viapro; 261 262 case VIA_596B_PMU_ID: 263 desc = "VIA VT82C596B Power Management Unit"; 264 viapm->type = VIAPM_TYP_596B; 265 base_cfgreg = VIAPM_PRO_BASE; 266 goto viapro; 267 268 case VIA_686A_PMU_ID: 269 desc = "VIA VT82C686A Power Management Unit"; 270 viapm->type = VIAPM_TYP_686A; 271 base_cfgreg = VIAPM_PRO_BASE; 272 goto viapro; 273 274 case VIA_8233_PMU_ID: 275 case VIA_8233A_PMU_ID: 276 desc = "VIA VT8233 Power Management Unit"; 277 viapm->type = VIAPM_TYP_UNKNOWN; 278 base_cfgreg = VIAPM_8233_BASE; 279 goto viapro; 280 281 case VIA_8235_PMU_ID: 282 desc = "VIA VT8235 Power Management Unit"; 283 viapm->type = VIAPM_TYP_UNKNOWN; 284 base_cfgreg = VIAPM_8233_BASE; 285 goto viapro; 286 287 case VIA_8237_PMU_ID: 288 desc = "VIA VT8237 Power Management Unit"; 289 viapm->type = VIAPM_TYP_UNKNOWN; 290 base_cfgreg = VIAPM_8233_BASE; 291 goto viapro; 292 293 case VIA_CX700_PMU_ID: 294 desc = "VIA CX700 Power Management Unit"; 295 viapm->type = VIAPM_TYP_UNKNOWN; 296 base_cfgreg = VIAPM_8233_BASE; 297 goto viapro; 298 299 viapro: 300 301 #ifdef VIAPM_BASE_ADDR 302 /* force VIAPM I/O base address */ 303 304 /* enable the SMBus controller function */ 305 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 306 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 307 308 /* write the base address */ 309 pci_write_config(dev, base_cfgreg, 310 VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4); 311 #endif 312 313 viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK; 314 315 /* 316 * We have to set the I/O resources by hand because it is 317 * described outside the viapmope of the traditional maps 318 */ 319 viapm->iorid = base_cfgreg; 320 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 321 viapm->base, 16)) { 322 device_printf(dev, "could not set bus resource 0x%x\n", 323 viapm->base); 324 return ENXIO; 325 } 326 327 if (bootverbose) { 328 device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base); 329 } 330 331 device_set_desc(dev, desc); 332 return (BUS_PROBE_DEFAULT); 333 334 default: 335 break; 336 } 337 338 return ENXIO; 339 } 340 341 static int 342 viapm_pro_attach(device_t dev) 343 { 344 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 345 u_int32_t l; 346 347 mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF); 348 if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 349 &viapm->iorid, RF_ACTIVE))) { 350 device_printf(dev, "could not allocate bus space\n"); 351 goto error; 352 } 353 354 #ifdef notyet 355 /* force irq 9 */ 356 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 357 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1); 358 359 viapm->irqrid = 0; 360 if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, 361 &viapm->irqrid, 9, 9, 1, 362 RF_SHAREABLE | RF_ACTIVE))) { 363 device_printf(dev, "could not allocate irq\n"); 364 goto error; 365 } 366 367 if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC | INTR_MPSAFE, 368 (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) { 369 device_printf(dev, "could not setup irq\n"); 370 goto error; 371 } 372 #endif 373 374 if (bootverbose) { 375 l = pci_read_config(dev, VIAPM_PRO_REVID, 1); 376 device_printf(dev, "SMBus revision code 0x%x\n", l); 377 } 378 379 viapm->smbus = device_add_child(dev, "smbus", -1); 380 381 /* probe and attach the smbus */ 382 bus_generic_attach(dev); 383 384 /* disable slave function */ 385 VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE); 386 387 /* enable the SMBus controller function */ 388 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 389 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 390 391 #ifdef notyet 392 /* enable interrupts */ 393 VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE); 394 #endif 395 396 #ifdef DEV_ISA 397 /* If this device is a PCI-ISA bridge, then attach an ISA bus. */ 398 if ((pci_get_class(dev) == PCIC_BRIDGE) && 399 (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) 400 isab_attach(dev); 401 #endif 402 return 0; 403 404 error: 405 if (viapm->iores) 406 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 407 #ifdef notyet 408 if (viapm->irqres) 409 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 410 #endif 411 mtx_destroy(&viapm->lock); 412 413 return ENXIO; 414 } 415 416 static int 417 viapm_586b_attach(device_t dev) 418 { 419 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 420 421 mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF); 422 if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 423 &viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) { 424 device_printf(dev, "could not allocate bus resource\n"); 425 goto error; 426 } 427 428 VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA); 429 430 /* add generic bit-banging code */ 431 if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1))) 432 goto error; 433 434 bus_generic_attach(dev); 435 436 return 0; 437 438 error: 439 if (viapm->iores) 440 bus_release_resource(dev, SYS_RES_IOPORT, 441 viapm->iorid, viapm->iores); 442 mtx_destroy(&viapm->lock); 443 return ENXIO; 444 } 445 446 static int 447 viapm_586b_detach(device_t dev) 448 { 449 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 450 451 bus_generic_detach(dev); 452 if (viapm->iicbb) { 453 device_delete_child(dev, viapm->iicbb); 454 } 455 456 if (viapm->iores) 457 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, 458 viapm->iores); 459 mtx_destroy(&viapm->lock); 460 461 return 0; 462 } 463 464 static int 465 viapm_pro_detach(device_t dev) 466 { 467 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 468 469 bus_generic_detach(dev); 470 if (viapm->smbus) { 471 device_delete_child(dev, viapm->smbus); 472 } 473 474 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 475 476 #ifdef notyet 477 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 478 #endif 479 mtx_destroy(&viapm->lock); 480 481 return 0; 482 } 483 484 static int 485 viabb_callback(device_t dev, int index, caddr_t data) 486 { 487 return 0; 488 } 489 490 static void 491 viabb_setscl(device_t dev, int ctrl) 492 { 493 struct viapm_softc *viapm = device_get_softc(dev); 494 u_char val; 495 496 VIAPM_LOCK(viapm); 497 val = VIAPM_INB(GPIO_VAL); 498 499 if (ctrl) 500 val |= VIAPM_SCL; 501 else 502 val &= ~VIAPM_SCL; 503 504 VIAPM_OUTB(GPIO_VAL, val); 505 VIAPM_UNLOCK(viapm); 506 507 return; 508 } 509 510 static void 511 viabb_setsda(device_t dev, int data) 512 { 513 struct viapm_softc *viapm = device_get_softc(dev); 514 u_char val; 515 516 VIAPM_LOCK(viapm); 517 val = VIAPM_INB(GPIO_VAL); 518 519 if (data) 520 val |= VIAPM_SDA; 521 else 522 val &= ~VIAPM_SDA; 523 524 VIAPM_OUTB(GPIO_VAL, val); 525 VIAPM_UNLOCK(viapm); 526 527 return; 528 } 529 530 static int 531 viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 532 { 533 /* reset bus */ 534 viabb_setsda(dev, 1); 535 viabb_setscl(dev, 1); 536 537 return (IIC_ENOADDR); 538 } 539 540 static int 541 viabb_getscl(device_t dev) 542 { 543 struct viapm_softc *viapm = device_get_softc(dev); 544 u_char val; 545 546 VIAPM_LOCK(viapm); 547 val = VIAPM_INB(EXTSMI_VAL); 548 VIAPM_UNLOCK(viapm); 549 return ((val & VIAPM_SCL) != 0); 550 } 551 552 static int 553 viabb_getsda(device_t dev) 554 { 555 struct viapm_softc *viapm = device_get_softc(dev); 556 u_char val; 557 558 VIAPM_LOCK(viapm); 559 val = VIAPM_INB(EXTSMI_VAL); 560 VIAPM_UNLOCK(viapm); 561 return ((val & VIAPM_SDA) != 0); 562 } 563 564 static int 565 viapm_abort(struct viapm_softc *viapm) 566 { 567 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); 568 DELAY(10); 569 570 return (0); 571 } 572 573 static int 574 viapm_clear(struct viapm_softc *viapm) 575 { 576 VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID | 577 SMBHST_ERROR | SMBHST_INTR); 578 DELAY(10); 579 580 return (0); 581 } 582 583 static int 584 viapm_busy(struct viapm_softc *viapm) 585 { 586 u_char sts; 587 588 sts = VIAPM_INB(SMBHST); 589 590 VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts)); 591 592 return (sts & SMBHST_BUSY); 593 } 594 595 /* 596 * Poll the SMBus controller 597 */ 598 static int 599 viapm_wait(struct viapm_softc *viapm) 600 { 601 int count = 10000; 602 u_char sts = 0; 603 int error; 604 605 VIAPM_LOCK_ASSERT(viapm); 606 607 /* wait for command to complete and SMBus controller is idle */ 608 while(count--) { 609 DELAY(10); 610 sts = VIAPM_INB(SMBHST); 611 612 /* check if the controller is processing a command */ 613 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) 614 break; 615 } 616 617 VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts)); 618 619 error = SMB_ENOERR; 620 621 if (!count) 622 error |= SMB_ETIMEOUT; 623 624 if (sts & SMBHST_FAILED) 625 error |= SMB_EABORT; 626 627 if (sts & SMBHST_COLLID) 628 error |= SMB_ENOACK; 629 630 if (sts & SMBHST_ERROR) 631 error |= SMB_EBUSERR; 632 633 if (error != SMB_ENOERR) 634 viapm_abort(viapm); 635 636 viapm_clear(viapm); 637 638 return (error); 639 } 640 641 static int 642 viasmb_callback(device_t dev, int index, void *data) 643 { 644 int error = 0; 645 646 switch (index) { 647 case SMB_REQUEST_BUS: 648 case SMB_RELEASE_BUS: 649 /* ok, bus allocation accepted */ 650 break; 651 default: 652 error = EINVAL; 653 } 654 655 return (error); 656 } 657 658 static int 659 viasmb_quick(device_t dev, u_char slave, int how) 660 { 661 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 662 int error; 663 664 VIAPM_LOCK(viapm); 665 viapm_clear(viapm); 666 if (viapm_busy(viapm)) { 667 VIAPM_UNLOCK(viapm); 668 return (SMB_EBUSY); 669 } 670 671 switch (how) { 672 case SMB_QWRITE: 673 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave)); 674 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 675 break; 676 case SMB_QREAD: 677 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave)); 678 VIAPM_OUTB(SMBHADDR, slave | LSB); 679 break; 680 default: 681 panic("%s: unknown QUICK command (%x)!", __func__, how); 682 } 683 684 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK); 685 686 error = viapm_wait(viapm); 687 VIAPM_UNLOCK(viapm); 688 689 return (error); 690 } 691 692 static int 693 viasmb_sendb(device_t dev, u_char slave, char byte) 694 { 695 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 696 int error; 697 698 VIAPM_LOCK(viapm); 699 viapm_clear(viapm); 700 if (viapm_busy(viapm)) { 701 VIAPM_UNLOCK(viapm); 702 return (SMB_EBUSY); 703 } 704 705 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 706 VIAPM_OUTB(SMBHCMD, byte); 707 708 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 709 710 error = viapm_wait(viapm); 711 712 VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 713 VIAPM_UNLOCK(viapm); 714 715 return (error); 716 } 717 718 static int 719 viasmb_recvb(device_t dev, u_char slave, char *byte) 720 { 721 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 722 int error; 723 724 VIAPM_LOCK(viapm); 725 viapm_clear(viapm); 726 if (viapm_busy(viapm)) { 727 VIAPM_UNLOCK(viapm); 728 return (SMB_EBUSY); 729 } 730 731 VIAPM_OUTB(SMBHADDR, slave | LSB); 732 733 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 734 735 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 736 *byte = VIAPM_INB(SMBHDATA0); 737 738 VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 739 VIAPM_UNLOCK(viapm); 740 741 return (error); 742 } 743 744 static int 745 viasmb_writeb(device_t dev, u_char slave, char cmd, char byte) 746 { 747 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 748 int error; 749 750 VIAPM_LOCK(viapm); 751 viapm_clear(viapm); 752 if (viapm_busy(viapm)) { 753 VIAPM_UNLOCK(viapm); 754 return (SMB_EBUSY); 755 } 756 757 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 758 VIAPM_OUTB(SMBHCMD, cmd); 759 VIAPM_OUTB(SMBHDATA0, byte); 760 761 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 762 763 error = viapm_wait(viapm); 764 765 VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 766 VIAPM_UNLOCK(viapm); 767 768 return (error); 769 } 770 771 static int 772 viasmb_readb(device_t dev, u_char slave, char cmd, char *byte) 773 { 774 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 775 int error; 776 777 VIAPM_LOCK(viapm); 778 viapm_clear(viapm); 779 if (viapm_busy(viapm)) { 780 VIAPM_UNLOCK(viapm); 781 return (SMB_EBUSY); 782 } 783 784 VIAPM_OUTB(SMBHADDR, slave | LSB); 785 VIAPM_OUTB(SMBHCMD, cmd); 786 787 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 788 789 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 790 *byte = VIAPM_INB(SMBHDATA0); 791 792 VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 793 VIAPM_UNLOCK(viapm); 794 795 return (error); 796 } 797 798 static int 799 viasmb_writew(device_t dev, u_char slave, char cmd, short word) 800 { 801 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 802 int error; 803 804 VIAPM_LOCK(viapm); 805 viapm_clear(viapm); 806 if (viapm_busy(viapm)) { 807 VIAPM_UNLOCK(viapm); 808 return (SMB_EBUSY); 809 } 810 811 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 812 VIAPM_OUTB(SMBHCMD, cmd); 813 VIAPM_OUTB(SMBHDATA0, word & 0x00ff); 814 VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8); 815 816 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 817 818 error = viapm_wait(viapm); 819 820 VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 821 VIAPM_UNLOCK(viapm); 822 823 return (error); 824 } 825 826 static int 827 viasmb_readw(device_t dev, u_char slave, char cmd, short *word) 828 { 829 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 830 int error; 831 u_char high, low; 832 833 VIAPM_LOCK(viapm); 834 viapm_clear(viapm); 835 if (viapm_busy(viapm)) { 836 VIAPM_UNLOCK(viapm); 837 return (SMB_EBUSY); 838 } 839 840 VIAPM_OUTB(SMBHADDR, slave | LSB); 841 VIAPM_OUTB(SMBHCMD, cmd); 842 843 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 844 845 if ((error = viapm_wait(viapm)) == SMB_ENOERR) { 846 low = VIAPM_INB(SMBHDATA0); 847 high = VIAPM_INB(SMBHDATA1); 848 849 *word = ((high & 0xff) << 8) | (low & 0xff); 850 } 851 852 VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 853 VIAPM_UNLOCK(viapm); 854 855 return (error); 856 } 857 858 static int 859 viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 860 { 861 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 862 u_char i; 863 int error; 864 865 if (count < 1 || count > 32) 866 return (SMB_EINVAL); 867 868 VIAPM_LOCK(viapm); 869 viapm_clear(viapm); 870 if (viapm_busy(viapm)) { 871 VIAPM_UNLOCK(viapm); 872 return (SMB_EBUSY); 873 } 874 875 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 876 VIAPM_OUTB(SMBHCMD, cmd); 877 VIAPM_OUTB(SMBHDATA0, count); 878 i = VIAPM_INB(SMBHCTRL); 879 880 /* fill the 32-byte internal buffer */ 881 for (i = 0; i < count; i++) { 882 VIAPM_OUTB(SMBHBLOCK, buf[i]); 883 DELAY(2); 884 } 885 VIAPM_OUTB(SMBHCMD, cmd); 886 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 887 888 error = viapm_wait(viapm); 889 890 VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 891 VIAPM_UNLOCK(viapm); 892 893 return (error); 894 895 } 896 897 static int 898 viasmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 899 { 900 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 901 u_char data, len, i; 902 int error; 903 904 if (*count < 1 || *count > 32) 905 return (SMB_EINVAL); 906 907 VIAPM_LOCK(viapm); 908 viapm_clear(viapm); 909 if (viapm_busy(viapm)) { 910 VIAPM_UNLOCK(viapm); 911 return (SMB_EBUSY); 912 } 913 914 VIAPM_OUTB(SMBHADDR, slave | LSB); 915 VIAPM_OUTB(SMBHCMD, cmd); 916 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 917 918 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 919 goto error; 920 921 len = VIAPM_INB(SMBHDATA0); 922 i = VIAPM_INB(SMBHCTRL); /* reset counter */ 923 924 /* read the 32-byte internal buffer */ 925 for (i = 0; i < len; i++) { 926 data = VIAPM_INB(SMBHBLOCK); 927 if (i < *count) 928 buf[i] = data; 929 DELAY(2); 930 } 931 *count = len; 932 933 error: 934 VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 935 VIAPM_UNLOCK(viapm); 936 937 return (error); 938 } 939 940 static device_method_t viapm_methods[] = { 941 /* device interface */ 942 DEVMETHOD(device_probe, viapm_586b_probe), 943 DEVMETHOD(device_attach, viapm_586b_attach), 944 DEVMETHOD(device_detach, viapm_586b_detach), 945 946 /* iicbb interface */ 947 DEVMETHOD(iicbb_callback, viabb_callback), 948 DEVMETHOD(iicbb_setscl, viabb_setscl), 949 DEVMETHOD(iicbb_setsda, viabb_setsda), 950 DEVMETHOD(iicbb_getscl, viabb_getscl), 951 DEVMETHOD(iicbb_getsda, viabb_getsda), 952 DEVMETHOD(iicbb_reset, viabb_reset), 953 954 /* Bus interface */ 955 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 956 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 957 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 958 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 959 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 960 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 961 962 DEVMETHOD_END 963 }; 964 965 static driver_t viapm_driver = { 966 "viapm", 967 viapm_methods, 968 sizeof(struct viapm_softc), 969 }; 970 971 static device_method_t viapropm_methods[] = { 972 /* device interface */ 973 DEVMETHOD(device_probe, viapm_pro_probe), 974 DEVMETHOD(device_attach, viapm_pro_attach), 975 DEVMETHOD(device_detach, viapm_pro_detach), 976 977 /* smbus interface */ 978 DEVMETHOD(smbus_callback, viasmb_callback), 979 DEVMETHOD(smbus_quick, viasmb_quick), 980 DEVMETHOD(smbus_sendb, viasmb_sendb), 981 DEVMETHOD(smbus_recvb, viasmb_recvb), 982 DEVMETHOD(smbus_writeb, viasmb_writeb), 983 DEVMETHOD(smbus_readb, viasmb_readb), 984 DEVMETHOD(smbus_writew, viasmb_writew), 985 DEVMETHOD(smbus_readw, viasmb_readw), 986 DEVMETHOD(smbus_bwrite, viasmb_bwrite), 987 DEVMETHOD(smbus_bread, viasmb_bread), 988 989 /* Bus interface */ 990 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 991 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 992 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 993 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 994 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 995 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 996 997 DEVMETHOD_END 998 }; 999 1000 static driver_t viapropm_driver = { 1001 "viapropm", 1002 viapropm_methods, 1003 sizeof(struct viapm_softc), 1004 }; 1005 1006 DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); 1007 DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); 1008 DRIVER_MODULE(iicbb, viapm, iicbb_driver, iicbb_devclass, 0, 0); 1009 DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0); 1010 1011 MODULE_DEPEND(viapm, pci, 1, 1, 1); 1012 MODULE_DEPEND(viapropm, pci, 1, 1, 1); 1013 MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 1014 MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 1015 MODULE_VERSION(viapm, 1); 1016 1017 #ifdef DEV_ISA 1018 DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0); 1019 DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0); 1020 MODULE_DEPEND(viapm, isa, 1, 1, 1); 1021 MODULE_DEPEND(viapropm, isa, 1, 1, 1); 1022 #endif 1023