Annotation of sys/dev/pci/amdpm.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: amdpm.c,v 1.21 2007/05/03 09:36:26 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*-
! 20: * Copyright (c) 2002 The NetBSD Foundation, Inc.
! 21: * All rights reserved.
! 22: *
! 23: * This code is derived from software contributed to The NetBSD Foundation
! 24: * by Enami Tsugutomo.
! 25: *
! 26: * Redistribution and use in source and binary forms, with or without
! 27: * modification, are permitted provided that the following conditions
! 28: * are met:
! 29: * 1. Redistributions of source code must retain the above copyright
! 30: * notice, this list of conditions and the following disclaimer.
! 31: * 2. Redistributions in binary form must reproduce the above copyright
! 32: * notice, this list of conditions and the following disclaimer in the
! 33: * documentation and/or other materials provided with the distribution.
! 34: * 3. All advertising materials mentioning features or use of this software
! 35: * must display the following acknowledgement:
! 36: * This product includes software developed by the NetBSD
! 37: * Foundation, Inc. and its contributors.
! 38: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 39: * contributors may be used to endorse or promote products derived
! 40: * from this software without specific prior written permission.
! 41: *
! 42: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 43: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 44: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 45: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 46: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 47: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 48: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 49: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 50: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 51: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 52: * POSSIBILITY OF SUCH DAMAGE.
! 53: */
! 54:
! 55: #include <sys/param.h>
! 56: #include <sys/systm.h>
! 57: #include <sys/device.h>
! 58: #include <sys/kernel.h>
! 59: #include <sys/rwlock.h>
! 60: #include <sys/proc.h>
! 61: #include <sys/timeout.h>
! 62: #ifdef __HAVE_TIMECOUNTER
! 63: #include <sys/timetc.h>
! 64: #endif
! 65:
! 66: #include <machine/bus.h>
! 67:
! 68: #include <dev/pci/pcivar.h>
! 69: #include <dev/pci/pcireg.h>
! 70: #include <dev/pci/pcidevs.h>
! 71:
! 72: #include <dev/rndvar.h>
! 73: #include <dev/i2c/i2cvar.h>
! 74:
! 75: #ifdef AMDPM_DEBUG
! 76: #define DPRINTF(x...) printf(x)
! 77: #else
! 78: #define DPRINTF(x...)
! 79: #endif
! 80:
! 81: #define AMDPM_SMBUS_DELAY 100
! 82: #define AMDPM_SMBUS_TIMEOUT 1
! 83:
! 84: #ifdef __HAVE_TIMECOUNTER
! 85: u_int amdpm_get_timecount(struct timecounter *tc);
! 86:
! 87: #ifndef AMDPM_FREQUENCY
! 88: #define AMDPM_FREQUENCY 3579545
! 89: #endif
! 90:
! 91: static struct timecounter amdpm_timecounter = {
! 92: amdpm_get_timecount, /* get_timecount */
! 93: 0, /* no poll_pps */
! 94: 0xffffff, /* counter_mask */
! 95: AMDPM_FREQUENCY, /* frequency */
! 96: "AMDPM", /* name */
! 97: 1000 /* quality */
! 98: };
! 99: #endif
! 100:
! 101: #define AMDPM_CONFREG 0x40
! 102:
! 103: /* 0x40: General Configuration 1 Register */
! 104: #define AMDPM_RNGEN 0x00000080 /* random number generator enable */
! 105: #define AMDPM_STOPTMR 0x00000040 /* stop free-running timer */
! 106:
! 107: /* 0x41: General Configuration 2 Register */
! 108: #define AMDPM_PMIOEN 0x00008000 /* system management IO space enable */
! 109: #define AMDPM_TMRRST 0x00004000 /* reset free-running timer */
! 110: #define AMDPM_TMR32 0x00000800 /* extended (32 bit) timer enable */
! 111:
! 112: /* 0x42: SCI Interrupt Configuration Register */
! 113: /* 0x43: Previous Power State Register */
! 114:
! 115: #define AMDPM_PMPTR 0x58 /* PMxx System Management IO space
! 116: Pointer */
! 117: #define NFPM_PMPTR 0x14 /* nForce System Management IO space
! 118: POinter */
! 119: #define AMDPM_PMBASE(x) ((x) & 0xff00) /* PMxx base address */
! 120: #define AMDPM_PMSIZE 256 /* PMxx space size */
! 121:
! 122: /* Registers in PMxx space */
! 123: #define AMDPM_TMR 0x08 /* 24/32 bit timer register */
! 124:
! 125: #define AMDPM_RNGDATA 0xf0 /* 32 bit random data register */
! 126: #define AMDPM_RNGSTAT 0xf4 /* RNG status register */
! 127: #define AMDPM_RNGDONE 0x00000001 /* Random number generation complete */
! 128:
! 129: #define AMDPM_SMB_REGS 0xe0 /* offset of SMB register space */
! 130: #define AMDPM_SMB_SIZE 0xf /* size of SMB register space */
! 131: #define AMDPM_SMBSTAT 0x0 /* SMBus status */
! 132: #define AMDPM_SMBSTAT_ABRT (1 << 0) /* transfer abort */
! 133: #define AMDPM_SMBSTAT_COL (1 << 1) /* collision */
! 134: #define AMDPM_SMBSTAT_PRERR (1 << 2) /* protocol error */
! 135: #define AMDPM_SMBSTAT_HBSY (1 << 3) /* host controller busy */
! 136: #define AMDPM_SMBSTAT_CYC (1 << 4) /* cycle complete */
! 137: #define AMDPM_SMBSTAT_TO (1 << 5) /* timeout */
! 138: #define AMDPM_SMBSTAT_SNP (1 << 8) /* snoop address match */
! 139: #define AMDPM_SMBSTAT_SLV (1 << 9) /* slave address match */
! 140: #define AMDPM_SMBSTAT_SMBA (1 << 10) /* SMBALERT# asserted */
! 141: #define AMDPM_SMBSTAT_BSY (1 << 11) /* bus busy */
! 142: #define AMDPM_SMBSTAT_BITS "\020\001ABRT\002COL\003PRERR\004HBSY\005CYC\006TO\011SNP\012SLV\013SMBA\014BSY"
! 143: #define AMDPM_SMBCTL 0x2 /* SMBus control */
! 144: #define AMDPM_SMBCTL_CMD_QUICK 0 /* QUICK command */
! 145: #define AMDPM_SMBCTL_CMD_BYTE 1 /* BYTE command */
! 146: #define AMDPM_SMBCTL_CMD_BDATA 2 /* BYTE DATA command */
! 147: #define AMDPM_SMBCTL_CMD_WDATA 3 /* WORD DATA command */
! 148: #define AMDPM_SMBCTL_CMD_PCALL 4 /* PROCESS CALL command */
! 149: #define AMDPM_SMBCTL_CMD_BLOCK 5 /* BLOCK command */
! 150: #define AMDPM_SMBCTL_START (1 << 3) /* start transfer */
! 151: #define AMDPM_SMBCTL_CYCEN (1 << 4) /* intr on cycle complete */
! 152: #define AMDPM_SMBCTL_ABORT (1 << 5) /* abort transfer */
! 153: #define AMDPM_SMBCTL_SNPEN (1 << 8) /* intr on snoop addr match */
! 154: #define AMDPM_SMBCTL_SLVEN (1 << 9) /* intr on slave addr match */
! 155: #define AMDPM_SMBCTL_SMBAEN (1 << 10) /* intr on SMBALERT# */
! 156: #define AMDPM_SMBADDR 0x4 /* SMBus address */
! 157: #define AMDPM_SMBADDR_READ (1 << 0) /* read direction */
! 158: #define AMDPM_SMBADDR_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
! 159: #define AMDPM_SMBDATA 0x6 /* SMBus data */
! 160: #define AMDPM_SMBCMD 0x8 /* SMBus command */
! 161:
! 162:
! 163: struct amdpm_softc {
! 164: struct device sc_dev;
! 165:
! 166: pci_chipset_tag_t sc_pc;
! 167: pcitag_t sc_tag;
! 168:
! 169: bus_space_tag_t sc_iot;
! 170: bus_space_handle_t sc_ioh; /* PMxx space */
! 171: bus_space_handle_t sc_i2c_ioh; /* I2C space */
! 172: int sc_poll;
! 173:
! 174: struct timeout sc_rnd_ch;
! 175:
! 176: struct i2c_controller sc_i2c_tag;
! 177: struct rwlock sc_i2c_lock;
! 178: struct {
! 179: i2c_op_t op;
! 180: void *buf;
! 181: size_t len;
! 182: int flags;
! 183: volatile int error;
! 184: } sc_i2c_xfer;
! 185: };
! 186:
! 187: int amdpm_match(struct device *, void *, void *);
! 188: void amdpm_attach(struct device *, struct device *, void *);
! 189: void amdpm_rnd_callout(void *);
! 190:
! 191: int amdpm_i2c_acquire_bus(void *, int);
! 192: void amdpm_i2c_release_bus(void *, int);
! 193: int amdpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
! 194: void *, size_t, int);
! 195:
! 196: int amdpm_intr(void *);
! 197:
! 198: struct cfattach amdpm_ca = {
! 199: sizeof(struct amdpm_softc), amdpm_match, amdpm_attach
! 200: };
! 201:
! 202: struct cfdriver amdpm_cd = {
! 203: NULL, "amdpm", DV_DULL
! 204: };
! 205:
! 206: const struct pci_matchid amdpm_ids[] = {
! 207: { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC },
! 208: { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC },
! 209: { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC },
! 210: { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_PMC },
! 211: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_SMB }
! 212: };
! 213:
! 214: int
! 215: amdpm_match(struct device *parent, void *match, void *aux)
! 216: {
! 217: return (pci_matchbyid(aux, amdpm_ids,
! 218: sizeof(amdpm_ids) / sizeof(amdpm_ids[0])));
! 219: }
! 220:
! 221: void
! 222: amdpm_attach(struct device *parent, struct device *self, void *aux)
! 223: {
! 224: struct amdpm_softc *sc = (struct amdpm_softc *) self;
! 225: struct pci_attach_args *pa = aux;
! 226: struct i2cbus_attach_args iba;
! 227: pcireg_t cfg_reg, reg;
! 228: int i;
! 229:
! 230: sc->sc_pc = pa->pa_pc;
! 231: sc->sc_tag = pa->pa_tag;
! 232: sc->sc_iot = pa->pa_iot;
! 233: sc->sc_poll = 1; /* XXX */
! 234:
! 235:
! 236: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD) {
! 237: cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_CONFREG);
! 238: if ((cfg_reg & AMDPM_PMIOEN) == 0) {
! 239: printf(": PMxx space isn't enabled\n");
! 240: return;
! 241: }
! 242:
! 243: reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_PMPTR);
! 244: if (AMDPM_PMBASE(reg) == 0 ||
! 245: bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_PMSIZE,
! 246: 0, &sc->sc_ioh)) {
! 247: printf("\n");
! 248: return;
! 249: }
! 250: if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, AMDPM_SMB_REGS,
! 251: AMDPM_SMB_SIZE, &sc->sc_i2c_ioh)) {
! 252: printf(": failed to map I2C subregion\n");
! 253: return;
! 254: }
! 255:
! 256: #ifdef __HAVE_TIMECOUNTER
! 257: if ((cfg_reg & AMDPM_TMRRST) == 0 &&
! 258: (cfg_reg & AMDPM_STOPTMR) == 0 &&
! 259: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC) {
! 260: printf(": %d-bit timer at %dHz",
! 261: (cfg_reg & AMDPM_TMR32) ? 32 : 24,
! 262: amdpm_timecounter.tc_frequency);
! 263:
! 264: amdpm_timecounter.tc_priv = sc;
! 265: if (cfg_reg & AMDPM_TMR32)
! 266: amdpm_timecounter.tc_counter_mask = 0xffffffffu;
! 267: tc_init(&amdpm_timecounter);
! 268: }
! 269: #endif
! 270: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
! 271: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC) {
! 272: if ((cfg_reg & AMDPM_RNGEN) ==0) {
! 273: pci_conf_write(pa->pa_pc, pa->pa_tag,
! 274: AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
! 275: cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
! 276: AMDPM_CONFREG);
! 277: }
! 278: if (cfg_reg & AMDPM_RNGEN) {
! 279: /* Check to see if we can read data from the RNG. */
! 280: (void) bus_space_read_4(sc->sc_iot, sc->sc_ioh,
! 281: AMDPM_RNGDATA);
! 282: for (i = 1000; i--; ) {
! 283: if (bus_space_read_1(sc->sc_iot,
! 284: sc->sc_ioh, AMDPM_RNGSTAT) &
! 285: AMDPM_RNGDONE)
! 286: break;
! 287: DELAY(10);
! 288: }
! 289: if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
! 290: AMDPM_RNGSTAT) & AMDPM_RNGDONE) {
! 291: printf(": rng active");
! 292: timeout_set(&sc->sc_rnd_ch,
! 293: amdpm_rnd_callout, sc);
! 294: amdpm_rnd_callout(sc);
! 295: }
! 296: }
! 297: }
! 298: } else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
! 299: reg = pci_conf_read(pa->pa_pc, pa->pa_tag, NFPM_PMPTR);
! 300: if (AMDPM_PMBASE(reg) == 0 ||
! 301: bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_SMB_SIZE, 0,
! 302: &sc->sc_i2c_ioh)) {
! 303: printf(": failed to map I2C subregion\n");
! 304: return;
! 305: }
! 306: }
! 307: printf("\n");
! 308:
! 309: /* Attach I2C bus */
! 310: rw_init(&sc->sc_i2c_lock, "iiclk");
! 311: sc->sc_i2c_tag.ic_cookie = sc;
! 312: sc->sc_i2c_tag.ic_acquire_bus = amdpm_i2c_acquire_bus;
! 313: sc->sc_i2c_tag.ic_release_bus = amdpm_i2c_release_bus;
! 314: sc->sc_i2c_tag.ic_exec = amdpm_i2c_exec;
! 315:
! 316: bzero(&iba, sizeof(iba));
! 317: iba.iba_name = "iic";
! 318: iba.iba_tag = &sc->sc_i2c_tag;
! 319: config_found(self, &iba, iicbus_print);
! 320: }
! 321:
! 322: void
! 323: amdpm_rnd_callout(void *v)
! 324: {
! 325: struct amdpm_softc *sc = v;
! 326: u_int32_t reg;
! 327:
! 328: if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
! 329: AMDPM_RNGDONE) != 0) {
! 330: reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGDATA);
! 331: add_true_randomness(reg);
! 332: }
! 333: timeout_add(&sc->sc_rnd_ch, 1);
! 334: }
! 335:
! 336: #ifdef __HAVE_TIMECOUNTER
! 337: u_int
! 338: amdpm_get_timecount(struct timecounter *tc)
! 339: {
! 340: struct amdpm_softc *sc = tc->tc_priv;
! 341: u_int u2;
! 342: #if 0
! 343: u_int u1, u3;
! 344: #endif
! 345:
! 346: u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
! 347: #if 0
! 348: u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
! 349: do {
! 350: u1 = u2;
! 351: u2 = u3;
! 352: u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
! 353: } while (u1 > u2 || u2 > u3);
! 354: #endif
! 355: return (u2);
! 356: }
! 357: #endif
! 358:
! 359: int
! 360: amdpm_i2c_acquire_bus(void *cookie, int flags)
! 361: {
! 362: struct amdpm_softc *sc = cookie;
! 363:
! 364: if (cold || sc->sc_poll || (flags & I2C_F_POLL))
! 365: return (0);
! 366:
! 367: return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
! 368: }
! 369:
! 370: void
! 371: amdpm_i2c_release_bus(void *cookie, int flags)
! 372: {
! 373: struct amdpm_softc *sc = cookie;
! 374:
! 375: if (cold || sc->sc_poll || (flags & I2C_F_POLL))
! 376: return;
! 377:
! 378: rw_exit(&sc->sc_i2c_lock);
! 379: }
! 380:
! 381: int
! 382: amdpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
! 383: const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
! 384: {
! 385: struct amdpm_softc *sc = cookie;
! 386: u_int8_t *b;
! 387: u_int16_t st, ctl, data;
! 388: int retries;
! 389:
! 390: DPRINTF("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
! 391: "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
! 392: len, flags);
! 393:
! 394: /* Wait for bus to be idle */
! 395: for (retries = 100; retries > 0; retries--) {
! 396: st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
! 397: if (!(st & AMDPM_SMBSTAT_BSY))
! 398: break;
! 399: DELAY(AMDPM_SMBUS_DELAY);
! 400: }
! 401: DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
! 402: AMDPM_SMBSTAT_BITS);
! 403: if (st & AMDPM_SMBSTAT_BSY)
! 404: return (1);
! 405:
! 406: if (cold || sc->sc_poll)
! 407: flags |= I2C_F_POLL;
! 408:
! 409: if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
! 410: return (1);
! 411:
! 412: /* Setup transfer */
! 413: sc->sc_i2c_xfer.op = op;
! 414: sc->sc_i2c_xfer.buf = buf;
! 415: sc->sc_i2c_xfer.len = len;
! 416: sc->sc_i2c_xfer.flags = flags;
! 417: sc->sc_i2c_xfer.error = 0;
! 418:
! 419: /* Set slave address and transfer direction */
! 420: bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR,
! 421: AMDPM_SMBADDR_ADDR(addr) |
! 422: (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0));
! 423:
! 424: b = (void *)cmdbuf;
! 425: if (cmdlen > 0)
! 426: /* Set command byte */
! 427: bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]);
! 428:
! 429: if (I2C_OP_WRITE_P(op)) {
! 430: /* Write data */
! 431: data = 0;
! 432: b = buf;
! 433: if (len > 0)
! 434: data = b[0];
! 435: if (len > 1)
! 436: data |= ((u_int16_t)b[1] << 8);
! 437: if (len > 0)
! 438: bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh,
! 439: AMDPM_SMBDATA, data);
! 440: }
! 441:
! 442: /* Set SMBus command */
! 443: if (len == 0)
! 444: ctl = AMDPM_SMBCTL_CMD_BYTE;
! 445: else if (len == 1)
! 446: ctl = AMDPM_SMBCTL_CMD_BDATA;
! 447: else if (len == 2)
! 448: ctl = AMDPM_SMBCTL_CMD_WDATA;
! 449:
! 450: if ((flags & I2C_F_POLL) == 0)
! 451: ctl |= AMDPM_SMBCTL_CYCEN;
! 452:
! 453: /* Start transaction */
! 454: ctl |= AMDPM_SMBCTL_START;
! 455: bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl);
! 456:
! 457: if (flags & I2C_F_POLL) {
! 458: /* Poll for completion */
! 459: DELAY(AMDPM_SMBUS_DELAY);
! 460: for (retries = 1000; retries > 0; retries--) {
! 461: st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
! 462: AMDPM_SMBSTAT);
! 463: if ((st & AMDPM_SMBSTAT_HBSY) == 0)
! 464: break;
! 465: DELAY(AMDPM_SMBUS_DELAY);
! 466: }
! 467: if (st & AMDPM_SMBSTAT_HBSY)
! 468: goto timeout;
! 469: amdpm_intr(sc);
! 470: } else {
! 471: /* Wait for interrupt */
! 472: if (tsleep(sc, PRIBIO, "iicexec", AMDPM_SMBUS_TIMEOUT * hz))
! 473: goto timeout;
! 474: }
! 475:
! 476: if (sc->sc_i2c_xfer.error)
! 477: return (1);
! 478:
! 479: return (0);
! 480:
! 481: timeout:
! 482: /*
! 483: * Transfer timeout. Kill the transaction and clear status bits.
! 484: */
! 485: printf("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
! 486: "flags 0x%02x: timeout, status 0x%b\n",
! 487: sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
! 488: st, AMDPM_SMBSTAT_BITS);
! 489: bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL,
! 490: AMDPM_SMBCTL_ABORT);
! 491: DELAY(AMDPM_SMBUS_DELAY);
! 492: st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
! 493: if ((st & AMDPM_SMBSTAT_ABRT) == 0)
! 494: printf("%s: abort failed, status 0x%b\n",
! 495: sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS);
! 496: bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
! 497: return (1);
! 498: }
! 499:
! 500: int
! 501: amdpm_intr(void *arg)
! 502: {
! 503: struct amdpm_softc *sc = arg;
! 504: u_int16_t st, data;
! 505: u_int8_t *b;
! 506: size_t len;
! 507:
! 508: /* Read status */
! 509: st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
! 510: if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT |
! 511: AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC |
! 512: AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV |
! 513: AMDPM_SMBSTAT_SMBA)) == 0)
! 514: /* Interrupt was not for us */
! 515: return (0);
! 516:
! 517: DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st,
! 518: AMDPM_SMBSTAT_BITS);
! 519:
! 520: /* Clear status bits */
! 521: bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
! 522:
! 523: /* Check for errors */
! 524: if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR |
! 525: AMDPM_SMBSTAT_TO)) {
! 526: sc->sc_i2c_xfer.error = 1;
! 527: goto done;
! 528: }
! 529:
! 530: if (st & AMDPM_SMBSTAT_CYC) {
! 531: if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
! 532: goto done;
! 533:
! 534: /* Read data */
! 535: b = sc->sc_i2c_xfer.buf;
! 536: len = sc->sc_i2c_xfer.len;
! 537: if (len > 0) {
! 538: data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
! 539: AMDPM_SMBDATA);
! 540: b[0] = data & 0xff;
! 541: }
! 542: if (len > 1)
! 543: b[1] = (data >> 8) & 0xff;
! 544: }
! 545:
! 546: done:
! 547: if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
! 548: wakeup(sc);
! 549: return (1);
! 550: }
CVSweb