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 61static int viapm_debug = 1; 62#else 63static 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 92struct 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 105static devclass_t viapm_devclass; 106static 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 187static int 188viapm_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 245static int 246viapm_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 341static int 342viapm_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 404error: 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 416static int 417viapm_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 438error: 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 446static int 447viapm_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 464static int 465viapm_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 484static int 485viabb_callback(device_t dev, int index, caddr_t data) 486{ 487 return 0; 488} 489 490static void 491viabb_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 510static void 511viabb_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 530static int 531viabb_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 540static int 541viabb_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 552static int 553viabb_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 564static int 565viapm_abort(struct viapm_softc *viapm) 566{ 567 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); 568 DELAY(10); 569 570 return (0); 571} 572 573static int 574viapm_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 583static int 584viapm_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 */ 598static int 599viapm_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 641static int 642viasmb_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 658static int 659viasmb_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 692static int 693viasmb_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 718static int 719viasmb_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 744static int 745viasmb_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 771static int 772viasmb_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 798static int 799viasmb_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 826static int 827viasmb_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 858static int 859viasmb_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 897static int 898viasmb_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 933error: 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 940static 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 965static driver_t viapm_driver = { 966 "viapm", 967 viapm_methods, 968 sizeof(struct viapm_softc), 969}; 970 971static 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 1000static driver_t viapropm_driver = { 1001 "viapropm", 1002 viapropm_methods, 1003 sizeof(struct viapm_softc), 1004}; 1005 1006DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); 1007DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); 1008DRIVER_MODULE(iicbb, viapm, iicbb_driver, iicbb_devclass, 0, 0); 1009DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0); 1010 1011MODULE_DEPEND(viapm, pci, 1, 1, 1); 1012MODULE_DEPEND(viapropm, pci, 1, 1, 1); 1013MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 1014MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 1015MODULE_VERSION(viapm, 1); 1016 1017#ifdef DEV_ISA 1018DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0); 1019DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0); 1020MODULE_DEPEND(viapm, isa, 1, 1, 1); 1021MODULE_DEPEND(viapropm, isa, 1, 1, 1); 1022#endif 1023