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