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