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

          Line data    Source code
       1             : /*      $OpenBSD: amdpm.c,v 1.33 2018/04/28 15:44:59 jasper Exp $       */
       2             : 
       3             : /*
       4             :  * Copyright (c) 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             :  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      21             :  * All rights reserved.
      22             :  *
      23             :  * This code is derived from software contributed to The NetBSD Foundation
      24             :  * by Enami Tsugutomo.
      25             :  *
      26             :  * Redistribution and use in source and binary forms, with or without
      27             :  * modification, are permitted provided that the following conditions
      28             :  * are met:
      29             :  * 1. Redistributions of source code must retain the above copyright
      30             :  *    notice, this list of conditions and the following disclaimer.
      31             :  * 2. Redistributions in binary form must reproduce the above copyright
      32             :  *    notice, this list of conditions and the following disclaimer in the
      33             :  *    documentation and/or other materials provided with the distribution.
      34             :  *
      35             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      36             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      37             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      38             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      39             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      40             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      41             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      42             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      43             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      44             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      45             :  * POSSIBILITY OF SUCH DAMAGE.
      46             :  */
      47             : 
      48             : #include <sys/param.h>
      49             : #include <sys/systm.h>
      50             : #include <sys/device.h>
      51             : #include <sys/kernel.h>
      52             : #include <sys/rwlock.h>
      53             : #include <sys/timeout.h>
      54             : #include <sys/timetc.h>
      55             : 
      56             : #include <machine/bus.h>
      57             : 
      58             : #include <dev/pci/pcivar.h>
      59             : #include <dev/pci/pcireg.h>
      60             : #include <dev/pci/pcidevs.h>
      61             : 
      62             : #include <dev/rndvar.h>
      63             : #include <dev/i2c/i2cvar.h>
      64             : 
      65             : #ifdef AMDPM_DEBUG
      66             : #define DPRINTF(x...) printf(x)
      67             : #else
      68             : #define DPRINTF(x...)
      69             : #endif
      70             : 
      71             : #define AMDPM_SMBUS_DELAY       100
      72             : #define AMDPM_SMBUS_TIMEOUT     1
      73             : 
      74             : u_int amdpm_get_timecount(struct timecounter *tc);
      75             : 
      76             : #ifndef AMDPM_FREQUENCY
      77             : #define AMDPM_FREQUENCY 3579545
      78             : #endif
      79             : 
      80             : static struct timecounter amdpm_timecounter = {
      81             :         amdpm_get_timecount,    /* get_timecount */
      82             :         0,                      /* no poll_pps */
      83             :         0xffffff,               /* counter_mask */
      84             :         AMDPM_FREQUENCY,        /* frequency */
      85             :         "AMDPM",              /* name */
      86             :         1000                    /* quality */
      87             : };
      88             : 
      89             : #define AMDPM_CONFREG   0x40
      90             : 
      91             : /* 0x40: General Configuration 1 Register */
      92             : #define AMDPM_RNGEN     0x00000080      /* random number generator enable */
      93             : #define AMDPM_STOPTMR   0x00000040      /* stop free-running timer */
      94             : 
      95             : /* 0x41: General Configuration 2 Register */
      96             : #define AMDPM_PMIOEN    0x00008000      /* system management IO space enable */
      97             : #define AMDPM_TMRRST    0x00004000      /* reset free-running timer */
      98             : #define AMDPM_TMR32     0x00000800      /* extended (32 bit) timer enable */
      99             : 
     100             : /* 0x42: SCI Interrupt Configuration Register */
     101             : /* 0x43: Previous Power State Register */
     102             : 
     103             : #define AMDPM_PMPTR     0x58            /* PMxx System Management IO space
     104             :                                            Pointer */
     105             : #define NFPM_PMPTR      0x14            /* nForce System Management IO space
     106             :                                            POinter */
     107             : #define AMDPM_PMBASE(x) ((x) & 0xff00)      /* PMxx base address */
     108             : #define AMDPM_PMSIZE    256             /* PMxx space size */
     109             : 
     110             : /* Registers in PMxx space */
     111             : #define AMDPM_TMR       0x08            /* 24/32 bit timer register */
     112             : 
     113             : #define AMDPM_RNGDATA   0xf0            /* 32 bit random data register */
     114             : #define AMDPM_RNGSTAT   0xf4            /* RNG status register */
     115             : #define AMDPM_RNGDONE   0x00000001      /* Random number generation complete */
     116             : 
     117             : #define AMDPM_SMB_REGS  0xe0            /* offset of SMB register space */
     118             : #define AMDPM_SMB_SIZE  0xf             /* size of SMB register space */ 
     119             : #define AMDPM_SMBSTAT   0x0             /* SMBus status */
     120             : #define AMDPM_SMBSTAT_ABRT      (1 << 0)  /* transfer abort */
     121             : #define AMDPM_SMBSTAT_COL       (1 << 1)  /* collision */
     122             : #define AMDPM_SMBSTAT_PRERR     (1 << 2)  /* protocol error */
     123             : #define AMDPM_SMBSTAT_HBSY      (1 << 3)  /* host controller busy */
     124             : #define AMDPM_SMBSTAT_CYC       (1 << 4)  /* cycle complete */
     125             : #define AMDPM_SMBSTAT_TO        (1 << 5)  /* timeout */
     126             : #define AMDPM_SMBSTAT_SNP       (1 << 8)  /* snoop address match */
     127             : #define AMDPM_SMBSTAT_SLV       (1 << 9)  /* slave address match */
     128             : #define AMDPM_SMBSTAT_SMBA      (1 << 10) /* SMBALERT# asserted */
     129             : #define AMDPM_SMBSTAT_BSY       (1 << 11) /* bus busy */
     130             : #define AMDPM_SMBSTAT_BITS      "\020\001ABRT\002COL\003PRERR\004HBSY\005CYC\006TO\011SNP\012SLV\013SMBA\014BSY"
     131             : #define AMDPM_SMBCTL    0x2             /* SMBus control */
     132             : #define AMDPM_SMBCTL_CMD_QUICK  0               /* QUICK command */
     133             : #define AMDPM_SMBCTL_CMD_BYTE   1               /* BYTE command */
     134             : #define AMDPM_SMBCTL_CMD_BDATA  2               /* BYTE DATA command */
     135             : #define AMDPM_SMBCTL_CMD_WDATA  3               /* WORD DATA command */
     136             : #define AMDPM_SMBCTL_CMD_PCALL  4               /* PROCESS CALL command */
     137             : #define AMDPM_SMBCTL_CMD_BLOCK  5               /* BLOCK command */
     138             : #define AMDPM_SMBCTL_START      (1 << 3)  /* start transfer */
     139             : #define AMDPM_SMBCTL_CYCEN      (1 << 4)  /* intr on cycle complete */
     140             : #define AMDPM_SMBCTL_ABORT      (1 << 5)  /* abort transfer */
     141             : #define AMDPM_SMBCTL_SNPEN      (1 << 8)  /* intr on snoop addr match */
     142             : #define AMDPM_SMBCTL_SLVEN      (1 << 9)  /* intr on slave addr match */
     143             : #define AMDPM_SMBCTL_SMBAEN     (1 << 10) /* intr on SMBALERT# */
     144             : #define AMDPM_SMBADDR   0x4             /* SMBus address */
     145             : #define AMDPM_SMBADDR_READ      (1 << 0)  /* read direction */
     146             : #define AMDPM_SMBADDR_ADDR(x)   (((x) & 0x7f) << 1) /* 7-bit address */
     147             : #define AMDPM_SMBDATA   0x6             /* SMBus data */
     148             : #define AMDPM_SMBCMD    0x8             /* SMBus command */
     149             : 
     150             : 
     151             : struct amdpm_softc {
     152             :         struct device sc_dev;
     153             : 
     154             :         pci_chipset_tag_t sc_pc;
     155             :         pcitag_t sc_tag;
     156             : 
     157             :         bus_space_tag_t sc_iot;
     158             :         bus_space_handle_t sc_ioh;              /* PMxx space */
     159             :         bus_space_handle_t sc_i2c_ioh;          /* I2C space */
     160             :         int sc_poll;
     161             : 
     162             :         struct timeout sc_rnd_ch;
     163             : 
     164             :         struct i2c_controller sc_i2c_tag;
     165             :         struct rwlock sc_i2c_lock;
     166             :         struct {
     167             :                 i2c_op_t op;
     168             :                 void *buf;
     169             :                 size_t len;
     170             :                 int flags;
     171             :                 volatile int error;
     172             :         } sc_i2c_xfer;
     173             : };
     174             : 
     175             : int     amdpm_match(struct device *, void *, void *);
     176             : void    amdpm_attach(struct device *, struct device *, void *);
     177             : int     amdpm_activate(struct device *, int);
     178             : void    amdpm_rnd_callout(void *);
     179             : 
     180             : int     amdpm_i2c_acquire_bus(void *, int);
     181             : void    amdpm_i2c_release_bus(void *, int);
     182             : int     amdpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
     183             :             void *, size_t, int);
     184             : 
     185             : int     amdpm_intr(void *);
     186             : 
     187             : struct cfattach amdpm_ca = {
     188             :         sizeof(struct amdpm_softc), amdpm_match, amdpm_attach,
     189             :         NULL, amdpm_activate
     190             : };
     191             : 
     192             : struct cfdriver amdpm_cd = {
     193             :         NULL, "amdpm", DV_DULL
     194             : };
     195             : 
     196             : const struct pci_matchid amdpm_ids[] = {
     197             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC },
     198             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC },
     199             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC },
     200             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_PMC },
     201             :         { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_SMB }
     202             : };
     203             : 
     204             : int
     205           0 : amdpm_match(struct device *parent, void *match, void *aux)
     206             : {
     207           0 :         return (pci_matchbyid(aux, amdpm_ids,
     208             :             sizeof(amdpm_ids) / sizeof(amdpm_ids[0])));
     209             : }
     210             : 
     211             : void
     212           0 : amdpm_attach(struct device *parent, struct device *self, void *aux)
     213             : {
     214           0 :         struct amdpm_softc *sc = (struct amdpm_softc *) self;
     215           0 :         struct pci_attach_args *pa = aux;
     216           0 :         struct i2cbus_attach_args iba;
     217             :         pcireg_t cfg_reg, reg;
     218             :         int i;
     219             : 
     220           0 :         sc->sc_pc = pa->pa_pc;
     221           0 :         sc->sc_tag = pa->pa_tag;
     222           0 :         sc->sc_iot = pa->pa_iot;
     223           0 :         sc->sc_poll = 1; /* XXX */
     224             : 
     225             :         
     226           0 :         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD)  {
     227           0 :                 cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_CONFREG);
     228           0 :                 if ((cfg_reg & AMDPM_PMIOEN) == 0) {
     229           0 :                         printf(": PMxx space isn't enabled\n");
     230           0 :                         return;
     231             :                 }
     232             : 
     233           0 :                 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_PMPTR);
     234           0 :                 if (AMDPM_PMBASE(reg) == 0 ||
     235           0 :                     bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_PMSIZE,
     236           0 :                     0, &sc->sc_ioh)) {
     237           0 :                         printf("\n");
     238           0 :                         return;
     239             :                 }
     240           0 :                 if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, AMDPM_SMB_REGS,
     241           0 :                     AMDPM_SMB_SIZE, &sc->sc_i2c_ioh)) {
     242           0 :                         printf(": failed to map I2C subregion\n");
     243           0 :                         return; 
     244             :                 }
     245             : 
     246           0 :                 if ((cfg_reg & AMDPM_TMRRST) == 0 &&
     247           0 :                     (cfg_reg & AMDPM_STOPTMR) == 0 &&
     248           0 :                     (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
     249           0 :                     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC)) {
     250           0 :                         printf(": %d-bit timer at %lluHz",
     251           0 :                             (cfg_reg & AMDPM_TMR32) ? 32 : 24,
     252           0 :                             amdpm_timecounter.tc_frequency);
     253             : 
     254           0 :                         amdpm_timecounter.tc_priv = sc;
     255           0 :                         if (cfg_reg & AMDPM_TMR32)
     256           0 :                                 amdpm_timecounter.tc_counter_mask = 0xffffffffu;
     257           0 :                         tc_init(&amdpm_timecounter);
     258           0 :                 }       
     259           0 :                 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
     260           0 :                     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC) {
     261           0 :                         if ((cfg_reg & AMDPM_RNGEN) ==0) {
     262           0 :                                 pci_conf_write(pa->pa_pc, pa->pa_tag, 
     263           0 :                                     AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
     264           0 :                                 cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
     265             :                                     AMDPM_CONFREG);
     266           0 :                         }
     267           0 :                         if (cfg_reg & AMDPM_RNGEN) {
     268             :                         /* Check to see if we can read data from the RNG. */
     269           0 :                                 (void) bus_space_read_4(sc->sc_iot, sc->sc_ioh,
     270             :                                     AMDPM_RNGDATA);
     271           0 :                                 for (i = 1000; i--; ) {
     272           0 :                                         if (bus_space_read_1(sc->sc_iot, 
     273           0 :                                             sc->sc_ioh, AMDPM_RNGSTAT) & 
     274             :                                             AMDPM_RNGDONE)
     275             :                                                 break;
     276           0 :                                         DELAY(10);
     277             :                                 }
     278           0 :                                 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
     279           0 :                                     AMDPM_RNGSTAT) & AMDPM_RNGDONE) {
     280           0 :                                         printf(": rng active");
     281           0 :                                         timeout_set(&sc->sc_rnd_ch, 
     282           0 :                                             amdpm_rnd_callout, sc);
     283           0 :                                         amdpm_rnd_callout(sc);
     284           0 :                                 }
     285             :                         }
     286             :                 }
     287           0 :         } else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
     288           0 :                 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, NFPM_PMPTR);
     289           0 :                 if (AMDPM_PMBASE(reg) == 0 ||
     290           0 :                     bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_SMB_SIZE, 0,
     291           0 :                     &sc->sc_i2c_ioh)) {
     292           0 :                         printf(": failed to map I2C subregion\n");
     293           0 :                         return;
     294             :                 }
     295             :         }
     296           0 :         printf("\n");
     297             : 
     298             :         /* Attach I2C bus */
     299           0 :         rw_init(&sc->sc_i2c_lock, "iiclk");
     300           0 :         sc->sc_i2c_tag.ic_cookie = sc;
     301           0 :         sc->sc_i2c_tag.ic_acquire_bus = amdpm_i2c_acquire_bus;
     302           0 :         sc->sc_i2c_tag.ic_release_bus = amdpm_i2c_release_bus;
     303           0 :         sc->sc_i2c_tag.ic_exec = amdpm_i2c_exec;
     304             : 
     305           0 :         bzero(&iba, sizeof(iba));
     306           0 :         iba.iba_name = "iic";
     307           0 :         iba.iba_tag = &sc->sc_i2c_tag;
     308           0 :         config_found(self, &iba, iicbus_print);
     309           0 : }
     310             : 
     311             : int
     312           0 : amdpm_activate(struct device *self, int act)
     313             : {
     314           0 :         struct amdpm_softc *sc = (struct amdpm_softc *)self;
     315             :         int rv = 0;
     316             : 
     317           0 :         switch (act) {
     318             :         case DVACT_RESUME:
     319           0 :                 if (timeout_initialized(&sc->sc_rnd_ch)) {
     320             :                         pcireg_t cfg_reg;
     321             : 
     322             :                         /* Restart the AMD PBC768_PMC/8111_PMC RNG */
     323           0 :                         cfg_reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
     324             :                             AMDPM_CONFREG);
     325           0 :                         pci_conf_write(sc->sc_pc, sc->sc_tag, 
     326           0 :                             AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
     327             :                 
     328           0 :                 }
     329           0 :                 rv = config_activate_children(self, act);
     330           0 :                 break;
     331             :         default:
     332           0 :                 rv = config_activate_children(self, act);
     333           0 :                 break;
     334             :         }
     335           0 :         return (rv);
     336             : }
     337             : 
     338             : void
     339           0 : amdpm_rnd_callout(void *v)
     340             : {
     341           0 :         struct amdpm_softc *sc = v;
     342             :         u_int32_t reg;
     343             : 
     344           0 :         if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
     345           0 :             AMDPM_RNGDONE) != 0) {
     346           0 :                 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGDATA);
     347           0 :                 enqueue_randomness(reg);
     348           0 :         }
     349           0 :         timeout_add(&sc->sc_rnd_ch, 1);
     350           0 : }
     351             : 
     352             : u_int
     353           0 : amdpm_get_timecount(struct timecounter *tc)
     354             : {
     355           0 :         struct amdpm_softc *sc = tc->tc_priv;
     356             :         u_int u2;
     357             : #if 0
     358             :         u_int u1, u3;
     359             : #endif
     360             : 
     361           0 :         u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
     362             : #if 0
     363             :         u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
     364             :         do {
     365             :                 u1 = u2;
     366             :                 u2 = u3;
     367             :                 u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
     368             :         } while (u1 > u2 || u2 > u3);
     369             : #endif
     370           0 :         return (u2);
     371             : }
     372             : 
     373             : int
     374           0 : amdpm_i2c_acquire_bus(void *cookie, int flags)
     375             : {
     376           0 :         struct amdpm_softc *sc = cookie;
     377             : 
     378           0 :         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
     379           0 :                 return (0);
     380             : 
     381           0 :         return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
     382           0 : }
     383             : 
     384             : void
     385           0 : amdpm_i2c_release_bus(void *cookie, int flags)
     386             : {
     387           0 :         struct amdpm_softc *sc = cookie;
     388             : 
     389           0 :         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
     390           0 :                 return;
     391             : 
     392           0 :         rw_exit(&sc->sc_i2c_lock);
     393           0 : }
     394             : 
     395             : int
     396           0 : amdpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     397             :     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
     398             : {
     399           0 :         struct amdpm_softc *sc = cookie;
     400             :         u_int8_t *b;
     401             :         u_int16_t st, ctl, data;
     402             :         int retries;
     403             : 
     404             :         DPRINTF("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
     405             :             "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
     406             :             len, flags);
     407             : 
     408             :         /* Wait for bus to be idle */
     409           0 :         for (retries = 100; retries > 0; retries--) {
     410           0 :                 st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
     411           0 :                 if (!(st & AMDPM_SMBSTAT_BSY))
     412             :                         break;
     413           0 :                 DELAY(AMDPM_SMBUS_DELAY);
     414             :         }
     415             :         DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
     416             :             AMDPM_SMBSTAT_BITS);
     417           0 :         if (st & AMDPM_SMBSTAT_BSY)
     418           0 :                 return (1);
     419             : 
     420           0 :         if (cold || sc->sc_poll)
     421           0 :                 flags |= I2C_F_POLL;
     422             : 
     423           0 :         if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
     424           0 :                 return (1);
     425             : 
     426             :         /* Setup transfer */
     427           0 :         sc->sc_i2c_xfer.op = op;
     428           0 :         sc->sc_i2c_xfer.buf = buf;
     429           0 :         sc->sc_i2c_xfer.len = len;
     430           0 :         sc->sc_i2c_xfer.flags = flags;
     431           0 :         sc->sc_i2c_xfer.error = 0;
     432             : 
     433             :         /* Set slave address and transfer direction */
     434           0 :         bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR,
     435             :             AMDPM_SMBADDR_ADDR(addr) |
     436             :             (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0));
     437             : 
     438             :         b = (void *)cmdbuf;
     439           0 :         if (cmdlen > 0)
     440             :                 /* Set command byte */
     441           0 :                 bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]);
     442             : 
     443           0 :         if (I2C_OP_WRITE_P(op)) {
     444             :                 /* Write data */
     445             :                 data = 0;
     446             :                 b = buf;
     447           0 :                 if (len > 0)
     448           0 :                         data = b[0];
     449           0 :                 if (len > 1)
     450           0 :                         data |= ((u_int16_t)b[1] << 8);
     451           0 :                 if (len > 0)
     452           0 :                         bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh,
     453             :                             AMDPM_SMBDATA, data);
     454             :         }
     455             : 
     456             :         /* Set SMBus command */
     457           0 :         if (len == 0)
     458           0 :                 ctl = AMDPM_SMBCTL_CMD_BYTE;
     459           0 :         else if (len == 1)
     460           0 :                 ctl = AMDPM_SMBCTL_CMD_BDATA;
     461           0 :         else if (len == 2)
     462             :                 ctl = AMDPM_SMBCTL_CMD_WDATA;
     463             :         else
     464           0 :                 panic("%s: unexpected len %zd", __func__, len);
     465             : 
     466           0 :         if ((flags & I2C_F_POLL) == 0)
     467           0 :                 ctl |= AMDPM_SMBCTL_CYCEN;
     468             : 
     469             :         /* Start transaction */
     470           0 :         ctl |= AMDPM_SMBCTL_START;
     471           0 :         bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl);
     472             : 
     473           0 :         if (flags & I2C_F_POLL) {
     474             :                 /* Poll for completion */
     475           0 :                 DELAY(AMDPM_SMBUS_DELAY);
     476           0 :                 for (retries = 1000; retries > 0; retries--) {
     477           0 :                         st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
     478             :                             AMDPM_SMBSTAT);
     479           0 :                         if ((st & AMDPM_SMBSTAT_HBSY) == 0)
     480             :                                 break;
     481           0 :                         DELAY(AMDPM_SMBUS_DELAY);
     482             :                 }
     483           0 :                 if (st & AMDPM_SMBSTAT_HBSY)
     484             :                         goto timeout;
     485           0 :                 amdpm_intr(sc);
     486           0 :         } else {
     487             :                 /* Wait for interrupt */
     488           0 :                 if (tsleep(sc, PRIBIO, "amdpm", AMDPM_SMBUS_TIMEOUT * hz))
     489             :                         goto timeout;
     490             :         }
     491             : 
     492           0 :         if (sc->sc_i2c_xfer.error)
     493           0 :                 return (1);
     494             : 
     495           0 :         return (0);
     496             : 
     497             : timeout:
     498             :         /*
     499             :          * Transfer timeout. Kill the transaction and clear status bits.
     500             :          */
     501           0 :         printf("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
     502             :             "flags 0x%02x: timeout, status 0x%b\n",
     503           0 :             sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
     504           0 :             st, AMDPM_SMBSTAT_BITS);
     505           0 :         bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL,
     506             :             AMDPM_SMBCTL_ABORT);
     507           0 :         DELAY(AMDPM_SMBUS_DELAY);
     508           0 :         st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
     509           0 :         if ((st & AMDPM_SMBSTAT_ABRT) == 0)
     510           0 :                 printf("%s: abort failed, status 0x%b\n",
     511             :                     sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS);
     512           0 :         bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
     513           0 :         return (1);
     514           0 : }
     515             : 
     516             : int
     517           0 : amdpm_intr(void *arg)
     518             : {
     519           0 :         struct amdpm_softc *sc = arg;
     520             :         u_int16_t st, data;
     521             :         u_int8_t *b;
     522             :         size_t len;
     523             : 
     524             :         /* Read status */
     525           0 :         st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
     526           0 :         if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT |
     527             :             AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC |
     528             :             AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV |
     529           0 :             AMDPM_SMBSTAT_SMBA)) == 0)
     530             :                 /* Interrupt was not for us */
     531           0 :                 return (0);
     532             : 
     533             :         DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st,
     534             :             AMDPM_SMBSTAT_BITS);
     535             : 
     536             :         /* Clear status bits */
     537           0 :         bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
     538             : 
     539             :         /* Check for errors */
     540           0 :         if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR |
     541             :             AMDPM_SMBSTAT_TO)) {
     542           0 :                 sc->sc_i2c_xfer.error = 1;
     543           0 :                 goto done;
     544             :         }
     545             : 
     546           0 :         if (st & AMDPM_SMBSTAT_CYC) {
     547           0 :                 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
     548             :                         goto done;
     549             : 
     550             :                 /* Read data */
     551           0 :                 b = sc->sc_i2c_xfer.buf;
     552           0 :                 len = sc->sc_i2c_xfer.len;
     553           0 :                 if (len > 0) {
     554           0 :                         data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
     555             :                             AMDPM_SMBDATA);
     556           0 :                         b[0] = data & 0xff;
     557           0 :                 }
     558           0 :                 if (len > 1)
     559           0 :                         b[1] = (data >> 8) & 0xff;
     560             :         }
     561             : 
     562             : done:
     563           0 :         if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
     564           0 :                 wakeup(sc);
     565           0 :         return (1);
     566           0 : }

Generated by: LCOV version 1.13