viapm.c revision 179622
1181834Sroberto/*- 2181834Sroberto * Copyright (c) 2001 Alcove - Nicolas Souchu 3181834Sroberto * All rights reserved. 4181834Sroberto * 5181834Sroberto * Redistribution and use in source and binary forms, with or without 6181834Sroberto * modification, are permitted provided that the following conditions 7181834Sroberto * are met: 8181834Sroberto * 1. Redistributions of source code must retain the above copyright 9181834Sroberto * notice, this list of conditions and the following disclaimer. 10181834Sroberto * 2. Redistributions in binary form must reproduce the above copyright 11181834Sroberto * notice, this list of conditions and the following disclaimer in the 12181834Sroberto * documentation and/or other materials provided with the distribution. 13181834Sroberto * 14181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15181834Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17181834Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18181834Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19181834Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20181834Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22181834Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23181834Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24181834Sroberto * SUCH DAMAGE. 25181834Sroberto */ 26181834Sroberto 27181834Sroberto#include <sys/cdefs.h> 28181834Sroberto__FBSDID("$FreeBSD: head/sys/pci/viapm.c 179622 2008-06-06 18:29:56Z jhb $"); 29181834Sroberto 30181834Sroberto#include "opt_isa.h" 31181834Sroberto 32181834Sroberto#include <sys/param.h> 33181834Sroberto#include <sys/bus.h> 34181834Sroberto#include <sys/kernel.h> 35181834Sroberto#include <sys/lock.h> 36181834Sroberto#include <sys/module.h> 37181834Sroberto#include <sys/mutex.h> 38181834Sroberto#include <sys/systm.h> 39181834Sroberto 40181834Sroberto#include <machine/bus.h> 41181834Sroberto#include <machine/resource.h> 42181834Sroberto#include <sys/rman.h> 43181834Sroberto 44181834Sroberto#ifdef DEV_ISA 45181834Sroberto#include <isa/isavar.h> 46181834Sroberto#include <isa/isa_common.h> 47181834Sroberto#endif 48181834Sroberto#include <dev/pci/pcivar.h> 49181834Sroberto#include <dev/pci/pcireg.h> 50181834Sroberto 51181834Sroberto#include <dev/iicbus/iiconf.h> 52181834Sroberto 53181834Sroberto#include <dev/smbus/smbconf.h> 54181834Sroberto 55181834Sroberto#include "iicbb_if.h" 56181834Sroberto#include "smbus_if.h" 57181834Sroberto 58181834Sroberto#define VIAPM_DEBUG(x) if (viapm_debug) (x) 59181834Sroberto 60181834Sroberto#ifdef DEBUG 61181834Srobertostatic int viapm_debug = 1; 62181834Sroberto#else 63181834Srobertostatic int viapm_debug = 0; 64181834Sroberto#endif 65181834Sroberto 66181834Sroberto#define VIA_586B_PMU_ID 0x30401106 67181834Sroberto#define VIA_596A_PMU_ID 0x30501106 68181834Sroberto#define VIA_596B_PMU_ID 0x30511106 69181834Sroberto#define VIA_686A_PMU_ID 0x30571106 70181834Sroberto#define VIA_8233_PMU_ID 0x30741106 71181834Sroberto#define VIA_8233A_PMU_ID 0x31471106 72181834Sroberto#define VIA_8235_PMU_ID 0x31771106 73181834Sroberto#define VIA_CX700_PMU_ID 0x83241106 74181834Sroberto 75181834Sroberto#define VIAPM_INB(port) \ 76181834Sroberto ((u_char)bus_read_1(viapm->iores, port)) 77181834Sroberto#define VIAPM_OUTB(port,val) \ 78181834Sroberto (bus_write_1(viapm->iores, port, (u_char)(val))) 79181834Sroberto 80181834Sroberto#define VIAPM_TYP_UNKNOWN 0 81181834Sroberto#define VIAPM_TYP_586B_3040E 1 82181834Sroberto#define VIAPM_TYP_586B_3040F 2 83181834Sroberto#define VIAPM_TYP_596B 3 84181834Sroberto#define VIAPM_TYP_686A 4 85181834Sroberto#define VIAPM_TYP_8233 5 86181834Sroberto 87181834Sroberto#define VIAPM_LOCK(sc) mtx_lock(&(sc)->lock) 88181834Sroberto#define VIAPM_UNLOCK(sc) mtx_unlock(&(sc)->lock) 89181834Sroberto#define VIAPM_LOCK_ASSERT(sc) mtx_assert(&(sc)->lock, MA_OWNED) 90181834Sroberto 91181834Srobertostruct viapm_softc { 92181834Sroberto int type; 93181834Sroberto u_int32_t base; 94181834Sroberto int iorid; 95181834Sroberto int irqrid; 96181834Sroberto struct resource *iores; 97181834Sroberto struct resource *irqres; 98181834Sroberto void *irqih; 99181834Sroberto device_t iicbb; 100181834Sroberto device_t smbus; 101181834Sroberto struct mtx lock; 102181834Sroberto}; 103181834Sroberto 104181834Srobertostatic devclass_t viapm_devclass; 105181834Srobertostatic devclass_t viapropm_devclass; 106181834Sroberto 107181834Sroberto/* 108181834Sroberto * VT82C586B definitions 109181834Sroberto */ 110181834Sroberto 111181834Sroberto#define VIAPM_586B_REVID 0x08 112181834Sroberto 113181834Sroberto#define VIAPM_586B_3040E_BASE 0x20 114181834Sroberto#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */ 115181834Sroberto 116181834Sroberto#define VIAPM_586B_3040F_BASE 0x48 117181834Sroberto#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */ 118181834Sroberto 119181834Sroberto#define VIAPM_586B_OEM_REV_E 0x00 120181834Sroberto#define VIAPM_586B_OEM_REV_F 0x01 121181834Sroberto#define VIAPM_586B_PROD_REV_A 0x10 122181834Sroberto 123181834Sroberto#define VIAPM_586B_BA_MASK 0x0000ff00 124181834Sroberto 125181834Sroberto#define GPIO_DIR 0x40 126181834Sroberto#define GPIO_VAL 0x42 127181834Sroberto#define EXTSMI_VAL 0x44 128181834Sroberto 129181834Sroberto#define VIAPM_SCL 0x02 /* GPIO1_VAL */ 130181834Sroberto#define VIAPM_SDA 0x04 /* GPIO2_VAL */ 131181834Sroberto 132181834Sroberto/* 133181834Sroberto * VIAPRO common definitions 134181834Sroberto */ 135181834Sroberto 136181834Sroberto#define VIAPM_PRO_BA_MASK 0x0000fff0 137181834Sroberto#define VIAPM_PRO_SMBCTRL 0xd2 138181834Sroberto#define VIAPM_PRO_REVID 0xd6 139181834Sroberto 140181834Sroberto/* 141181834Sroberto * VT82C686A definitions 142181834Sroberto */ 143 144#define VIAPM_PRO_BASE 0x90 145 146#define SMBHST 0x0 147#define SMBHSL 0x1 148#define SMBHCTRL 0x2 149#define SMBHCMD 0x3 150#define SMBHADDR 0x4 151#define SMBHDATA0 0x5 152#define SMBHDATA1 0x6 153#define SMBHBLOCK 0x7 154 155#define SMBSST 0x1 156#define SMBSCTRL 0x8 157#define SMBSSDWCMD 0x9 158#define SMBSEVENT 0xa 159#define SMBSDATA 0xc 160 161#define SMBHST_RESERVED 0xef /* reserved bits */ 162#define SMBHST_FAILED 0x10 /* failed bus transaction */ 163#define SMBHST_COLLID 0x08 /* bus collision */ 164#define SMBHST_ERROR 0x04 /* device error */ 165#define SMBHST_INTR 0x02 /* command completed */ 166#define SMBHST_BUSY 0x01 /* host busy */ 167 168#define SMBHCTRL_START 0x40 /* start command */ 169#define SMBHCTRL_PROTO 0x1c /* command protocol mask */ 170#define SMBHCTRL_QUICK 0x00 171#define SMBHCTRL_SENDRECV 0x04 172#define SMBHCTRL_BYTE 0x08 173#define SMBHCTRL_WORD 0x0c 174#define SMBHCTRL_BLOCK 0x14 175#define SMBHCTRL_KILL 0x02 /* stop the current transaction */ 176#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */ 177 178#define SMBSCTRL_ENABLE 0x01 /* enable slave */ 179 180 181/* 182 * VIA8233 definitions 183 */ 184 185#define VIAPM_8233_BASE 0xD0 186 187static int 188viapm_586b_probe(device_t dev) 189{ 190 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 191 u_int32_t l; 192 u_int16_t s; 193 u_int8_t c; 194 195 switch (pci_get_devid(dev)) { 196 case VIA_586B_PMU_ID: 197 198 bzero(viapm, sizeof(struct viapm_softc)); 199 200 l = pci_read_config(dev, VIAPM_586B_REVID, 1); 201 switch (l) { 202 case VIAPM_586B_OEM_REV_E: 203 viapm->type = VIAPM_TYP_586B_3040E; 204 viapm->iorid = VIAPM_586B_3040E_BASE; 205 206 /* Activate IO block access */ 207 s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2); 208 pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2); 209 break; 210 211 case VIAPM_586B_OEM_REV_F: 212 case VIAPM_586B_PROD_REV_A: 213 default: 214 viapm->type = VIAPM_TYP_586B_3040F; 215 viapm->iorid = VIAPM_586B_3040F_BASE; 216 217 /* Activate IO block access */ 218 c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1); 219 pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1); 220 break; 221 } 222 223 viapm->base = pci_read_config(dev, viapm->iorid, 4) & 224 VIAPM_586B_BA_MASK; 225 226 /* 227 * We have to set the I/O resources by hand because it is 228 * described outside the viapmope of the traditional maps 229 */ 230 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 231 viapm->base, 256)) { 232 device_printf(dev, "could not set bus resource\n"); 233 return ENXIO; 234 } 235 device_set_desc(dev, "VIA VT82C586B Power Management Unit"); 236 return (BUS_PROBE_DEFAULT); 237 238 default: 239 break; 240 } 241 242 return ENXIO; 243} 244 245 246static int 247viapm_pro_probe(device_t dev) 248{ 249 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 250#ifdef VIAPM_BASE_ADDR 251 u_int32_t l; 252#endif 253 u_int32_t base_cfgreg; 254 char *desc; 255 256 switch (pci_get_devid(dev)) { 257 case VIA_596A_PMU_ID: 258 desc = "VIA VT82C596A Power Management Unit"; 259 viapm->type = VIAPM_TYP_596B; 260 base_cfgreg = VIAPM_PRO_BASE; 261 goto viapro; 262 263 case VIA_596B_PMU_ID: 264 desc = "VIA VT82C596B Power Management Unit"; 265 viapm->type = VIAPM_TYP_596B; 266 base_cfgreg = VIAPM_PRO_BASE; 267 goto viapro; 268 269 case VIA_686A_PMU_ID: 270 desc = "VIA VT82C686A Power Management Unit"; 271 viapm->type = VIAPM_TYP_686A; 272 base_cfgreg = VIAPM_PRO_BASE; 273 goto viapro; 274 275 case VIA_8233_PMU_ID: 276 case VIA_8233A_PMU_ID: 277 desc = "VIA VT8233 Power Management Unit"; 278 viapm->type = VIAPM_TYP_UNKNOWN; 279 base_cfgreg = VIAPM_8233_BASE; 280 goto viapro; 281 282 case VIA_8235_PMU_ID: 283 desc = "VIA VT8235 Power Management Unit"; 284 viapm->type = VIAPM_TYP_UNKNOWN; 285 base_cfgreg = VIAPM_8233_BASE; 286 goto viapro; 287 288 case VIA_CX700_PMU_ID: 289 desc = "VIA CX700 Power Management Unit"; 290 viapm->type = VIAPM_TYP_UNKNOWN; 291 base_cfgreg = VIAPM_8233_BASE; 292 goto viapro; 293 294 viapro: 295 296#ifdef VIAPM_BASE_ADDR 297 /* force VIAPM I/O base address */ 298 299 /* enable the SMBus controller function */ 300 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 301 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 302 303 /* write the base address */ 304 pci_write_config(dev, base_cfgreg, 305 VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4); 306#endif 307 308 viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK; 309 310 /* 311 * We have to set the I/O resources by hand because it is 312 * described outside the viapmope of the traditional maps 313 */ 314 viapm->iorid = base_cfgreg; 315 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 316 viapm->base, 16)) { 317 device_printf(dev, "could not set bus resource 0x%x\n", 318 viapm->base); 319 return ENXIO; 320 } 321 322 if (bootverbose) { 323 device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base); 324 } 325 326 device_set_desc(dev, desc); 327 return (BUS_PROBE_DEFAULT); 328 329 default: 330 break; 331 } 332 333 return ENXIO; 334} 335 336static int 337viapm_pro_attach(device_t dev) 338{ 339 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 340 u_int32_t l; 341 342 mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF); 343 if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 344 &viapm->iorid, RF_ACTIVE))) { 345 device_printf(dev, "could not allocate bus space\n"); 346 goto error; 347 } 348 349#ifdef notyet 350 /* force irq 9 */ 351 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 352 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1); 353 354 viapm->irqrid = 0; 355 if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, 356 &viapm->irqrid, 9, 9, 1, 357 RF_SHAREABLE | RF_ACTIVE))) { 358 device_printf(dev, "could not allocate irq\n"); 359 goto error; 360 } 361 362 if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC | INTR_MPSAFE, 363 (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) { 364 device_printf(dev, "could not setup irq\n"); 365 goto error; 366 } 367#endif 368 369 if (bootverbose) { 370 l = pci_read_config(dev, VIAPM_PRO_REVID, 1); 371 device_printf(dev, "SMBus revision code 0x%x\n", l); 372 } 373 374 viapm->smbus = device_add_child(dev, "smbus", -1); 375 376 /* probe and attach the smbus */ 377 bus_generic_attach(dev); 378 379 /* disable slave function */ 380 VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE); 381 382 /* enable the SMBus controller function */ 383 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 384 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 385 386#ifdef notyet 387 /* enable interrupts */ 388 VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE); 389#endif 390 391#ifdef DEV_ISA 392 /* If this device is a PCI-ISA bridge, then attach an ISA bus. */ 393 if ((pci_get_class(dev) == PCIC_BRIDGE) && 394 (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) 395 isab_attach(dev); 396#endif 397 return 0; 398 399error: 400 if (viapm->iores) 401 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 402#ifdef notyet 403 if (viapm->irqres) 404 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 405#endif 406 mtx_destroy(&viapm->lock); 407 408 return ENXIO; 409} 410 411static int 412viapm_586b_attach(device_t dev) 413{ 414 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 415 416 mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF); 417 if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 418 &viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) { 419 device_printf(dev, "could not allocate bus resource\n"); 420 goto error; 421 } 422 423 VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA); 424 425 /* add generic bit-banging code */ 426 if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1))) 427 goto error; 428 429 bus_generic_attach(dev); 430 431 return 0; 432 433error: 434 if (viapm->iores) 435 bus_release_resource(dev, SYS_RES_IOPORT, 436 viapm->iorid, viapm->iores); 437 mtx_destroy(&viapm->lock); 438 return ENXIO; 439} 440 441static int 442viapm_586b_detach(device_t dev) 443{ 444 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 445 446 bus_generic_detach(dev); 447 if (viapm->iicbb) { 448 device_delete_child(dev, viapm->iicbb); 449 } 450 451 if (viapm->iores) 452 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, 453 viapm->iores); 454 mtx_destroy(&viapm->lock); 455 456 return 0; 457} 458 459static int 460viapm_pro_detach(device_t dev) 461{ 462 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 463 464 bus_generic_detach(dev); 465 if (viapm->smbus) { 466 device_delete_child(dev, viapm->smbus); 467 } 468 469 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 470 471#ifdef notyet 472 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 473#endif 474 mtx_destroy(&viapm->lock); 475 476 return 0; 477} 478 479static int 480viabb_callback(device_t dev, int index, caddr_t *data) 481{ 482 return 0; 483} 484 485static void 486viabb_setscl(device_t dev, int ctrl) 487{ 488 struct viapm_softc *viapm = device_get_softc(dev); 489 u_char val; 490 491 VIAPM_LOCK(viapm); 492 val = VIAPM_INB(GPIO_VAL); 493 494 if (ctrl) 495 val |= VIAPM_SCL; 496 else 497 val &= ~VIAPM_SCL; 498 499 VIAPM_OUTB(GPIO_VAL, val); 500 VIAPM_UNLOCK(viapm); 501 502 return; 503} 504 505static void 506viabb_setsda(device_t dev, int data) 507{ 508 struct viapm_softc *viapm = device_get_softc(dev); 509 u_char val; 510 511 VIAPM_LOCK(viapm); 512 val = VIAPM_INB(GPIO_VAL); 513 514 if (data) 515 val |= VIAPM_SDA; 516 else 517 val &= ~VIAPM_SDA; 518 519 VIAPM_OUTB(GPIO_VAL, val); 520 VIAPM_UNLOCK(viapm); 521 522 return; 523} 524 525static int 526viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 527{ 528 /* reset bus */ 529 viabb_setsda(dev, 1); 530 viabb_setscl(dev, 1); 531 532 return (IIC_ENOADDR); 533} 534 535static int 536viabb_getscl(device_t dev) 537{ 538 struct viapm_softc *viapm = device_get_softc(dev); 539 u_char val; 540 541 VIAPM_LOCK(viapm); 542 val = VIAPM_INB(EXTSMI_VAL); 543 VIAPM_UNLOCK(viapm); 544 return ((val & VIAPM_SCL) != 0); 545} 546 547static int 548viabb_getsda(device_t dev) 549{ 550 struct viapm_softc *viapm = device_get_softc(dev); 551 u_char val; 552 553 VIAPM_LOCK(viapm); 554 val = VIAPM_INB(EXTSMI_VAL); 555 VIAPM_UNLOCK(viapm); 556 return ((val & VIAPM_SDA) != 0); 557} 558 559static int 560viapm_abort(struct viapm_softc *viapm) 561{ 562 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); 563 DELAY(10); 564 565 return (0); 566} 567 568static int 569viapm_clear(struct viapm_softc *viapm) 570{ 571 VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID | 572 SMBHST_ERROR | SMBHST_INTR); 573 DELAY(10); 574 575 return (0); 576} 577 578static int 579viapm_busy(struct viapm_softc *viapm) 580{ 581 u_char sts; 582 583 sts = VIAPM_INB(SMBHST); 584 585 VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts)); 586 587 return (sts & SMBHST_BUSY); 588} 589 590/* 591 * Poll the SMBus controller 592 */ 593static int 594viapm_wait(struct viapm_softc *viapm) 595{ 596 int count = 10000; 597 u_char sts = 0; 598 int error; 599 600 VIAPM_LOCK_ASSERT(viapm); 601 602 /* wait for command to complete and SMBus controller is idle */ 603 while(count--) { 604 DELAY(10); 605 sts = VIAPM_INB(SMBHST); 606 607 /* check if the controller is processing a command */ 608 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) 609 break; 610 } 611 612 VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts)); 613 614 error = SMB_ENOERR; 615 616 if (!count) 617 error |= SMB_ETIMEOUT; 618 619 if (sts & SMBHST_FAILED) 620 error |= SMB_EABORT; 621 622 if (sts & SMBHST_COLLID) 623 error |= SMB_ENOACK; 624 625 if (sts & SMBHST_ERROR) 626 error |= SMB_EBUSERR; 627 628 if (error != SMB_ENOERR) 629 viapm_abort(viapm); 630 631 viapm_clear(viapm); 632 633 return (error); 634} 635 636static int 637viasmb_callback(device_t dev, int index, caddr_t *data) 638{ 639 int error = 0; 640 641 switch (index) { 642 case SMB_REQUEST_BUS: 643 case SMB_RELEASE_BUS: 644 /* ok, bus allocation accepted */ 645 break; 646 default: 647 error = EINVAL; 648 } 649 650 return (error); 651} 652 653static int 654viasmb_quick(device_t dev, u_char slave, int how) 655{ 656 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 657 int error; 658 659 VIAPM_LOCK(viapm); 660 viapm_clear(viapm); 661 if (viapm_busy(viapm)) { 662 VIAPM_UNLOCK(viapm); 663 return (SMB_EBUSY); 664 } 665 666 switch (how) { 667 case SMB_QWRITE: 668 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave)); 669 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 670 break; 671 case SMB_QREAD: 672 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave)); 673 VIAPM_OUTB(SMBHADDR, slave | LSB); 674 break; 675 default: 676 panic("%s: unknown QUICK command (%x)!", __func__, how); 677 } 678 679 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK); 680 681 error = viapm_wait(viapm); 682 VIAPM_UNLOCK(viapm); 683 684 return (error); 685} 686 687static int 688viasmb_sendb(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_LOCK(viapm); 694 viapm_clear(viapm); 695 if (viapm_busy(viapm)) { 696 VIAPM_UNLOCK(viapm); 697 return (SMB_EBUSY); 698 } 699 700 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 701 VIAPM_OUTB(SMBHCMD, byte); 702 703 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 704 705 error = viapm_wait(viapm); 706 707 VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 708 VIAPM_UNLOCK(viapm); 709 710 return (error); 711} 712 713static int 714viasmb_recvb(device_t dev, u_char slave, char *byte) 715{ 716 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 717 int error; 718 719 VIAPM_LOCK(viapm); 720 viapm_clear(viapm); 721 if (viapm_busy(viapm)) { 722 VIAPM_UNLOCK(viapm); 723 return (SMB_EBUSY); 724 } 725 726 VIAPM_OUTB(SMBHADDR, slave | LSB); 727 728 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 729 730 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 731 *byte = VIAPM_INB(SMBHDATA0); 732 733 VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 734 VIAPM_UNLOCK(viapm); 735 736 return (error); 737} 738 739static int 740viasmb_writeb(device_t dev, u_char slave, char cmd, char byte) 741{ 742 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 743 int error; 744 745 VIAPM_LOCK(viapm); 746 viapm_clear(viapm); 747 if (viapm_busy(viapm)) { 748 VIAPM_UNLOCK(viapm); 749 return (SMB_EBUSY); 750 } 751 752 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 753 VIAPM_OUTB(SMBHCMD, cmd); 754 VIAPM_OUTB(SMBHDATA0, byte); 755 756 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 757 758 error = viapm_wait(viapm); 759 760 VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 761 VIAPM_UNLOCK(viapm); 762 763 return (error); 764} 765 766static int 767viasmb_readb(device_t dev, u_char slave, char cmd, char *byte) 768{ 769 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 770 int error; 771 772 VIAPM_LOCK(viapm); 773 viapm_clear(viapm); 774 if (viapm_busy(viapm)) { 775 VIAPM_UNLOCK(viapm); 776 return (SMB_EBUSY); 777 } 778 779 VIAPM_OUTB(SMBHADDR, slave | LSB); 780 VIAPM_OUTB(SMBHCMD, cmd); 781 782 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 783 784 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 785 *byte = VIAPM_INB(SMBHDATA0); 786 787 VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 788 VIAPM_UNLOCK(viapm); 789 790 return (error); 791} 792 793static int 794viasmb_writew(device_t dev, u_char slave, char cmd, short word) 795{ 796 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 797 int error; 798 799 VIAPM_LOCK(viapm); 800 viapm_clear(viapm); 801 if (viapm_busy(viapm)) { 802 VIAPM_UNLOCK(viapm); 803 return (SMB_EBUSY); 804 } 805 806 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 807 VIAPM_OUTB(SMBHCMD, cmd); 808 VIAPM_OUTB(SMBHDATA0, word & 0x00ff); 809 VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8); 810 811 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 812 813 error = viapm_wait(viapm); 814 815 VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 816 VIAPM_UNLOCK(viapm); 817 818 return (error); 819} 820 821static int 822viasmb_readw(device_t dev, u_char slave, char cmd, short *word) 823{ 824 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 825 int error; 826 u_char high, low; 827 828 VIAPM_LOCK(viapm); 829 viapm_clear(viapm); 830 if (viapm_busy(viapm)) { 831 VIAPM_UNLOCK(viapm); 832 return (SMB_EBUSY); 833 } 834 835 VIAPM_OUTB(SMBHADDR, slave | LSB); 836 VIAPM_OUTB(SMBHCMD, cmd); 837 838 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 839 840 if ((error = viapm_wait(viapm)) == SMB_ENOERR) { 841 low = VIAPM_INB(SMBHDATA0); 842 high = VIAPM_INB(SMBHDATA1); 843 844 *word = ((high & 0xff) << 8) | (low & 0xff); 845 } 846 847 VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 848 VIAPM_UNLOCK(viapm); 849 850 return (error); 851} 852 853static int 854viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 855{ 856 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 857 u_char i; 858 int error; 859 860 if (count < 1 || count > 32) 861 return (SMB_EINVAL); 862 863 VIAPM_LOCK(viapm); 864 viapm_clear(viapm); 865 if (viapm_busy(viapm)) { 866 VIAPM_UNLOCK(viapm); 867 return (SMB_EBUSY); 868 } 869 870 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 871 VIAPM_OUTB(SMBHCMD, cmd); 872 VIAPM_OUTB(SMBHDATA0, count); 873 i = VIAPM_INB(SMBHCTRL); 874 875 /* fill the 32-byte internal buffer */ 876 for (i = 0; i < count; i++) { 877 VIAPM_OUTB(SMBHBLOCK, buf[i]); 878 DELAY(2); 879 } 880 VIAPM_OUTB(SMBHCMD, cmd); 881 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 882 883 error = viapm_wait(viapm); 884 885 VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 886 VIAPM_UNLOCK(viapm); 887 888 return (error); 889 890} 891 892static int 893viasmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 894{ 895 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 896 u_char data, len, i; 897 int error; 898 899 if (*count < 1 || *count > 32) 900 return (SMB_EINVAL); 901 902 VIAPM_LOCK(viapm); 903 viapm_clear(viapm); 904 if (viapm_busy(viapm)) { 905 VIAPM_UNLOCK(viapm); 906 return (SMB_EBUSY); 907 } 908 909 VIAPM_OUTB(SMBHADDR, slave | LSB); 910 VIAPM_OUTB(SMBHCMD, cmd); 911 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 912 913 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 914 goto error; 915 916 len = VIAPM_INB(SMBHDATA0); 917 i = VIAPM_INB(SMBHCTRL); /* reset counter */ 918 919 /* read the 32-byte internal buffer */ 920 for (i = 0; i < len; i++) { 921 data = VIAPM_INB(SMBHBLOCK); 922 if (i < *count) 923 buf[i] = data; 924 DELAY(2); 925 } 926 *count = len; 927 928error: 929 VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 930 VIAPM_UNLOCK(viapm); 931 932 return (error); 933} 934 935static device_method_t viapm_methods[] = { 936 /* device interface */ 937 DEVMETHOD(device_probe, viapm_586b_probe), 938 DEVMETHOD(device_attach, viapm_586b_attach), 939 DEVMETHOD(device_detach, viapm_586b_detach), 940 941 /* iicbb interface */ 942 DEVMETHOD(iicbb_callback, viabb_callback), 943 DEVMETHOD(iicbb_setscl, viabb_setscl), 944 DEVMETHOD(iicbb_setsda, viabb_setsda), 945 DEVMETHOD(iicbb_getscl, viabb_getscl), 946 DEVMETHOD(iicbb_getsda, viabb_getsda), 947 DEVMETHOD(iicbb_reset, viabb_reset), 948 949 /* Bus interface */ 950 DEVMETHOD(bus_print_child, bus_generic_print_child), 951 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 952 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 953 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 954 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 955 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 956 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 957 958 { 0, 0 } 959}; 960 961static driver_t viapm_driver = { 962 "viapm", 963 viapm_methods, 964 sizeof(struct viapm_softc), 965}; 966 967static device_method_t viapropm_methods[] = { 968 /* device interface */ 969 DEVMETHOD(device_probe, viapm_pro_probe), 970 DEVMETHOD(device_attach, viapm_pro_attach), 971 DEVMETHOD(device_detach, viapm_pro_detach), 972 973 /* smbus interface */ 974 DEVMETHOD(smbus_callback, viasmb_callback), 975 DEVMETHOD(smbus_quick, viasmb_quick), 976 DEVMETHOD(smbus_sendb, viasmb_sendb), 977 DEVMETHOD(smbus_recvb, viasmb_recvb), 978 DEVMETHOD(smbus_writeb, viasmb_writeb), 979 DEVMETHOD(smbus_readb, viasmb_readb), 980 DEVMETHOD(smbus_writew, viasmb_writew), 981 DEVMETHOD(smbus_readw, viasmb_readw), 982 DEVMETHOD(smbus_bwrite, viasmb_bwrite), 983 DEVMETHOD(smbus_bread, viasmb_bread), 984 985 /* Bus interface */ 986 DEVMETHOD(bus_print_child, bus_generic_print_child), 987 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 988 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 989 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 990 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 991 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 992 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 993 994 { 0, 0 } 995}; 996 997static driver_t viapropm_driver = { 998 "viapropm", 999 viapropm_methods, 1000 sizeof(struct viapm_softc), 1001}; 1002 1003DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); 1004DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); 1005DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0); 1006 1007MODULE_DEPEND(viapm, pci, 1, 1, 1); 1008MODULE_DEPEND(viapropm, pci, 1, 1, 1); 1009MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 1010MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 1011MODULE_VERSION(viapm, 1); 1012 1013#ifdef DEV_ISA 1014DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0); 1015DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0); 1016MODULE_DEPEND(viapm, isa, 1, 1, 1); 1017MODULE_DEPEND(viapropm, isa, 1, 1, 1); 1018#endif 1019