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