root/dev/pci/amdpm.c

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

DEFINITIONS

This source file includes following definitions.
  1. amdpm_match
  2. amdpm_attach
  3. amdpm_rnd_callout
  4. amdpm_get_timecount
  5. amdpm_i2c_acquire_bus
  6. amdpm_i2c_release_bus
  7. amdpm_i2c_exec
  8. amdpm_intr

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

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