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

          Line data    Source code
       1             : /*      $OpenBSD: viapm.c,v 1.17 2018/07/05 10:09:11 fcambus Exp $      */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2005 Mark Kettenis <kettenis@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             : /*      $NetBSD: viaenv.c,v 1.9 2002/10/02 16:51:59 thorpej Exp $       */
      20             : 
      21             : /*
      22             :  * Copyright (c) 2000 Johan Danielsson
      23             :  * All rights reserved.
      24             :  *
      25             :  * Redistribution and use in source and binary forms, with or without
      26             :  * modification, are permitted provided that the following conditions
      27             :  * are met:
      28             :  *
      29             :  * 1. Redistributions of source code must retain the above copyright
      30             :  *    notice, this list of conditions and the following disclaimer.
      31             :  *
      32             :  * 2. Redistributions in binary form must reproduce the above copyright
      33             :  *    notice, this list of conditions and the following disclaimer in the
      34             :  *    documentation and/or other materials provided with the distribution.
      35             :  *
      36             :  * 3. Neither the name of author nor the names of any contributors may
      37             :  *    be used to endorse or promote products derived from this
      38             :  *    software without specific prior written permission.
      39             :  *
      40             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
      41             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      42             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      43             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      44             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      45             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      46             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      47             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      48             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      49             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      50             :  * POSSIBILITY OF SUCH DAMAGE.
      51             :  */
      52             : 
      53             : /*
      54             :  * Driver for the SMBus controller and power management timer
      55             :  * in the VIA VT82C596[B], VT82C686A, VT8231, VT8233[A], VT8235, VT8237[A,S],
      56             :  * VT8251, CX700, VX800, VX855 and VX900 South Bridges.
      57             :  * Also for the hardware monitoring part of the VIA VT82C686A and VT8231.
      58             :  */
      59             : 
      60             : #include <sys/param.h>
      61             : #include <sys/systm.h>
      62             : #include <sys/device.h>
      63             : #include <sys/kernel.h>
      64             : #include <sys/rwlock.h>
      65             : #include <sys/sensors.h>
      66             : #include <sys/timeout.h>
      67             : #include <sys/timetc.h>
      68             : 
      69             : #include <machine/bus.h>
      70             : 
      71             : #include <dev/pci/pcidevs.h>
      72             : #include <dev/pci/pcireg.h>
      73             : #include <dev/pci/pcivar.h>
      74             : 
      75             : #include <dev/i2c/i2cvar.h>
      76             : 
      77             : /*
      78             :  * Register definitions.
      79             :  */
      80             : 
      81             : /* PCI configuration registers */
      82             : #define VIAPM_PM_CFG1           0x40    /* general configuration */
      83             : #define VIAPM_PM_CFG2           0x80
      84             : #define VIAPM_PM_CFG_TMR32      (1 << 11) /* 32-bit PM timer */
      85             : #define VIAPM_PM_CFG_PMEN       (1 << 15) /* enable PM I/O space */
      86             : #define VIAPM_PM_BASE1          0x48    /* power management I/O base address */
      87             : #define VIAPM_PM_BASE2          0x88
      88             : #define VIAPM_PM_BASE_MASK      0xff80
      89             : 
      90             : #define VIAPM_HWMON_BASE        0x70    /* HWMon I/O base address */
      91             : #define VIAPM_HWMON_BASE_MASK   0xff80
      92             : #define VIAPM_HWMON_CFG         0x74    /* HWMon control register */
      93             : #define VIAPM_HWMON_CFG_HWEN    (1 << 0)  /* enable HWMon I/O space */
      94             : 
      95             : #define VIAPM_SMB_BASE1         0x90    /* SMBus I/O base address */
      96             : #define VIAPM_SMB_BASE2         0x80
      97             : #define VIAPM_SMB_BASE3         0xd0
      98             : #define VIAPM_SMB_BASE_MASK     0xfff0
      99             : #define VIAPM_SMB_CFG1          0xd2    /* host configuration */
     100             : #define VIAPM_SMB_CFG2          0x84
     101             : #define VIAPM_SMB_CFG_HSTEN     (1 << 0)  /* enable SMBus I/O space */
     102             : #define VIAPM_SMB_CFG_INTEN     (1 << 1)  /* enable SCI/SMI */
     103             : #define VIAPM_SMB_CFG_SCIEN     (1 << 3)  /* interrupt type (SCI/SMI) */
     104             : 
     105             : #define VIAPM_PM_SIZE           256     /* Power management I/O space size */
     106             : #define VIAPM_HWMON_SIZE        128     /* HWMon I/O space size */
     107             : #define VIAPM_SMB_SIZE          16      /* SMBus I/O space size */
     108             : 
     109             : /* HWMon I/O registers */
     110             : #define VIAPM_HWMON_TSENS3      0x1f
     111             : #define VIAPM_HWMON_TSENS1      0x20
     112             : #define VIAPM_HWMON_TSENS2      0x21
     113             : #define VIAPM_HWMON_VSENS1      0x22
     114             : #define VIAPM_HWMON_VSENS2      0x23
     115             : #define VIAPM_HWMON_VCORE       0x24
     116             : #define VIAPM_HWMON_VSENS3      0x25
     117             : #define VIAPM_HWMON_VSENS4      0x26
     118             : #define VIAPM_HWMON_FAN1        0x29
     119             : #define VIAPM_HWMON_FAN2        0x2a
     120             : #define VIAPM_HWMON_FANCONF     0x47    /* fan configuration */
     121             : #define VIAPM_HWMON_TLOW        0x49    /* temperature low order value */
     122             : #define VIAPM_HWMON_TIRQ        0x4b    /* temperature interrupt configuration */
     123             : 
     124             : /* ACPI I/O registers */
     125             : #define VIAPM_PM_TMR            0x08    /* PM timer */
     126             : 
     127             : /* SMBus I/O registers */
     128             : #define VIAPM_SMB_HS            0x00    /* host status */
     129             : #define VIAPM_SMB_HS_BUSY       (1 << 0)  /* running a command */
     130             : #define VIAPM_SMB_HS_INTR       (1 << 1)  /* command completed */
     131             : #define VIAPM_SMB_HS_DEVERR     (1 << 2)  /* command error */
     132             : #define VIAPM_SMB_HS_BUSERR     (1 << 3)  /* transaction collision */
     133             : #define VIAPM_SMB_HS_FAILED     (1 << 4)  /* failed bus transaction */
     134             : #define VIAPM_SMB_HS_INUSE      (1 << 6)  /* bus semaphore */
     135             : #define VIAPM_SMB_HS_BITS       \
     136             :   "\020\001BUSY\002INTR\003DEVERR\004BUSERR\005FAILED\007INUSE"
     137             : #define VIAPM_SMB_HC            0x02    /* host control */
     138             : #define VIAPM_SMB_HC_INTREN     (1 << 0)  /* enable interrupts */
     139             : #define VIAPM_SMB_HC_KILL       (1 << 1)  /* kill current transaction */
     140             : #define VIAPM_SMB_HC_CMD_QUICK  (0 << 2)  /* QUICK command */
     141             : #define VIAPM_SMB_HC_CMD_BYTE   (1 << 2)  /* BYTE command */
     142             : #define VIAPM_SMB_HC_CMD_BDATA  (2 << 2)  /* BYTE DATA command */
     143             : #define VIAPM_SMB_HC_CMD_WDATA  (3 << 2)  /* WORD DATA command */
     144             : #define VIAPM_SMB_HC_CMD_PCALL  (4 << 2)  /* PROCESS CALL command */
     145             : #define VIAPM_SMB_HC_CMD_BLOCK  (5 << 2)  /* BLOCK command */
     146             : #define VIAPM_SMB_HC_START      (1 << 6)  /* start transaction */
     147             : #define VIAPM_SMB_HCMD          0x03    /* host command */
     148             : #define VIAPM_SMB_TXSLVA        0x04    /* transmit slave address */
     149             : #define VIAPM_SMB_TXSLVA_READ   (1 << 0)  /* read direction */
     150             : #define VIAPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
     151             : #define VIAPM_SMB_HD0           0x05    /* host data 0 */
     152             : #define VIAPM_SMB_HD1           0x06    /* host data 1 */
     153             : #define VIAPM_SMB_HBDB          0x07    /* host block data byte */
     154             : 
     155             : #ifdef VIAPM_DEBUG
     156             : #define DPRINTF(x...) printf(x)
     157             : #else
     158             : #define DPRINTF(x...)
     159             : #endif
     160             : 
     161             : #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
     162             : 
     163             : #define VIAPM_SMBUS_DELAY       100
     164             : #define VIAPM_SMBUS_TIMEOUT     1
     165             : 
     166             : #define VIAPM_NUM_SENSORS       10      /* three temp, two fan, five voltage */
     167             : 
     168             : u_int   viapm_get_timecount(struct timecounter *tc);
     169             : 
     170             : #ifndef VIAPM_FREQUENCY
     171             : #define VIAPM_FREQUENCY 3579545
     172             : #endif
     173             : 
     174             : static struct timecounter viapm_timecounter = {
     175             :         viapm_get_timecount,    /* get_timecount */
     176             :         0,                      /* no poll_pps */
     177             :         0xffffff,               /* counter_mask */
     178             :         VIAPM_FREQUENCY,        /* frequency */
     179             :         "VIAPM",              /* name */
     180             :         1000                    /* quality */
     181             : };
     182             : 
     183             : struct timeout viapm_timeout;
     184             : 
     185             : struct viapm_softc {
     186             :         struct device           sc_dev;
     187             : 
     188             :         bus_space_tag_t         sc_iot;
     189             :         bus_space_handle_t      sc_pm_ioh;
     190             :         bus_space_handle_t      sc_smbus_ioh;
     191             :         bus_space_handle_t      sc_hwmon_ioh;
     192             :         void *                  sc_ih;
     193             :         int                     sc_poll;
     194             : 
     195             :         int                     sc_fan_div[2];  /* fan RPM divisor */
     196             : 
     197             :         struct ksensor          sc_data[VIAPM_NUM_SENSORS];
     198             :         struct ksensordev       sc_sensordev;
     199             : 
     200             :         struct i2c_controller   sc_i2c_tag;
     201             :         struct rwlock           sc_i2c_lock;
     202             :         struct {
     203             :                 i2c_op_t     op;
     204             :                 void *       buf;
     205             :                 size_t       len;
     206             :                 int          flags;
     207             :                 volatile int error;
     208             :         }                       sc_i2c_xfer;
     209             : };
     210             : 
     211             : int     viapm_match(struct device *, void *, void *);
     212             : void    viapm_attach(struct device *, struct device *, void *);
     213             : 
     214             : int     viapm_i2c_acquire_bus(void *, int);
     215             : void    viapm_i2c_release_bus(void *, int);
     216             : int     viapm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
     217             :             void *, size_t, int);
     218             : 
     219             : int     viapm_intr(void *);
     220             : 
     221             : int     val_to_uK(unsigned int);
     222             : int     val_to_rpm(unsigned int, int);
     223             : long    val_to_uV(unsigned int, int);
     224             : void    viapm_refresh_sensor_data(struct viapm_softc *);
     225             : void    viapm_refresh(void *);
     226             : 
     227             : struct cfattach viapm_ca = {
     228             :         sizeof(struct viapm_softc), viapm_match, viapm_attach
     229             : };
     230             : 
     231             : struct cfdriver viapm_cd = {
     232             :         NULL, "viapm", DV_DULL
     233             : };
     234             : 
     235             : const struct pci_matchid viapm_ids[] = {
     236             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596 },
     237             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596B_PM },
     238             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB },
     239             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_PWR },
     240             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA },
     241             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA },
     242             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA },
     243             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA },
     244             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA },
     245             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237S_ISA },
     246             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_ISA },
     247             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_CX700_ISA },
     248             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX800_ISA },
     249             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX855_ISA },
     250             :         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX900_ISA }
     251             : };
     252             : 
     253             : /*
     254             :  * XXX there doesn't seem to exist much hard documentation on how to
     255             :  * convert the raw values to usable units, this code is more or less
     256             :  * stolen from the Linux driver, but changed to suit our conditions
     257             :  */
     258             : 
     259             : /*
     260             :  * lookup-table to translate raw values to uK, this is the same table
     261             :  * used by the Linux driver (modulo units); there is a fifth degree
     262             :  * polynomial that supposedly been used to generate this table, but I
     263             :  * haven't been able to figure out how -- it doesn't give the same values
     264             :  */
     265             : 
     266             : static const long val_to_temp[] = {
     267             :         20225, 20435, 20645, 20855, 21045, 21245, 21425, 21615, 21785, 21955,
     268             :         22125, 22285, 22445, 22605, 22755, 22895, 23035, 23175, 23315, 23445,
     269             :         23565, 23695, 23815, 23925, 24045, 24155, 24265, 24365, 24465, 24565,
     270             :         24665, 24765, 24855, 24945, 25025, 25115, 25195, 25275, 25355, 25435,
     271             :         25515, 25585, 25655, 25725, 25795, 25865, 25925, 25995, 26055, 26115,
     272             :         26175, 26235, 26295, 26355, 26405, 26465, 26515, 26575, 26625, 26675,
     273             :         26725, 26775, 26825, 26875, 26925, 26975, 27025, 27065, 27115, 27165,
     274             :         27205, 27255, 27295, 27345, 27385, 27435, 27475, 27515, 27565, 27605,
     275             :         27645, 27685, 27735, 27775, 27815, 27855, 27905, 27945, 27985, 28025,
     276             :         28065, 28105, 28155, 28195, 28235, 28275, 28315, 28355, 28405, 28445,
     277             :         28485, 28525, 28565, 28615, 28655, 28695, 28735, 28775, 28825, 28865,
     278             :         28905, 28945, 28995, 29035, 29075, 29125, 29165, 29205, 29245, 29295,
     279             :         29335, 29375, 29425, 29465, 29505, 29555, 29595, 29635, 29685, 29725,
     280             :         29765, 29815, 29855, 29905, 29945, 29985, 30035, 30075, 30125, 30165,
     281             :         30215, 30255, 30305, 30345, 30385, 30435, 30475, 30525, 30565, 30615,
     282             :         30655, 30705, 30755, 30795, 30845, 30885, 30935, 30975, 31025, 31075,
     283             :         31115, 31165, 31215, 31265, 31305, 31355, 31405, 31455, 31505, 31545,
     284             :         31595, 31645, 31695, 31745, 31805, 31855, 31905, 31955, 32005, 32065,
     285             :         32115, 32175, 32225, 32285, 32335, 32395, 32455, 32515, 32575, 32635,
     286             :         32695, 32755, 32825, 32885, 32955, 33025, 33095, 33155, 33235, 33305,
     287             :         33375, 33455, 33525, 33605, 33685, 33765, 33855, 33935, 34025, 34115,
     288             :         34205, 34295, 34395, 34495, 34595, 34695, 34805, 34905, 35015, 35135,
     289             :         35245, 35365, 35495, 35615, 35745, 35875, 36015, 36145, 36295, 36435,
     290             :         36585, 36745, 36895, 37065, 37225, 37395, 37575, 37755, 37935, 38125,
     291             :         38325, 38525, 38725, 38935, 39155, 39375, 39605, 39835, 40075, 40325,
     292             :         40575, 40835, 41095, 41375, 41655, 41935,
     293             : };
     294             : 
     295             : int
     296           0 : viapm_match(struct device *parent, void *match, void *aux)
     297             : {
     298           0 :         return (pci_matchbyid(aux, viapm_ids, nitems(viapm_ids)));
     299             : }
     300             : 
     301             : void
     302           0 : viapm_attach(struct device *parent, struct device *self, void *aux)
     303             : {
     304           0 :         struct viapm_softc *sc = (struct viapm_softc *)self;
     305           0 :         struct pci_attach_args *pa = aux;
     306           0 :         struct i2cbus_attach_args iba;
     307             :         pcireg_t conf, iobase;
     308           0 :         pci_intr_handle_t ih;
     309             :         const char *intrstr = NULL;
     310             :         int basereg, cfgreg;
     311             :         int i, v;
     312             : 
     313           0 :         sc->sc_iot = pa->pa_iot;
     314             : 
     315             :         /* SMBus */
     316           0 :         switch (PCI_PRODUCT(pa->pa_id)) {
     317             :         case PCI_PRODUCT_VIATECH_VT82C596:
     318             :         case PCI_PRODUCT_VIATECH_VT82C596B_PM:
     319             :         case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
     320             :         case PCI_PRODUCT_VIATECH_VT8231_PWR:
     321             :                 basereg = VIAPM_SMB_BASE1;
     322           0 :                 break;
     323             :         default:
     324             :                 basereg = VIAPM_SMB_BASE3;
     325           0 :         }
     326             : 
     327             :         cfgreg = (VIAPM_SMB_CFG1 & (~0x03));        /* XXX 4-byte aligned */
     328             : 
     329             :         /* Check 2nd address for VT82C596 */
     330           0 :         iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg);
     331           0 :         if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT82C596) &&
     332           0 :             ((iobase & 0x0001) == 0)) {
     333           0 :                 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_SMB_BASE2);
     334             :                 cfgreg = VIAPM_SMB_CFG2;
     335           0 :         }
     336             : 
     337             :         /* Check if SMBus I/O space is enabled */
     338           0 :         conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg);
     339           0 :         if (cfgreg != VIAPM_SMB_CFG2)
     340           0 :                 conf >>= 16;
     341             :         DPRINTF(": conf 0x%02x", conf & 0xff);
     342             : 
     343           0 :         if ((conf & VIAPM_SMB_CFG_HSTEN) == 0) {
     344           0 :                 printf(": SMBus disabled\n");
     345           0 :                 goto nosmb;
     346             :         }
     347             : 
     348             :         /* Map SMBus I/O space */
     349           0 :         iobase &= VIAPM_SMB_BASE_MASK;
     350           0 :         if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
     351           0 :             VIAPM_SMB_SIZE, 0, &sc->sc_smbus_ioh)) {
     352           0 :                 printf(": can't map SMBus i/o space\n");
     353           0 :                 goto nosmb;
     354             :         }
     355             : 
     356           0 :         sc->sc_poll = 1;
     357           0 :         if ((conf & VIAPM_SMB_CFG_SCIEN) == 0) {
     358             :                 /* No PCI IRQ */
     359           0 :                 printf(": SMI");
     360           0 :         } else {
     361             :                 /* Install interrupt handler */
     362           0 :                 if (pci_intr_map(pa, &ih) == 0) {
     363           0 :                         intrstr = pci_intr_string(pa->pa_pc, ih);
     364           0 :                         sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
     365           0 :                             viapm_intr, sc, DEVNAME(sc));
     366           0 :                         if (sc->sc_ih != NULL) {
     367           0 :                                 printf(": %s", intrstr);
     368           0 :                                 sc->sc_poll = 0;
     369           0 :                         }
     370             :                 }
     371           0 :                 if (sc->sc_poll)
     372           0 :                         printf(": polling");
     373             :         }
     374             : 
     375           0 :         printf("\n");
     376             : 
     377             :         /* Attach I2C bus */
     378           0 :         rw_init(&sc->sc_i2c_lock, "iiclk");
     379           0 :         sc->sc_i2c_tag.ic_cookie = sc;
     380           0 :         sc->sc_i2c_tag.ic_acquire_bus = viapm_i2c_acquire_bus;
     381           0 :         sc->sc_i2c_tag.ic_release_bus = viapm_i2c_release_bus;
     382           0 :         sc->sc_i2c_tag.ic_exec = viapm_i2c_exec;
     383             : 
     384           0 :         bzero(&iba, sizeof iba);
     385           0 :         iba.iba_name = "iic";
     386           0 :         iba.iba_tag = &sc->sc_i2c_tag;
     387           0 :         config_found(self, &iba, iicbus_print);
     388             : 
     389             : nosmb:
     390             : 
     391             :         /* Power management */
     392           0 :         switch (PCI_PRODUCT(pa->pa_id)) {
     393             :         case PCI_PRODUCT_VIATECH_VT82C596:
     394             :         case PCI_PRODUCT_VIATECH_VT82C596B_PM:
     395             :         case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
     396             :         case PCI_PRODUCT_VIATECH_VT8231_PWR:
     397             :                 basereg = VIAPM_PM_BASE1;
     398             :                 cfgreg = VIAPM_PM_CFG1;
     399           0 :                 break;
     400             :         default:
     401             :                 basereg = VIAPM_PM_BASE2;
     402             :                 cfgreg = VIAPM_PM_CFG2;
     403           0 :         }
     404             : 
     405             :         /* Check if power management I/O space is enabled */
     406           0 :         conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg);
     407           0 :         if ((conf & VIAPM_PM_CFG_PMEN) == 0) {
     408           0 :                 printf("%s: PM disabled\n", DEVNAME(sc));
     409           0 :                 goto nopm;
     410             :         }
     411             : 
     412             :         /* Map power management I/O space */
     413           0 :         iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg);
     414           0 :         iobase &= VIAPM_PM_BASE_MASK;
     415           0 :         if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
     416           0 :             VIAPM_PM_SIZE, 0, &sc->sc_pm_ioh)) {
     417             :                 /* XXX can't map PM i/o space if ACPI mode */
     418             :                 DPRINTF("%s: can't map PM i/o space\n", DEVNAME(sc));
     419             :                 goto nopm;
     420             :         }
     421             : 
     422             :         /* Check for 32-bit PM timer */
     423           0 :         if (conf & VIAPM_PM_CFG_TMR32)
     424           0 :                 viapm_timecounter.tc_counter_mask = 0xffffffff;
     425             : 
     426             :         /* Register new timecounter */
     427           0 :         viapm_timecounter.tc_priv = sc;
     428           0 :         tc_init(&viapm_timecounter);
     429             : 
     430           0 :         printf("%s: %s-bit timer at %lluHz\n", DEVNAME(sc),
     431           0 :             (viapm_timecounter.tc_counter_mask == 0xffffffff ? "32" : "24"),
     432           0 :             (unsigned long long)viapm_timecounter.tc_frequency);
     433             : 
     434             : nopm:
     435             : 
     436             :         /* HWMon */
     437           0 :         switch (PCI_PRODUCT(pa->pa_id)) {
     438             :         case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
     439             :         case PCI_PRODUCT_VIATECH_VT8231_PWR:
     440             :                 break;
     441             :         default:
     442           0 :                 return;
     443             :         }
     444             : 
     445             :         /* Check if HWMon I/O space is enabled */
     446           0 :         conf = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_CFG);
     447           0 :         if ((conf & VIAPM_HWMON_CFG_HWEN) == 0) {
     448           0 :                 printf("%s: HWM disabled\n", DEVNAME(sc));
     449           0 :                 return;
     450             :         }
     451             : 
     452             :         /* Map HWMon I/O space */
     453           0 :         iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_BASE);
     454           0 :         iobase &= VIAPM_HWMON_BASE_MASK;
     455           0 :         if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
     456           0 :             VIAPM_HWMON_SIZE, 0, &sc->sc_hwmon_ioh)) {
     457           0 :                 printf("%s: can't map HWM i/o space\n", DEVNAME(sc));
     458           0 :                 return;
     459             :         }
     460             : 
     461           0 :         v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_FANCONF);
     462             : 
     463           0 :         sc->sc_fan_div[0] = 1 << ((v >> 4) & 0x3);
     464           0 :         sc->sc_fan_div[1] = 1 << ((v >> 6) & 0x3);
     465             : 
     466           0 :         for (i = 0; i <= 2; i++)
     467           0 :                 sc->sc_data[i].type = SENSOR_TEMP;
     468           0 :         for (i = 3; i <= 4; i++)
     469           0 :                 sc->sc_data[i].type = SENSOR_FANRPM;
     470           0 :         for (i = 5; i <= 9; ++i)
     471           0 :                 sc->sc_data[i].type = SENSOR_VOLTS_DC;
     472             : 
     473           0 :         strlcpy(sc->sc_data[5].desc, "VSENS1",
     474             :             sizeof(sc->sc_data[5].desc));    /* CPU core (2V) */
     475           0 :         strlcpy(sc->sc_data[6].desc, "VSENS2",
     476             :             sizeof(sc->sc_data[6].desc));    /* NB core? (2.5V) */
     477           0 :         strlcpy(sc->sc_data[7].desc, "Vcore",
     478             :             sizeof(sc->sc_data[7].desc));    /* Vcore (3.3V) */
     479           0 :         strlcpy(sc->sc_data[8].desc, "VSENS3",
     480             :             sizeof(sc->sc_data[8].desc));    /* VSENS3 (5V) */
     481           0 :         strlcpy(sc->sc_data[9].desc, "VSENS4",
     482             :             sizeof(sc->sc_data[9].desc));    /* VSENS4 (12V) */
     483             : 
     484             :         /* Get initial set of sensor values. */
     485           0 :         viapm_refresh_sensor_data(sc);
     486             : 
     487             :         /* Register sensors with sysctl */
     488           0 :         strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
     489             :             sizeof(sc->sc_sensordev.xname));
     490           0 :         for (i = 0; i < VIAPM_NUM_SENSORS; ++i)
     491           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_data[i]);
     492           0 :         sensordev_install(&sc->sc_sensordev);
     493             : 
     494             :         /* Refresh sensors data every 1.5 seconds */
     495           0 :         timeout_set(&viapm_timeout, viapm_refresh, sc);
     496           0 :         timeout_add_msec(&viapm_timeout, 1500);
     497           0 : }
     498             : 
     499             : int
     500           0 : viapm_i2c_acquire_bus(void *cookie, int flags)
     501             : {
     502           0 :         struct viapm_softc *sc = cookie;
     503             : 
     504           0 :         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
     505           0 :                 return (0);
     506             : 
     507           0 :         return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
     508           0 : }
     509             : 
     510             : void
     511           0 : viapm_i2c_release_bus(void *cookie, int flags)
     512             : {
     513           0 :         struct viapm_softc *sc = cookie;
     514             : 
     515           0 :         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
     516           0 :                 return;
     517             : 
     518           0 :         rw_exit(&sc->sc_i2c_lock);
     519           0 : }
     520             : 
     521             : int
     522           0 : viapm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     523             :     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
     524             : {
     525           0 :         struct viapm_softc *sc = cookie;
     526             :         u_int8_t *b;
     527             :         u_int8_t ctl, st;
     528             :         int retries;
     529             : 
     530             :         /* Check if there's a transfer already running */
     531           0 :         st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
     532             :         DPRINTF("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
     533             :             "flags 0x%x, status 0x%b\n", DEVNAME(sc), op, addr,
     534             :             cmdlen, len, flags, st, VIAPM_SMB_HS_BITS);
     535           0 :         if (st & VIAPM_SMB_HS_BUSY)
     536           0 :                 return (1);
     537             : 
     538           0 :         if (cold || sc->sc_poll)
     539           0 :                 flags |= I2C_F_POLL;
     540             : 
     541           0 :         if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
     542           0 :                 return (1);
     543             : 
     544             :         /* Setup transfer */
     545           0 :         sc->sc_i2c_xfer.op = op;
     546           0 :         sc->sc_i2c_xfer.buf = buf;
     547           0 :         sc->sc_i2c_xfer.len = len;
     548           0 :         sc->sc_i2c_xfer.flags = flags;
     549           0 :         sc->sc_i2c_xfer.error = 0;
     550             : 
     551             :         /* Set slave address and transfer direction */
     552           0 :         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_TXSLVA,
     553             :             VIAPM_SMB_TXSLVA_ADDR(addr) |
     554             :             (I2C_OP_READ_P(op) ? VIAPM_SMB_TXSLVA_READ : 0));
     555             : 
     556             :         b = (void *)cmdbuf;
     557           0 :         if (cmdlen > 0)
     558             :                 /* Set command byte */
     559           0 :                 bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
     560             :                     VIAPM_SMB_HCMD, b[0]);
     561             : 
     562           0 :         if (I2C_OP_WRITE_P(op)) {
     563             :                 /* Write data */
     564             :                 b = buf;
     565           0 :                 if (len > 0)
     566           0 :                         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
     567             :                             VIAPM_SMB_HD0, b[0]);
     568           0 :                 if (len > 1)
     569           0 :                         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
     570             :                             VIAPM_SMB_HD1, b[1]);
     571             :         }
     572             : 
     573             :         /* Set SMBus command */
     574           0 :         if (len == 0)
     575           0 :                 ctl = VIAPM_SMB_HC_CMD_BYTE;
     576           0 :         else if (len == 1)
     577           0 :                 ctl = VIAPM_SMB_HC_CMD_BDATA;
     578           0 :         else if (len == 2)
     579             :                 ctl = VIAPM_SMB_HC_CMD_WDATA;
     580             :         else
     581           0 :                 panic("%s: unexpected len %zd", __func__, len);
     582             : 
     583           0 :         if ((flags & I2C_F_POLL) == 0)
     584           0 :                 ctl |= VIAPM_SMB_HC_INTREN;
     585             : 
     586             :         /* Start transaction */
     587           0 :         ctl |= VIAPM_SMB_HC_START;
     588           0 :         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC, ctl);
     589             : 
     590           0 :         if (flags & I2C_F_POLL) {
     591             :                 /* Poll for completion */
     592           0 :                 DELAY(VIAPM_SMBUS_DELAY);
     593           0 :                 for (retries = 1000; retries > 0; retries--) {
     594           0 :                         st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
     595             :                             VIAPM_SMB_HS);
     596           0 :                         if ((st & VIAPM_SMB_HS_BUSY) == 0)
     597             :                                 break;
     598           0 :                         DELAY(VIAPM_SMBUS_DELAY);
     599             :                 }
     600           0 :                 if (st & VIAPM_SMB_HS_BUSY)
     601             :                         goto timeout;
     602           0 :                 viapm_intr(sc);
     603           0 :         } else {
     604             :                 /* Wait for interrupt */
     605           0 :                 if (tsleep(sc, PRIBIO, "iicexec", VIAPM_SMBUS_TIMEOUT * hz))
     606             :                         goto timeout;
     607             :         }
     608             : 
     609           0 :         if (sc->sc_i2c_xfer.error)
     610           0 :                 return (1);
     611             : 
     612           0 :         return (0);
     613             : 
     614             : timeout:
     615             :         /*
     616             :          * Transfer timeout. Kill the transaction and clear status bits.
     617             :          */
     618           0 :         printf("%s: timeout, status 0x%b\n", DEVNAME(sc), st,
     619             :             VIAPM_SMB_HS_BITS);
     620           0 :         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC,
     621             :             VIAPM_SMB_HC_KILL);
     622           0 :         DELAY(VIAPM_SMBUS_DELAY);
     623           0 :         st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
     624           0 :         if ((st & VIAPM_SMB_HS_FAILED) == 0)
     625           0 :                 printf("%s: transaction abort failed, status 0x%b\n",
     626             :                     DEVNAME(sc), st, VIAPM_SMB_HS_BITS);
     627           0 :         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS, st);
     628           0 :         return (1);
     629           0 : }
     630             : 
     631             : int
     632           0 : viapm_intr(void *arg)
     633             : {
     634           0 :         struct viapm_softc *sc = arg;
     635             :         u_int8_t st;
     636             :         u_int8_t *b;
     637             :         size_t len;
     638             : 
     639             :         /* Read status */
     640           0 :         st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
     641           0 :         if ((st & VIAPM_SMB_HS_BUSY) != 0 || (st & (VIAPM_SMB_HS_INTR |
     642             :             VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
     643           0 :             VIAPM_SMB_HS_FAILED)) == 0)
     644             :                 /* Interrupt was not for us */
     645           0 :                 return (0);
     646             : 
     647             :         DPRINTF("%s: intr st 0x%b\n", DEVNAME(sc), st, VIAPM_SMB_HS_BITS);
     648             : 
     649             :         /* Clear status bits */
     650           0 :         bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS, st);
     651             : 
     652             :         /* Check for errors */
     653           0 :         if (st & (VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
     654             :             VIAPM_SMB_HS_FAILED)) {
     655           0 :                 sc->sc_i2c_xfer.error = 1;
     656           0 :                 goto done;
     657             :         }
     658             : 
     659           0 :         if (st & VIAPM_SMB_HS_INTR) {
     660           0 :                 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
     661             :                         goto done;
     662             : 
     663             :                 /* Read data */
     664           0 :                 b = sc->sc_i2c_xfer.buf;
     665           0 :                 len = sc->sc_i2c_xfer.len;
     666           0 :                 if (len > 0)
     667           0 :                         b[0] = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
     668             :                             VIAPM_SMB_HD0);
     669           0 :                 if (len > 1)
     670           0 :                         b[1] = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
     671             :                             VIAPM_SMB_HD1);
     672             :         }
     673             : 
     674             : done:
     675           0 :         if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
     676           0 :                 wakeup(sc);
     677           0 :         return (1);
     678           0 : }
     679             : 
     680             : int
     681           0 : val_to_uK(unsigned int val)
     682             : {
     683           0 :         int i = val / 4;
     684           0 :         int j = val % 4;
     685             : 
     686           0 :         KASSERT(i >= 0 && i <= 255);
     687             : 
     688           0 :         if (j == 0 || i == 255)
     689           0 :                 return val_to_temp[i] * 10000;
     690             : 
     691             :         /* is linear interpolation ok? */
     692           0 :         return (val_to_temp[i] * (4 - j) +
     693           0 :             val_to_temp[i + 1] * j) * 2500 /* really: / 4 * 10000 */ ;
     694           0 : }
     695             : 
     696             : int
     697           0 : val_to_rpm(unsigned int val, int div)
     698             : {
     699           0 :         if (val == 0)
     700           0 :                 return 0;
     701             : 
     702           0 :         return 1350000 / val / div;
     703           0 : }
     704             : 
     705             : long
     706           0 : val_to_uV(unsigned int val, int index)
     707             : {
     708             :         static const long mult[] =
     709             :             {1250000, 1250000, 1670000, 2600000, 6300000};
     710             : 
     711           0 :         KASSERT(index >= 0 && index <= 4);
     712             : 
     713           0 :         return (25LL * val + 133) * mult[index] / 2628;
     714             : }
     715             : 
     716             : void
     717           0 : viapm_refresh_sensor_data(struct viapm_softc *sc)
     718             : {
     719             :         int i;
     720             :         u_int8_t v, v2;
     721             : 
     722             :         /* temperature */
     723           0 :         v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TIRQ);
     724           0 :         v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS1);
     725             :         DPRINTF("%s: TSENS1 = %d\n", DEVNAME(sc), (v2 << 2) | (v >> 6));
     726           0 :         sc->sc_data[0].value = val_to_uK((v2 << 2) | (v >> 6));
     727             : 
     728           0 :         v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TLOW);
     729           0 :         v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS2);
     730             :         DPRINTF("%s: TSENS2 = %d\n", DEVNAME(sc), (v2 << 2) | ((v >> 4) & 0x3));
     731           0 :         sc->sc_data[1].value = val_to_uK((v2 << 2) | ((v >> 4) & 0x3));
     732             : 
     733           0 :         v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS3);
     734             :         DPRINTF("%s: TSENS3 = %d\n", DEVNAME(sc), (v2 << 2) | (v >> 6));
     735           0 :         sc->sc_data[2].value = val_to_uK((v2 << 2) | (v >> 6));
     736             : 
     737             :         /* fan */
     738           0 :         for (i = 3; i <= 4; i++) {
     739           0 :                 v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh,
     740             :                     VIAPM_HWMON_FAN1 + i - 3);
     741             :                 DPRINTF("%s: FAN%d = %d / %d\n", DEVNAME(sc), i - 3, v,
     742             :                     sc->sc_fan_div[i - 3]);
     743           0 :                 sc->sc_data[i].value = val_to_rpm(v, sc->sc_fan_div[i - 3]);
     744             :         }
     745             : 
     746             :         /* voltage */
     747           0 :         for (i = 5; i <= 9; i++) {
     748           0 :                 v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh,
     749             :                     VIAPM_HWMON_VSENS1 + i - 5);
     750             :                 DPRINTF("%s: V%d = %d\n", DEVNAME(sc), i - 5, v);
     751           0 :                 sc->sc_data[i].value = val_to_uV(v, i - 5);
     752             :         }
     753           0 : }
     754             : 
     755             : void
     756           0 : viapm_refresh(void *arg)
     757             : {
     758           0 :         struct viapm_softc *sc = (struct viapm_softc *)arg;
     759             : 
     760           0 :         viapm_refresh_sensor_data(sc);
     761           0 :         timeout_add_msec(&viapm_timeout, 1500);
     762           0 : }
     763             : 
     764             : u_int
     765           0 : viapm_get_timecount(struct timecounter *tc)
     766             : {
     767           0 :         struct viapm_softc *sc = tc->tc_priv;
     768             :         u_int u1, u2, u3;
     769             : 
     770           0 :         u2 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
     771           0 :         u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
     772           0 :         do {
     773             :                 u1 = u2;
     774             :                 u2 = u3;
     775           0 :                 u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
     776           0 :         } while (u1 > u2 || u2 > u3);
     777             : 
     778           0 :         return (u2);
     779             : }

Generated by: LCOV version 1.13