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

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

1.1     ! nbrk        1: /*     $OpenBSD: nviic.c,v 1.11 2007/05/03 09:36:26 dlg Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005 David Gwynne <dlg@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: #include <sys/param.h>
        !            20: #include <sys/systm.h>
        !            21: #include <sys/device.h>
        !            22: #include <sys/kernel.h>
        !            23: #include <sys/rwlock.h>
        !            24: #include <sys/proc.h>
        !            25:
        !            26: #include <machine/bus.h>
        !            27:
        !            28: #include <dev/pci/pcidevs.h>
        !            29: #include <dev/pci/pcireg.h>
        !            30: #include <dev/pci/pcivar.h>
        !            31:
        !            32: #include <dev/i2c/i2cvar.h>
        !            33:
        !            34: /* PCI Configuration space registers */
        !            35: #define NVI_PCI_SMBASE1                0x20
        !            36: #define NVI_PCI_SMBASE2                0x24
        !            37:
        !            38: #define NVI_OLD_PCI_SMBASE1    0x50
        !            39: #define NVI_OLD_PCI_SMBASE2    0x54
        !            40:
        !            41: #define NVI_SMBASE(x)          ((x) & 0xfffc)
        !            42: #define NVI_SMBASE_SIZE                8
        !            43:
        !            44: /* SMBus 2.0 registers */
        !            45: #define NVI_SMB_PRTCL          0x00    /* protocol, PEC */
        !            46: #define NVI_SMB_STS            0x01    /* status */
        !            47: #define NVI_SMB_ADDR           0x02    /* address */
        !            48: #define NVI_SMB_CMD            0x03    /* command */
        !            49: #define NVI_SMB_DATA(o)                (0x04 + (o))    /* 32 data registers */
        !            50: #define NVI_SMB_BCNT           0x24    /* number of data bytes */
        !            51: #define NVI_SMB_ALRM_A         0x25    /* alarm address */
        !            52: #define NVI_SMB_ALRM_D         0x26    /* 2 bytes alarm data */
        !            53:
        !            54: #define NVI_SMB_STS_DONE       0x80
        !            55: #define NVI_SMB_STS_ALRM       0x40
        !            56: #define NVI_SMB_STS_RES                0x20
        !            57: #define NVI_SMB_STS_STATUS     0x1f
        !            58:
        !            59: #define NVI_SMB_PRTCL_WRITE    0x00
        !            60: #define NVI_SMB_PRTCL_READ     0x01
        !            61: #define NVI_SMB_PRTCL_QUICK    0x02
        !            62: #define NVI_SMB_PRTCL_BYTE     0x04
        !            63: #define NVI_SMB_PRTCL_BYTE_DATA        0x06
        !            64: #define NVI_SMB_PRTCL_WORD_DATA        0x08
        !            65: #define NVI_SMB_PRTCL_BLOCK_DATA 0x0a
        !            66: #define NVI_SMB_PRTCL_PROC_CALL        0x0c
        !            67: #define NVI_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
        !            68: #define NVI_SMB_PRTCL_PEC      0x80
        !            69:
        !            70: #ifdef NVIIC_DEBUG
        !            71: #define DPRINTF(x...)          do { if (nviic_debug) printf(x); } while (0)
        !            72: int nviic_debug = 1;
        !            73: #else
        !            74: #define DPRINTF(x...)          /* x */
        !            75: #endif
        !            76:
        !            77: /* there are two iic busses on this pci device */
        !            78: #define NVIIC_NBUS             2
        !            79:
        !            80: int            nviic_match(struct device *, void *, void *);
        !            81: void           nviic_attach(struct device *, struct device *, void *);
        !            82:
        !            83: struct nviic_softc;
        !            84:
        !            85: struct nviic_controller {
        !            86:        struct nviic_softc      *nc_sc;
        !            87:        bus_space_handle_t      nc_ioh;
        !            88:        struct rwlock           nc_lock;
        !            89:        struct i2c_controller   nc_i2c;
        !            90: };
        !            91:
        !            92: struct nviic_softc {
        !            93:        struct device           sc_dev;
        !            94:        bus_space_tag_t         sc_iot;
        !            95:        struct nviic_controller sc_nc[NVIIC_NBUS];
        !            96: };
        !            97:
        !            98: struct cfattach nviic_ca = {
        !            99:        sizeof(struct nviic_softc), nviic_match, nviic_attach
        !           100: };
        !           101:
        !           102: struct cfdriver nviic_cd = {
        !           103:        NULL, "nviic", DV_DULL
        !           104: };
        !           105:
        !           106: int            nviic_i2c_acquire_bus(void *, int);
        !           107: void           nviic_i2c_release_bus(void *, int);
        !           108: int            nviic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
        !           109:                    size_t, void *, size_t, int);
        !           110:
        !           111: u_int8_t       nviic_read(struct nviic_controller *, bus_size_t);
        !           112: void           nviic_write(struct nviic_controller *, bus_size_t, u_int8_t);
        !           113:
        !           114: #define DEVNAME(s)             ((sc)->sc_dev.dv_xname)
        !           115:
        !           116: const struct pci_matchid nviic_ids[] = {
        !           117:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_SMB },
        !           118:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_SMB },
        !           119:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_SMB },
        !           120:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_SMB },
        !           121:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_SMB },
        !           122:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_SMB },
        !           123:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_SMB },
        !           124:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_SMB },
        !           125:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SMB },
        !           126:        { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SMB }
        !           127: };
        !           128:
        !           129: int
        !           130: nviic_match(struct device *parent, void *match, void *aux)
        !           131: {
        !           132:        return (pci_matchbyid(aux, nviic_ids,
        !           133:            sizeof(nviic_ids) / sizeof(nviic_ids[0])));
        !           134: }
        !           135:
        !           136: void
        !           137: nviic_attach(struct device *parent, struct device *self, void *aux)
        !           138: {
        !           139:        struct nviic_softc              *sc = (struct nviic_softc *)self;
        !           140:        struct pci_attach_args          *pa = aux;
        !           141:        struct nviic_controller         *nc;
        !           142:        struct i2cbus_attach_args       iba;
        !           143:        int                             baseregs[NVIIC_NBUS];
        !           144:        pcireg_t                        reg;
        !           145:        int                             i;
        !           146:
        !           147:        sc->sc_iot = pa->pa_iot;
        !           148:
        !           149:        printf("\n");
        !           150:
        !           151:        /* Older chipsets used non-standard BARs */
        !           152:        switch (PCI_PRODUCT(pa->pa_id)) {
        !           153:        case PCI_PRODUCT_NVIDIA_NFORCE2_SMB:
        !           154:        case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMB:
        !           155:        case PCI_PRODUCT_NVIDIA_NFORCE3_SMB:
        !           156:        case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMB:
        !           157:        case PCI_PRODUCT_NVIDIA_NFORCE4_SMB:
        !           158:                baseregs[0] = NVI_OLD_PCI_SMBASE1;
        !           159:                baseregs[1] = NVI_OLD_PCI_SMBASE2;
        !           160:                break;
        !           161:        default:
        !           162:                baseregs[0] = NVI_PCI_SMBASE1;
        !           163:                baseregs[1] = NVI_PCI_SMBASE2;
        !           164:        }
        !           165:
        !           166:        for (i = 0; i < NVIIC_NBUS; i++) {
        !           167:                nc = &sc->sc_nc[i];
        !           168:
        !           169:                reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[i]);
        !           170:                if (NVI_SMBASE(reg) == 0 ||
        !           171:                    bus_space_map(sc->sc_iot, NVI_SMBASE(reg), NVI_SMBASE_SIZE,
        !           172:                    0, &nc->nc_ioh)) {
        !           173:                        printf("%s: unable to map space for bus %d\n",
        !           174:                            DEVNAME(sc), i);
        !           175:                        continue;
        !           176:                }
        !           177:
        !           178:                nc->nc_sc = sc;
        !           179:                rw_init(&nc->nc_lock, "nviic");
        !           180:                nc->nc_i2c.ic_cookie = nc;
        !           181:                nc->nc_i2c.ic_acquire_bus = nviic_i2c_acquire_bus;
        !           182:                nc->nc_i2c.ic_release_bus = nviic_i2c_release_bus;
        !           183:                nc->nc_i2c.ic_exec = nviic_i2c_exec;
        !           184:
        !           185:                bzero(&iba, sizeof(iba));
        !           186:                iba.iba_name = "iic";
        !           187:                iba.iba_tag = &nc->nc_i2c;
        !           188:                config_found(self, &iba, iicbus_print);
        !           189:        }
        !           190: }
        !           191:
        !           192: int
        !           193: nviic_i2c_acquire_bus(void *arg, int flags)
        !           194: {
        !           195:        struct nviic_controller         *nc = arg;
        !           196:
        !           197:        if (cold || (flags & I2C_F_POLL))
        !           198:                return (0);
        !           199:
        !           200:        return (rw_enter(&nc->nc_lock, RW_WRITE | RW_INTR));
        !           201: }
        !           202:
        !           203: void
        !           204: nviic_i2c_release_bus(void *arg, int flags)
        !           205: {
        !           206:        struct nviic_controller         *nc = arg;
        !           207:
        !           208:        if (cold || (flags & I2C_F_POLL))
        !           209:                return;
        !           210:
        !           211:        rw_exit(&nc->nc_lock);
        !           212: }
        !           213:
        !           214: int
        !           215: nviic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
        !           216:     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
        !           217: {
        !           218:        struct nviic_controller         *nc = arg;
        !           219: #ifdef NVIIC_DEBUG
        !           220:        struct nviic_softc              *sc = nc->nc_sc;
        !           221: #endif
        !           222:        u_int8_t                        protocol;
        !           223:        u_int8_t                        *b;
        !           224:        u_int8_t                        sts;
        !           225:        int                             i;
        !           226:
        !           227:        DPRINTF("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
        !           228:            DEVNAME(sc), op, addr, cmdlen, len, flags);
        !           229:
        !           230:        if (cold)
        !           231:                flags |= I2C_F_POLL;
        !           232:
        !           233:        if (I2C_OP_STOP_P(op) == 0 || cmdlen > 1 || len > 2)
        !           234:                return (1);
        !           235:
        !           236:        /* set slave address */
        !           237:        nviic_write(nc, NVI_SMB_ADDR, addr << 1);
        !           238:
        !           239:        /* set command byte */
        !           240:        if (cmdlen > 0) {
        !           241:                b = (u_int8_t *)cmdbuf;
        !           242:                nviic_write(nc, NVI_SMB_CMD, b[0]);
        !           243:        }
        !           244:
        !           245:        b = (u_int8_t *)buf;
        !           246:
        !           247:        /* write data */
        !           248:        if (I2C_OP_WRITE_P(op)) {
        !           249:                for (i = 0; i < len; i++)
        !           250:                        nviic_write(nc, NVI_SMB_DATA(i), b[i]);
        !           251:        }
        !           252:
        !           253:        switch (len) {
        !           254:        case 0:
        !           255:                protocol = NVI_SMB_PRTCL_BYTE;
        !           256:                break;
        !           257:        case 1:
        !           258:                protocol = NVI_SMB_PRTCL_BYTE_DATA;
        !           259:                break;
        !           260:        case 2:
        !           261:                protocol = NVI_SMB_PRTCL_WORD_DATA;
        !           262:                break;
        !           263:        }
        !           264:
        !           265:        /* set direction */
        !           266:        if (I2C_OP_READ_P(op))
        !           267:                protocol |= NVI_SMB_PRTCL_READ;
        !           268:
        !           269:        /* start transaction */
        !           270:        nviic_write(nc, NVI_SMB_PRTCL, protocol);
        !           271:
        !           272:        for (i = 1000; i > 0; i--) {
        !           273:                delay(100);
        !           274:                if (nviic_read(nc, NVI_SMB_PRTCL) == 0)
        !           275:                        break;
        !           276:        }
        !           277:        if (i == 0) {
        !           278:                DPRINTF("%s: timeout\n", DEVNAME(sc));
        !           279:                return (1);
        !           280:        }
        !           281:
        !           282:        sts = nviic_read(nc, NVI_SMB_STS);
        !           283:        if (sts & NVI_SMB_STS_STATUS)
        !           284:                return (1);
        !           285:
        !           286:        /* read data */
        !           287:        if (I2C_OP_READ_P(op)) {
        !           288:                for (i = 0; i < len; i++)
        !           289:                        b[i] = nviic_read(nc, NVI_SMB_DATA(i));
        !           290:        }
        !           291:
        !           292:        return (0);
        !           293: }
        !           294:
        !           295: u_int8_t
        !           296: nviic_read(struct nviic_controller *nc, bus_size_t r)
        !           297: {
        !           298:        struct nviic_softc              *sc = nc->nc_sc;
        !           299:
        !           300:        bus_space_barrier(sc->sc_iot, nc->nc_ioh, r, 1,
        !           301:            BUS_SPACE_BARRIER_READ);
        !           302:        return (bus_space_read_1(sc->sc_iot, nc->nc_ioh, r));
        !           303: }
        !           304:
        !           305: void
        !           306: nviic_write(struct nviic_controller *nc, bus_size_t r, u_int8_t v)
        !           307: {
        !           308:        struct nviic_softc              *sc = nc->nc_sc;
        !           309:
        !           310:        bus_space_write_1(sc->sc_iot, nc->nc_ioh, r, v);
        !           311:        bus_space_barrier(sc->sc_iot, nc->nc_ioh, r, 1,
        !           312:            BUS_SPACE_BARRIER_WRITE);
        !           313: }

CVSweb