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