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