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