root/dev/pci/nviic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nviic_match
  2. nviic_attach
  3. nviic_i2c_acquire_bus
  4. nviic_i2c_release_bus
  5. nviic_i2c_exec
  6. nviic_read
  7. nviic_write

    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 }

/* [<][>][^][v][top][bottom][index][help] */