[BACK]Return to amdpm.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/amdpm.c, Revision 1.1.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