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