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