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