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

Annotation of sys/dev/pci/viapm.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: viapm.c,v 1.8 2007/05/03 09:36:26 dlg Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005 Mark Kettenis <kettenis@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:  * VIA VT8237 SMBus controller driver.
        !            21:  */
        !            22:
        !            23: #include <sys/param.h>
        !            24: #include <sys/systm.h>
        !            25: #include <sys/device.h>
        !            26: #include <sys/kernel.h>
        !            27: #include <sys/rwlock.h>
        !            28: #include <sys/proc.h>
        !            29:
        !            30: #include <machine/bus.h>
        !            31:
        !            32: #include <dev/pci/pcidevs.h>
        !            33: #include <dev/pci/pcireg.h>
        !            34: #include <dev/pci/pcivar.h>
        !            35:
        !            36: #include <dev/i2c/i2cvar.h>
        !            37:
        !            38: /*
        !            39:  * VIA VT8237 ISA register definitions.
        !            40:  */
        !            41:
        !            42: /* PCI configuration registers */
        !            43: #define VIAPM_SMB_BASE 0xd0            /* SMBus base address */
        !            44: #define VIAPM_SMB_HOSTC        0xd2            /* host configuration */
        !            45: #define VIAPM_SMB_HOSTC_HSTEN  (1 << 0)        /* enable host controller */
        !            46: #define VIAPM_SMB_HOSTC_INTEN  (1 << 1)        /* enable SCI/SMI */
        !            47: #define VIAPM_SMB_HOSTC_SCIEN  (1 << 3)        /* interrupt type (SCI/SMI) */
        !            48:
        !            49: /* SMBus I/O registers */
        !            50: #define VIAPM_SMB_HS   0x00            /* host status */
        !            51: #define VIAPM_SMB_HS_BUSY      (1 << 0)        /* running a command */
        !            52: #define VIAPM_SMB_HS_INTR      (1 << 1)        /* command completed */
        !            53: #define VIAPM_SMB_HS_DEVERR    (1 << 2)        /* command error */
        !            54: #define VIAPM_SMB_HS_BUSERR    (1 << 3)        /* transaction collision */
        !            55: #define VIAPM_SMB_HS_FAILED    (1 << 4)        /* failed bus transaction */
        !            56: #define VIAPM_SMB_HS_INUSE     (1 << 6)        /* bus semaphore */
        !            57: #define VIAPM_SMB_HS_BITS      \
        !            58:   "\020\001BUSY\002INTR\003DEVERR\004BUSERR\005FAILED\007INUSE"
        !            59: #define VIAPM_SMB_HC   0x02            /* host control */
        !            60: #define VIAPM_SMB_HC_INTREN    (1 << 0)        /* enable interrupts */
        !            61: #define VIAPM_SMB_HC_KILL      (1 << 1)        /* kill current transaction */
        !            62: #define VIAPM_SMB_HC_CMD_QUICK (0 << 2)        /* QUICK command */
        !            63: #define VIAPM_SMB_HC_CMD_BYTE  (1 << 2)        /* BYTE command */
        !            64: #define VIAPM_SMB_HC_CMD_BDATA (2 << 2)        /* BYTE DATA command */
        !            65: #define VIAPM_SMB_HC_CMD_WDATA (3 << 2)        /* WORD DATA command */
        !            66: #define VIAPM_SMB_HC_CMD_PCALL (4 << 2)        /* PROCESS CALL command */
        !            67: #define VIAPM_SMB_HC_CMD_BLOCK (5 << 2)        /* BLOCK command */
        !            68: #define VIAPM_SMB_HC_START     (1 << 6)        /* start transaction */
        !            69: #define VIAPM_SMB_HCMD 0x03            /* host command */
        !            70: #define VIAPM_SMB_TXSLVA       0x04            /* transmit slave address */
        !            71: #define VIAPM_SMB_TXSLVA_READ  (1 << 0)        /* read direction */
        !            72: #define VIAPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
        !            73: #define VIAPM_SMB_HD0  0x05            /* host data 0 */
        !            74: #define VIAPM_SMB_HD1  0x06            /* host data 1 */
        !            75: #define VIAPM_SMB_HBDB 0x07            /* host block data byte */
        !            76:
        !            77: #define VIAPM_SMB_SIZE 16
        !            78:
        !            79: #ifdef VIAPM_DEBUG
        !            80: #define DPRINTF(x) printf x
        !            81: #else
        !            82: #define DPRINTF(x)
        !            83: #endif
        !            84:
        !            85: #define VIAPM_DELAY    100
        !            86: #define VIAPM_TIMEOUT  1
        !            87:
        !            88: struct viapm_softc {
        !            89:        struct device           sc_dev;
        !            90:
        !            91:        bus_space_tag_t         sc_iot;
        !            92:        bus_space_handle_t      sc_ioh;
        !            93:        void *                  sc_ih;
        !            94:        int                     sc_poll;
        !            95:
        !            96:        struct i2c_controller   sc_i2c_tag;
        !            97:        struct rwlock           sc_i2c_lock;
        !            98:        struct {
        !            99:                i2c_op_t     op;
        !           100:                void *       buf;
        !           101:                size_t       len;
        !           102:                int          flags;
        !           103:                volatile int error;
        !           104:        }                       sc_i2c_xfer;
        !           105: };
        !           106:
        !           107: int    viapm_match(struct device *, void *, void *);
        !           108: void   viapm_attach(struct device *, struct device *, void *);
        !           109:
        !           110: int    viapm_i2c_acquire_bus(void *, int);
        !           111: void   viapm_i2c_release_bus(void *, int);
        !           112: int    viapm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
        !           113:            void *, size_t, int);
        !           114:
        !           115: int    viapm_intr(void *);
        !           116:
        !           117: struct cfattach viapm_ca = {
        !           118:        sizeof(struct viapm_softc),
        !           119:        viapm_match,
        !           120:        viapm_attach
        !           121: };
        !           122:
        !           123: struct cfdriver viapm_cd = {
        !           124:        NULL, "viapm", DV_DULL
        !           125: };
        !           126:
        !           127: const struct pci_matchid viapm_ids[] = {
        !           128:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA },
        !           129:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA },
        !           130:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA },
        !           131:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA },
        !           132:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA },
        !           133:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_ISA },
        !           134:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_CX700_ISA }
        !           135: };
        !           136:
        !           137: int
        !           138: viapm_match(struct device *parent, void *match, void *aux)
        !           139: {
        !           140:        return (pci_matchbyid(aux, viapm_ids,
        !           141:            sizeof(viapm_ids) / sizeof(viapm_ids[0])));
        !           142: }
        !           143:
        !           144: void
        !           145: viapm_attach(struct device *parent, struct device *self, void *aux)
        !           146: {
        !           147:        struct viapm_softc *sc = (struct viapm_softc *)self;
        !           148:        struct pci_attach_args *pa = aux;
        !           149:        struct i2cbus_attach_args iba;
        !           150:        pcireg_t conf, iobase;
        !           151: #if 0
        !           152:        pci_intr_handle_t ih;
        !           153:        const char *intrstr = NULL;
        !           154: #endif
        !           155:
        !           156:        /* Map I/O space */
        !           157:        sc->sc_iot = pa->pa_iot;
        !           158:        iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_SMB_BASE);
        !           159:        if (iobase == 0 ||
        !           160:            bus_space_map(sc->sc_iot, iobase & 0xfffe,
        !           161:            VIAPM_SMB_SIZE, 0, &sc->sc_ioh)) {
        !           162:                printf(": can't map I/O space\n");
        !           163:                return;
        !           164:        }
        !           165:
        !           166:        /* Read configuration */
        !           167:        conf = (iobase >> 16);
        !           168:        DPRINTF((": conf 0x%x", conf));
        !           169:
        !           170:        if ((conf & VIAPM_SMB_HOSTC_HSTEN) == 0) {
        !           171:                printf(": SMBus host disabled\n");
        !           172:                goto fail;
        !           173:        }
        !           174:
        !           175:        if (conf & VIAPM_SMB_HOSTC_INTEN) {
        !           176:                if (conf & VIAPM_SMB_HOSTC_SCIEN)
        !           177:                        printf(": SCI");
        !           178:                else
        !           179:                        printf(": SMI");
        !           180:                sc->sc_poll = 1;
        !           181:        } else {
        !           182: #if 0
        !           183:                /* Install interrupt handler */
        !           184:                if (pci_intr_map(pa, &ih)) {
        !           185:                        printf(": can't map interrupt\n");
        !           186:                        goto fail;
        !           187:                }
        !           188:                intrstr = pci_intr_string(pa->pa_pc, ih);
        !           189:                sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
        !           190:                    viapm_intr, sc, sc->sc_dev.dv_xname);
        !           191:                if (sc->sc_ih == NULL) {
        !           192:                        printf(": can't establish interrupt");
        !           193:                        if (intrstr != NULL)
        !           194:                                printf(" at %s", intrstr);
        !           195:                        printf("\n");
        !           196:                        goto fail;
        !           197:                }
        !           198:                printf(": %s", intrstr);
        !           199: #endif
        !           200:                sc->sc_poll = 1;
        !           201:        }
        !           202:
        !           203:        printf("\n");
        !           204:
        !           205:        /* Attach I2C bus */
        !           206:        rw_init(&sc->sc_i2c_lock, "iiclk");
        !           207:        sc->sc_i2c_tag.ic_cookie = sc;
        !           208:        sc->sc_i2c_tag.ic_acquire_bus = viapm_i2c_acquire_bus;
        !           209:        sc->sc_i2c_tag.ic_release_bus = viapm_i2c_release_bus;
        !           210:        sc->sc_i2c_tag.ic_exec = viapm_i2c_exec;
        !           211:
        !           212:        bzero(&iba, sizeof iba);
        !           213:        iba.iba_name = "iic";
        !           214:        iba.iba_tag = &sc->sc_i2c_tag;
        !           215:        config_found(self, &iba, iicbus_print);
        !           216:
        !           217:        return;
        !           218:
        !           219: fail:
        !           220:        bus_space_unmap(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_SIZE);
        !           221: }
        !           222:
        !           223: int
        !           224: viapm_i2c_acquire_bus(void *cookie, int flags)
        !           225: {
        !           226:        struct viapm_softc *sc = cookie;
        !           227:
        !           228:        if (cold || sc->sc_poll || (flags & I2C_F_POLL))
        !           229:                return (0);
        !           230:
        !           231:        return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
        !           232: }
        !           233:
        !           234: void
        !           235: viapm_i2c_release_bus(void *cookie, int flags)
        !           236: {
        !           237:        struct viapm_softc *sc = cookie;
        !           238:
        !           239:        if (cold || sc->sc_poll || (flags & I2C_F_POLL))
        !           240:                return;
        !           241:
        !           242:        rw_exit(&sc->sc_i2c_lock);
        !           243: }
        !           244:
        !           245: int
        !           246: viapm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
        !           247:     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
        !           248: {
        !           249:        struct viapm_softc *sc = cookie;
        !           250:        u_int8_t *b;
        !           251:        u_int8_t ctl, st;
        !           252:        int retries;
        !           253:
        !           254:        DPRINTF(("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
        !           255:            "flags 0x%x, status 0x%b\n", sc->sc_dev.dv_xname, op, addr,
        !           256:            cmdlen, len, flags, bus_space_read_1(sc->sc_iot, sc->sc_ioh,
        !           257:            VIAPM_SMB_HS), VIAPM_SMB_HS_BITS));
        !           258:
        !           259:        /* Check if there's a transfer already running */
        !           260:        st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS);
        !           261:        DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
        !           262:            VIAPM_SMB_HS_BITS));
        !           263:        if (st & VIAPM_SMB_HS_BUSY)
        !           264:                return (1);
        !           265:
        !           266:        if (cold || sc->sc_poll)
        !           267:                flags |= I2C_F_POLL;
        !           268:
        !           269:        if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
        !           270:                return (1);
        !           271:
        !           272:        /* Setup transfer */
        !           273:        sc->sc_i2c_xfer.op = op;
        !           274:        sc->sc_i2c_xfer.buf = buf;
        !           275:        sc->sc_i2c_xfer.len = len;
        !           276:        sc->sc_i2c_xfer.flags = flags;
        !           277:        sc->sc_i2c_xfer.error = 0;
        !           278:
        !           279:        /* Set slave address and transfer direction */
        !           280:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_TXSLVA,
        !           281:            VIAPM_SMB_TXSLVA_ADDR(addr) |
        !           282:            (I2C_OP_READ_P(op) ? VIAPM_SMB_TXSLVA_READ : 0));
        !           283:
        !           284:        b = (void *)cmdbuf;
        !           285:        if (cmdlen > 0)
        !           286:                /* Set command byte */
        !           287:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
        !           288:                    VIAPM_SMB_HCMD, b[0]);
        !           289:
        !           290:        if (I2C_OP_WRITE_P(op)) {
        !           291:                /* Write data */
        !           292:                b = buf;
        !           293:                if (len > 0)
        !           294:                        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
        !           295:                            VIAPM_SMB_HD0, b[0]);
        !           296:                if (len > 1)
        !           297:                        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
        !           298:                            VIAPM_SMB_HD1, b[1]);
        !           299:        }
        !           300:
        !           301:        /* Set SMBus command */
        !           302:        if (len == 0)
        !           303:                ctl = VIAPM_SMB_HC_CMD_BYTE;
        !           304:        else if (len == 1)
        !           305:                ctl = VIAPM_SMB_HC_CMD_BDATA;
        !           306:        else if (len == 2)
        !           307:                ctl = VIAPM_SMB_HC_CMD_WDATA;
        !           308:
        !           309:        if ((flags & I2C_F_POLL) == 0)
        !           310:                ctl |= VIAPM_SMB_HC_INTREN;
        !           311:
        !           312:        /* Start transaction */
        !           313:        ctl |= VIAPM_SMB_HC_START;
        !           314:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HC, ctl);
        !           315:
        !           316:        if (flags & I2C_F_POLL) {
        !           317:                /* Poll for completion */
        !           318:                DELAY(VIAPM_DELAY);
        !           319:                for (retries = 1000; retries > 0; retries--) {
        !           320:                        st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
        !           321:                            VIAPM_SMB_HS);
        !           322:                        if ((st & VIAPM_SMB_HS_BUSY) == 0)
        !           323:                                break;
        !           324:                        DELAY(VIAPM_DELAY);
        !           325:                }
        !           326:                if (st & VIAPM_SMB_HS_BUSY)
        !           327:                        goto timeout;
        !           328:                viapm_intr(sc);
        !           329:        } else {
        !           330:                /* Wait for interrupt */
        !           331:                if (tsleep(sc, PRIBIO, "iicexec", VIAPM_TIMEOUT * hz))
        !           332:                        goto timeout;
        !           333:        }
        !           334:
        !           335:        if (sc->sc_i2c_xfer.error)
        !           336:                return (1);
        !           337:
        !           338:        return (0);
        !           339:
        !           340: timeout:
        !           341:        /*
        !           342:         * Transfer timeout. Kill the transaction and clear status bits.
        !           343:         */
        !           344:        printf("%s: timeout, status 0x%b\n", sc->sc_dev.dv_xname, st,
        !           345:            VIAPM_SMB_HS_BITS);
        !           346:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HC,
        !           347:            VIAPM_SMB_HC_KILL);
        !           348:        DELAY(VIAPM_DELAY);
        !           349:        st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS);
        !           350:        if ((st & VIAPM_SMB_HS_FAILED) == 0)
        !           351:                printf("%s: transaction abort failed, status 0x%b\n",
        !           352:                    sc->sc_dev.dv_xname, st, VIAPM_SMB_HS_BITS);
        !           353:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS, st);
        !           354:        return (1);
        !           355: }
        !           356:
        !           357: int
        !           358: viapm_intr(void *arg)
        !           359: {
        !           360:        struct viapm_softc *sc = arg;
        !           361:        u_int8_t st;
        !           362:        u_int8_t *b;
        !           363:        size_t len;
        !           364:
        !           365:        /* Read status */
        !           366:        st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS);
        !           367:        if ((st & VIAPM_SMB_HS_BUSY) != 0 || (st & (VIAPM_SMB_HS_INTR |
        !           368:            VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
        !           369:            VIAPM_SMB_HS_FAILED)) == 0)
        !           370:                /* Interrupt was not for us */
        !           371:                return (0);
        !           372:
        !           373:        DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
        !           374:            VIAPM_SMB_HS_BITS));
        !           375:
        !           376:        /* Clear status bits */
        !           377:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS, st);
        !           378:
        !           379:        /* Check for errors */
        !           380:        if (st & (VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
        !           381:            VIAPM_SMB_HS_FAILED)) {
        !           382:                sc->sc_i2c_xfer.error = 1;
        !           383:                goto done;
        !           384:        }
        !           385:
        !           386:        if (st & VIAPM_SMB_HS_INTR) {
        !           387:                if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
        !           388:                        goto done;
        !           389:
        !           390:                /* Read data */
        !           391:                b = sc->sc_i2c_xfer.buf;
        !           392:                len = sc->sc_i2c_xfer.len;
        !           393:                if (len > 0)
        !           394:                        b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
        !           395:                            VIAPM_SMB_HD0);
        !           396:                if (len > 1)
        !           397:                        b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
        !           398:                            VIAPM_SMB_HD1);
        !           399:        }
        !           400:
        !           401: done:
        !           402:        if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
        !           403:                wakeup(sc);
        !           404:        return (1);
        !           405: }

CVSweb