LCOV - code coverage report
Current view: top level - dev/pci - nviic.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 91 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13