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