[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

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