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

          Line data    Source code
       1             : /*      $OpenBSD: ichiic.c,v 1.41 2018/04/02 08:39:24 henning Exp $     */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@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             :  * Intel ICH 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             : 
      29             : #include <machine/bus.h>
      30             : 
      31             : #include <dev/pci/pcidevs.h>
      32             : #include <dev/pci/pcireg.h>
      33             : #include <dev/pci/pcivar.h>
      34             : 
      35             : #include <dev/pci/ichreg.h>
      36             : 
      37             : #include <dev/i2c/i2cvar.h>
      38             : 
      39             : #ifdef ICHIIC_DEBUG
      40             : #define DPRINTF(x) printf x
      41             : #else
      42             : #define DPRINTF(x)
      43             : #endif
      44             : 
      45             : #define ICHIIC_DELAY    100
      46             : #define ICHIIC_TIMEOUT  1
      47             : 
      48             : struct ichiic_softc {
      49             :         struct device           sc_dev;
      50             : 
      51             :         bus_space_tag_t         sc_iot;
      52             :         bus_space_handle_t      sc_ioh;
      53             :         void *                  sc_ih;
      54             :         int                     sc_poll;
      55             : 
      56             :         struct i2c_controller   sc_i2c_tag;
      57             :         struct rwlock           sc_i2c_lock;
      58             :         struct {
      59             :                 i2c_op_t     op;
      60             :                 void *       buf;
      61             :                 size_t       len;
      62             :                 int          flags;
      63             :                 volatile int error;
      64             :         }                       sc_i2c_xfer;
      65             : };
      66             : 
      67             : int     ichiic_match(struct device *, void *, void *);
      68             : void    ichiic_attach(struct device *, struct device *, void *);
      69             : 
      70             : int     ichiic_i2c_acquire_bus(void *, int);
      71             : void    ichiic_i2c_release_bus(void *, int);
      72             : int     ichiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
      73             :             void *, size_t, int);
      74             : 
      75             : int     ichiic_intr(void *);
      76             : 
      77             : struct cfattach ichiic_ca = {
      78             :         sizeof(struct ichiic_softc),
      79             :         ichiic_match,
      80             :         ichiic_attach
      81             : };
      82             : 
      83             : struct cfdriver ichiic_cd = {
      84             :         NULL, "ichiic", DV_DULL
      85             : };
      86             : 
      87             : const struct pci_matchid ichiic_ids[] = {
      88             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_SMB },
      89             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6SERIES_SMB },
      90             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_SMB },
      91             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_SMB },
      92             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_7SERIES_SMB },
      93             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_SMB },
      94             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_LP_SMB },
      95             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_SMB },
      96             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_LP_SMB },
      97             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB },
      98             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB },
      99             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB },
     100             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_SMB },
     101             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_SMB },
     102             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_SMB },
     103             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_SMB },
     104             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_SMB },
     105             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_SMB },
     106             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_SMB },
     107             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_SMB },
     108             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JD_SMB },
     109             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JI_SMB },
     110             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_SMB },
     111             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ATOMC2000_PCU_SMB },
     112             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BAYTRAIL_SMB },
     113             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BRASWELL_SMB },
     114             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB },
     115             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_1 },
     116             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_2 },
     117             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_3 },
     118             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_SMB },
     119             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_MS_SMB_1 },
     120             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_MS_SMB_2 },
     121             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_MS_SMB_3 },
     122             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_DH8900_SMB },
     123             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_SMBUS },
     124             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_SMB },
     125             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_SMB },
     126             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_SMB }
     127             : };
     128             : 
     129             : int
     130           0 : ichiic_match(struct device *parent, void *match, void *aux)
     131             : {
     132           0 :         return (pci_matchbyid(aux, ichiic_ids,
     133             :             sizeof(ichiic_ids) / sizeof(ichiic_ids[0])));
     134             : }
     135             : 
     136             : void
     137           0 : ichiic_attach(struct device *parent, struct device *self, void *aux)
     138             : {
     139           0 :         struct ichiic_softc *sc = (struct ichiic_softc *)self;
     140           0 :         struct pci_attach_args *pa = aux;
     141           0 :         struct i2cbus_attach_args iba;
     142             :         pcireg_t conf;
     143           0 :         bus_size_t iosize;
     144           0 :         pci_intr_handle_t ih;
     145             :         const char *intrstr = NULL;
     146             : 
     147             :         /* Read configuration */
     148           0 :         conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
     149             :         DPRINTF((": conf 0x%08x", conf));
     150             : 
     151           0 :         if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
     152           0 :                 printf(": SMBus disabled\n");
     153           0 :                 return;
     154             :         }
     155             : 
     156             :         /* Map I/O space */
     157           0 :         if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
     158           0 :             &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
     159           0 :                 printf(": can't map i/o space\n");
     160           0 :                 return;
     161             :         }
     162             : 
     163           0 :         sc->sc_poll = 1;
     164           0 :         if (conf & ICH_SMB_HOSTC_SMIEN) {
     165             :                 /* No PCI IRQ */
     166           0 :                 printf(": SMI");
     167           0 :         } else {
     168             :                 /* Install interrupt handler */
     169           0 :                 if (pci_intr_map(pa, &ih) == 0) {
     170           0 :                         intrstr = pci_intr_string(pa->pa_pc, ih);
     171           0 :                         sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
     172           0 :                             ichiic_intr, sc, sc->sc_dev.dv_xname);
     173           0 :                         if (sc->sc_ih != NULL) {
     174           0 :                                 printf(": %s", intrstr);
     175           0 :                                 sc->sc_poll = 0;
     176           0 :                         }
     177             :                 }
     178           0 :                 if (sc->sc_poll)
     179           0 :                         printf(": polling");
     180             :         }
     181             : 
     182           0 :         printf("\n");
     183             : 
     184             :         /* Attach I2C bus */
     185           0 :         rw_init(&sc->sc_i2c_lock, "iiclk");
     186           0 :         sc->sc_i2c_tag.ic_cookie = sc;
     187           0 :         sc->sc_i2c_tag.ic_acquire_bus = ichiic_i2c_acquire_bus;
     188           0 :         sc->sc_i2c_tag.ic_release_bus = ichiic_i2c_release_bus;
     189           0 :         sc->sc_i2c_tag.ic_exec = ichiic_i2c_exec;
     190             : 
     191           0 :         bzero(&iba, sizeof(iba));
     192           0 :         iba.iba_name = "iic";
     193           0 :         iba.iba_tag = &sc->sc_i2c_tag;
     194           0 :         config_found(self, &iba, iicbus_print);
     195             : 
     196           0 :         return;
     197           0 : }
     198             : 
     199             : int
     200           0 : ichiic_i2c_acquire_bus(void *cookie, int flags)
     201             : {
     202           0 :         struct ichiic_softc *sc = cookie;
     203             : 
     204           0 :         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
     205           0 :                 return (0);
     206             : 
     207           0 :         return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
     208           0 : }
     209             : 
     210             : void
     211           0 : ichiic_i2c_release_bus(void *cookie, int flags)
     212             : {
     213           0 :         struct ichiic_softc *sc = cookie;
     214             : 
     215           0 :         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
     216           0 :                 return;
     217             : 
     218           0 :         rw_exit(&sc->sc_i2c_lock);
     219           0 : }
     220             : 
     221             : int
     222           0 : ichiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     223             :     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
     224             : {
     225           0 :         struct ichiic_softc *sc = cookie;
     226             :         u_int8_t *b;
     227             :         u_int8_t ctl, st;
     228             :         int retries;
     229             : 
     230             :         DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
     231             :             "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
     232             :             len, flags));
     233             : 
     234             :         /* Wait for bus to be idle */
     235           0 :         for (retries = 100; retries > 0; retries--) {
     236           0 :                 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
     237           0 :                 if (!(st & ICH_SMB_HS_BUSY))
     238             :                         break;
     239           0 :                 DELAY(ICHIIC_DELAY);
     240             :         }
     241             :         DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
     242             :             ICH_SMB_HS_BITS));
     243           0 :         if (st & ICH_SMB_HS_BUSY)
     244           0 :                 return (1);
     245             : 
     246           0 :         if (cold || sc->sc_poll)
     247           0 :                 flags |= I2C_F_POLL;
     248             : 
     249           0 :         if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
     250           0 :                 return (1);
     251             : 
     252             :         /* Setup transfer */
     253           0 :         sc->sc_i2c_xfer.op = op;
     254           0 :         sc->sc_i2c_xfer.buf = buf;
     255           0 :         sc->sc_i2c_xfer.len = len;
     256           0 :         sc->sc_i2c_xfer.flags = flags;
     257           0 :         sc->sc_i2c_xfer.error = 0;
     258             : 
     259             :         /* Set slave address and transfer direction */
     260           0 :         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
     261             :             ICH_SMB_TXSLVA_ADDR(addr) |
     262             :             (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
     263             : 
     264             :         b = (void *)cmdbuf;
     265           0 :         if (cmdlen > 0)
     266             :                 /* Set command byte */
     267           0 :                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
     268             : 
     269           0 :         if (I2C_OP_WRITE_P(op)) {
     270             :                 /* Write data */
     271             :                 b = buf;
     272           0 :                 if (len > 0)
     273           0 :                         bus_space_write_1(sc->sc_iot, sc->sc_ioh,
     274             :                             ICH_SMB_HD0, b[0]);
     275           0 :                 if (len > 1)
     276           0 :                         bus_space_write_1(sc->sc_iot, sc->sc_ioh,
     277             :                             ICH_SMB_HD1, b[1]);
     278             :         }
     279             : 
     280             :         /* Set SMBus command */
     281           0 :         if (len == 0)
     282           0 :                 ctl = ICH_SMB_HC_CMD_BYTE;
     283           0 :         else if (len == 1)
     284           0 :                 ctl = ICH_SMB_HC_CMD_BDATA;
     285           0 :         else if (len == 2)
     286             :                 ctl = ICH_SMB_HC_CMD_WDATA;
     287             :         else
     288           0 :                 panic("%s: unexpected len %zd", __func__, len);
     289             : 
     290           0 :         if ((flags & I2C_F_POLL) == 0)
     291           0 :                 ctl |= ICH_SMB_HC_INTREN;
     292             : 
     293             :         /* Start transaction */
     294           0 :         ctl |= ICH_SMB_HC_START;
     295           0 :         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
     296             : 
     297           0 :         if (flags & I2C_F_POLL) {
     298             :                 /* Poll for completion */
     299           0 :                 DELAY(ICHIIC_DELAY);
     300           0 :                 for (retries = 1000; retries > 0; retries--) {
     301           0 :                         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
     302             :                             ICH_SMB_HS);
     303           0 :                         if ((st & ICH_SMB_HS_BUSY) == 0)
     304             :                                 break;
     305           0 :                         DELAY(ICHIIC_DELAY);
     306             :                 }
     307           0 :                 if (st & ICH_SMB_HS_BUSY)
     308             :                         goto timeout;
     309           0 :                 ichiic_intr(sc);
     310           0 :         } else {
     311             :                 /* Wait for interrupt */
     312           0 :                 if (tsleep(sc, PRIBIO, "ichiic", ICHIIC_TIMEOUT * hz))
     313             :                         goto timeout;
     314             :         }
     315             : 
     316           0 :         if (sc->sc_i2c_xfer.error)
     317           0 :                 return (1);
     318             : 
     319           0 :         return (0);
     320             : 
     321             : timeout:
     322             :         /*
     323             :          * Transfer timeout. Kill the transaction and clear status bits.
     324             :          */
     325           0 :         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
     326             :             ICH_SMB_HC_KILL);
     327           0 :         DELAY(ICHIIC_DELAY);
     328           0 :         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
     329           0 :         if ((st & ICH_SMB_HS_FAILED) == 0)
     330           0 :                 printf("%s: abort failed, status 0x%b\n",
     331           0 :                     sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
     332           0 :         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
     333           0 :         return (1);
     334           0 : }
     335             : 
     336             : int
     337           0 : ichiic_intr(void *arg)
     338             : {
     339           0 :         struct ichiic_softc *sc = arg;
     340             :         u_int8_t st;
     341             :         u_int8_t *b;
     342             :         size_t len;
     343             : 
     344             :         /* Read status */
     345           0 :         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
     346             : 
     347             :         /* Clear status bits */
     348           0 :         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
     349             : 
     350             :         /* XXX Ignore SMBALERT# for now */
     351           0 :         if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
     352             :             ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
     353           0 :             ICH_SMB_HS_BDONE)) == 0)
     354             :                 /* Interrupt was not for us */
     355           0 :                 return (0);
     356             : 
     357             :         DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
     358             :             ICH_SMB_HS_BITS));
     359             : 
     360             :         /* Check for errors */
     361           0 :         if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
     362           0 :                 sc->sc_i2c_xfer.error = 1;
     363           0 :                 goto done;
     364             :         }
     365             : 
     366           0 :         if (st & ICH_SMB_HS_INTR) {
     367           0 :                 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
     368             :                         goto done;
     369             : 
     370             :                 /* Read data */
     371           0 :                 b = sc->sc_i2c_xfer.buf;
     372           0 :                 len = sc->sc_i2c_xfer.len;
     373           0 :                 if (len > 0)
     374           0 :                         b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
     375             :                             ICH_SMB_HD0);
     376           0 :                 if (len > 1)
     377           0 :                         b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
     378             :                             ICH_SMB_HD1);
     379             :         }
     380             : 
     381             : done:
     382           0 :         if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
     383           0 :                 wakeup(sc);
     384           0 :         return (1);
     385           0 : }

Generated by: LCOV version 1.13