The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pci/amdpm.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000 Matthew C. Forman
    3  *
    4  * Based (heavily) on alpm.c which is:
    5  *
    6  * Copyright (c) 1998, 1999 Nicolas Souchu
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /*
   32  * Power management function/SMBus function support for the AMD 756 chip.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD$");
   37 
   38 #include <sys/param.h>
   39 #include <sys/bus.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/module.h>
   43 #include <sys/mutex.h>
   44 #include <sys/systm.h>
   45 
   46 #include <machine/bus.h>
   47 #include <machine/resource.h>
   48 #include <sys/rman.h>
   49 
   50 #include <dev/pci/pcivar.h>
   51 #include <dev/pci/pcireg.h>
   52 
   53 #include <dev/smbus/smbconf.h>
   54 #include "smbus_if.h"
   55 
   56 #define AMDPM_DEBUG(x)  if (amdpm_debug) (x)
   57 
   58 #ifdef DEBUG
   59 static int amdpm_debug = 1;
   60 #else
   61 static int amdpm_debug = 0;
   62 #endif
   63 
   64 #define AMDPM_VENDORID_AMD 0x1022
   65 #define AMDPM_DEVICEID_AMD756PM 0x740b
   66 #define AMDPM_DEVICEID_AMD766PM 0x7413
   67 #define AMDPM_DEVICEID_AMD768PM 0x7443
   68 #define AMDPM_DEVICEID_AMD8111PM 0x746B
   69 
   70 /* nVidia nForce chipset */
   71 #define AMDPM_VENDORID_NVIDIA 0x10de
   72 #define AMDPM_DEVICEID_NF_SMB 0x01b4
   73 
   74 /* PCI Configuration space registers */
   75 #define AMDPCI_PMBASE 0x58
   76 #define NFPCI_PMBASE  0x14
   77 
   78 #define AMDPCI_GEN_CONFIG_PM 0x41
   79 #define AMDPCI_PMIOEN (1<<7)
   80 
   81 #define AMDPCI_SCIINT_CONFIG_PM 0x42
   82 #define AMDPCI_SCISEL_IRQ11 11
   83 
   84 #define AMDPCI_REVID 0x08
   85 
   86 /*
   87  * I/O registers.
   88  * Base address programmed via AMDPCI_PMBASE.
   89  */
   90 
   91 #define AMDSMB_GLOBAL_STATUS (0x00)
   92 #define AMDSMB_GS_TO_STS (1<<5)
   93 #define AMDSMB_GS_HCYC_STS (1<<4)
   94 #define AMDSMB_GS_HST_STS (1<<3)
   95 #define AMDSMB_GS_PRERR_STS (1<<2)
   96 #define AMDSMB_GS_COL_STS (1<<1)
   97 #define AMDSMB_GS_ABRT_STS (1<<0)
   98 #define AMDSMB_GS_CLEAR_STS (AMDSMB_GS_TO_STS|AMDSMB_GS_HCYC_STS|AMDSMB_GS_PRERR_STS|AMDSMB_GS_COL_STS|AMDSMB_GS_ABRT_STS)
   99 
  100 #define AMDSMB_GLOBAL_ENABLE (0x02)
  101 #define AMDSMB_GE_ABORT (1<<5)
  102 #define AMDSMB_GE_HCYC_EN (1<<4)
  103 #define AMDSMB_GE_HOST_STC (1<<3)
  104 #define AMDSMB_GE_CYC_QUICK 0
  105 #define AMDSMB_GE_CYC_BYTE 1
  106 #define AMDSMB_GE_CYC_BDATA 2
  107 #define AMDSMB_GE_CYC_WDATA 3
  108 #define AMDSMB_GE_CYC_PROCCALL 4
  109 #define AMDSMB_GE_CYC_BLOCK 5
  110 
  111 #define LSB             0x1     /* XXX: Better name: Read/Write? */
  112 
  113 #define AMDSMB_HSTADDR  (0x04)
  114 #define AMDSMB_HSTDATA  (0x06)
  115 #define AMDSMB_HSTCMD   (0x08)
  116 #define AMDSMB_HSTDFIFO (0x09)
  117 #define AMDSMB_HSLVDATA (0x0A)
  118 #define AMDSMB_HSLVDA   (0x0C)
  119 #define AMDSMB_HSLVDDR  (0x0E)
  120 #define AMDSMB_SNPADDR  (0x0F)
  121 
  122 struct amdpm_softc {
  123         int base;
  124         int rid;
  125         struct resource *res;
  126         bus_space_tag_t smbst;
  127         bus_space_handle_t smbsh;
  128         device_t smbus;
  129         struct mtx lock;
  130 };
  131 
  132 #define AMDPM_LOCK(amdpm)               mtx_lock(&(amdpm)->lock)
  133 #define AMDPM_UNLOCK(amdpm)             mtx_unlock(&(amdpm)->lock)
  134 #define AMDPM_LOCK_ASSERT(amdpm)        mtx_assert(&(amdpm)->lock, MA_OWNED)
  135 
  136 #define AMDPM_SMBINB(amdpm,register) \
  137         (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register))
  138 #define AMDPM_SMBOUTB(amdpm,register,value) \
  139         (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value))
  140 #define AMDPM_SMBINW(amdpm,register) \
  141         (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register))
  142 #define AMDPM_SMBOUTW(amdpm,register,value) \
  143         (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value))
  144 
  145 static int      amdpm_detach(device_t dev);
  146 
  147 static int
  148 amdpm_probe(device_t dev)
  149 {
  150         u_long base;
  151         u_int16_t vid;
  152         u_int16_t did;
  153 
  154         vid = pci_get_vendor(dev);
  155         did = pci_get_device(dev);
  156         if ((vid == AMDPM_VENDORID_AMD) &&
  157             ((did == AMDPM_DEVICEID_AMD756PM) ||
  158              (did == AMDPM_DEVICEID_AMD766PM) ||
  159              (did == AMDPM_DEVICEID_AMD768PM) ||
  160              (did == AMDPM_DEVICEID_AMD8111PM))) {
  161                 device_set_desc(dev, "AMD 756/766/768/8111 Power Management Controller");
  162 
  163                 /* 
  164                  * We have to do this, since the BIOS won't give us the
  165                  * resource info (not mine, anyway).
  166                  */
  167                 base = pci_read_config(dev, AMDPCI_PMBASE, 4);
  168                 base &= 0xff00;
  169                 bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE,
  170                                  base+0xe0, 32);
  171                 return (BUS_PROBE_DEFAULT);
  172         }
  173 
  174         if ((vid == AMDPM_VENDORID_NVIDIA) &&
  175             (did == AMDPM_DEVICEID_NF_SMB)) {
  176                 device_set_desc(dev, "nForce SMBus Controller");
  177 
  178                 /* 
  179                 * We have to do this, since the BIOS won't give us the
  180                 * resource info (not mine, anyway).
  181                 */
  182                 base = pci_read_config(dev, NFPCI_PMBASE, 4);
  183                 base &= 0xff00;
  184                 bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE,
  185                                  base, 32);
  186 
  187                 return (BUS_PROBE_DEFAULT);
  188         }
  189 
  190         return ENXIO;
  191 }
  192 
  193 static int
  194 amdpm_attach(device_t dev)
  195 {
  196         struct amdpm_softc *amdpm_sc = device_get_softc(dev);
  197         u_char val_b;
  198         
  199         /* Enable I/O block access */
  200         val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1);
  201         pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1);
  202 
  203         /* Allocate I/O space */
  204         if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD)
  205                 amdpm_sc->rid = AMDPCI_PMBASE;
  206         else
  207                 amdpm_sc->rid = NFPCI_PMBASE;
  208         amdpm_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  209                 &amdpm_sc->rid, RF_ACTIVE);
  210         
  211         if (amdpm_sc->res == NULL) {
  212                 device_printf(dev, "could not map i/o space\n");
  213                 return (ENXIO);
  214         }            
  215 
  216         amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res);
  217         amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res);
  218         mtx_init(&amdpm_sc->lock, device_get_nameunit(dev), "amdpm", MTX_DEF);
  219 
  220         /* Allocate a new smbus device */
  221         amdpm_sc->smbus = device_add_child(dev, "smbus", -1);
  222         if (!amdpm_sc->smbus) {
  223                 amdpm_detach(dev);
  224                 return (EINVAL);
  225         }
  226 
  227         bus_generic_attach(dev);
  228 
  229         return (0);
  230 }
  231 
  232 static int
  233 amdpm_detach(device_t dev)
  234 {
  235         struct amdpm_softc *amdpm_sc = device_get_softc(dev);
  236 
  237         if (amdpm_sc->smbus) {
  238                 device_delete_child(dev, amdpm_sc->smbus);
  239                 amdpm_sc->smbus = NULL;
  240         }
  241 
  242         mtx_destroy(&amdpm_sc->lock);
  243         if (amdpm_sc->res)
  244                 bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid,
  245                                      amdpm_sc->res);
  246 
  247         return (0);
  248 }
  249 
  250 static int
  251 amdpm_callback(device_t dev, int index, void *data)
  252 {
  253         int error = 0;
  254 
  255         switch (index) {
  256         case SMB_REQUEST_BUS:
  257         case SMB_RELEASE_BUS:
  258                 break;
  259         default:
  260                 error = EINVAL;
  261         }
  262 
  263         return (error);
  264 }
  265 
  266 static int
  267 amdpm_clear(struct amdpm_softc *sc)
  268 {
  269 
  270         AMDPM_LOCK_ASSERT(sc);
  271         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
  272         DELAY(10);
  273 
  274         return (0);
  275 }
  276 
  277 #if 0
  278 static int
  279 amdpm_abort(struct amdpm_softc *sc)
  280 {
  281         u_short l;
  282         
  283         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  284         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
  285 
  286         return (0);
  287 }
  288 #endif
  289 
  290 static int
  291 amdpm_idle(struct amdpm_softc *sc)
  292 {
  293         u_short sts;
  294 
  295         AMDPM_LOCK_ASSERT(sc);
  296         sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
  297 
  298         AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts));
  299 
  300         return (~(sts & AMDSMB_GS_HST_STS));
  301 }
  302 
  303 /*
  304  * Poll the SMBus controller
  305  */
  306 static int
  307 amdpm_wait(struct amdpm_softc *sc)
  308 {
  309         int count = 10000;
  310         u_short sts = 0;
  311         int error;
  312 
  313         AMDPM_LOCK_ASSERT(sc);
  314         /* Wait for command to complete (SMBus controller is idle) */
  315         while(count--) {
  316                 DELAY(10);
  317                 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
  318                 if (!(sts & AMDSMB_GS_HST_STS))
  319                         break;
  320         }
  321 
  322         AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count));
  323 
  324         error = SMB_ENOERR;
  325 
  326         if (!count)
  327                 error |= SMB_ETIMEOUT;
  328 
  329         if (sts & AMDSMB_GS_ABRT_STS)
  330                 error |= SMB_EABORT;
  331 
  332         if (sts & AMDSMB_GS_COL_STS)
  333                 error |= SMB_ENOACK;
  334 
  335         if (sts & AMDSMB_GS_PRERR_STS)
  336                 error |= SMB_EBUSERR;
  337 
  338         if (error != SMB_ENOERR)
  339                 amdpm_clear(sc);
  340 
  341         return (error);
  342 }
  343 
  344 static int
  345 amdpm_quick(device_t dev, u_char slave, int how)
  346 {
  347         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  348         int error;
  349         u_short l;
  350 
  351         AMDPM_LOCK(sc);
  352         amdpm_clear(sc);
  353         if (!amdpm_idle(sc)) {
  354                 AMDPM_UNLOCK(sc);
  355                 return (EBUSY);
  356         }
  357 
  358         switch (how) {
  359         case SMB_QWRITE:
  360                 AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave));
  361                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  362                 break;
  363         case SMB_QREAD:
  364                 AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave));
  365                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  366                 break;
  367         default:
  368                 panic("%s: unknown QUICK command (%x)!", __func__, how);
  369         }
  370         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  371         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
  372 
  373         error = amdpm_wait(sc);
  374 
  375         AMDPM_DEBUG(printf(", error=0x%x\n", error));
  376         AMDPM_UNLOCK(sc);
  377 
  378         return (error);
  379 }
  380 
  381 static int
  382 amdpm_sendb(device_t dev, u_char slave, char byte)
  383 {
  384         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  385         int error;
  386         u_short l;
  387 
  388         AMDPM_LOCK(sc);
  389         amdpm_clear(sc);
  390         if (!amdpm_idle(sc)) {
  391                 AMDPM_UNLOCK(sc);
  392                 return (SMB_EBUSY);
  393         }
  394 
  395         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  396         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
  397         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  398         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
  399 
  400         error = amdpm_wait(sc);
  401 
  402         AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
  403         AMDPM_UNLOCK(sc);
  404 
  405         return (error);
  406 }
  407 
  408 static int
  409 amdpm_recvb(device_t dev, u_char slave, char *byte)
  410 {
  411         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  412         int error;
  413         u_short l;
  414 
  415         AMDPM_LOCK(sc);
  416         amdpm_clear(sc);
  417         if (!amdpm_idle(sc)) {
  418                 AMDPM_UNLOCK(sc);
  419                 return (SMB_EBUSY);
  420         }
  421 
  422         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  423         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  424         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
  425 
  426         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  427                 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  428 
  429         AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
  430         AMDPM_UNLOCK(sc);
  431 
  432         return (error);
  433 }
  434 
  435 static int
  436 amdpm_writeb(device_t dev, u_char slave, char cmd, char byte)
  437 {
  438         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  439         int error;
  440         u_short l;
  441 
  442         AMDPM_LOCK(sc);
  443         amdpm_clear(sc);
  444         if (!amdpm_idle(sc)) {
  445                 AMDPM_UNLOCK(sc);
  446                 return (SMB_EBUSY);
  447         }
  448 
  449         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  450         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
  451         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  452         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  453         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
  454 
  455         error = amdpm_wait(sc);
  456 
  457         AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
  458         AMDPM_UNLOCK(sc);
  459 
  460         return (error);
  461 }
  462 
  463 static int
  464 amdpm_readb(device_t dev, u_char slave, char cmd, char *byte)
  465 {
  466         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  467         int error;
  468         u_short l;
  469 
  470         AMDPM_LOCK(sc);
  471         amdpm_clear(sc);
  472         if (!amdpm_idle(sc)) {
  473                 AMDPM_UNLOCK(sc);
  474                 return (SMB_EBUSY);
  475         }
  476 
  477         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  478         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  479         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  480         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
  481 
  482         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  483                 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  484 
  485         AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
  486         AMDPM_UNLOCK(sc);
  487 
  488         return (error);
  489 }
  490 
  491 static int
  492 amdpm_writew(device_t dev, u_char slave, char cmd, short word)
  493 {
  494         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  495         int error;
  496         u_short l;
  497 
  498         AMDPM_LOCK(sc);
  499         amdpm_clear(sc);
  500         if (!amdpm_idle(sc)) {
  501                 AMDPM_UNLOCK(sc);
  502                 return (SMB_EBUSY);
  503         }
  504 
  505         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  506         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
  507         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  508         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  509         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
  510 
  511         error = amdpm_wait(sc);
  512 
  513         AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
  514         AMDPM_UNLOCK(sc);
  515 
  516         return (error);
  517 }
  518 
  519 static int
  520 amdpm_readw(device_t dev, u_char slave, char cmd, short *word)
  521 {
  522         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  523         int error;
  524         u_short l;
  525 
  526         AMDPM_LOCK(sc);
  527         amdpm_clear(sc);
  528         if (!amdpm_idle(sc)) {
  529                 AMDPM_UNLOCK(sc);
  530                 return (SMB_EBUSY);
  531         }
  532 
  533         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  534         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  535         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  536         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
  537 
  538         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  539                 *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  540 
  541         AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
  542         AMDPM_UNLOCK(sc);
  543 
  544         return (error);
  545 }
  546 
  547 static int
  548 amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  549 {
  550         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  551         u_char i;
  552         int error;
  553         u_short l;
  554 
  555         if (count < 1 || count > 32)
  556                 return (SMB_EINVAL);
  557 
  558         AMDPM_LOCK(sc);
  559         amdpm_clear(sc);
  560         if (!amdpm_idle(sc)) {
  561                 AMDPM_UNLOCK(sc);
  562                 return (SMB_EBUSY);
  563         }
  564 
  565         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  566         
  567         /*
  568          * Do we have to reset the internal 32-byte buffer?
  569          * Can't see how to do this from the data sheet.
  570          */
  571         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, count);
  572 
  573         /* Fill the 32-byte internal buffer */
  574         for (i = 0; i < count; i++) {
  575                 AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[i]);
  576                 DELAY(2);
  577         }
  578         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  579         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  580         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE,
  581             (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
  582 
  583         error = amdpm_wait(sc);
  584 
  585         AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
  586         AMDPM_UNLOCK(sc);
  587 
  588         return (error);
  589 }
  590 
  591 static int
  592 amdpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  593 {
  594         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  595         u_char data, len, i;
  596         int error;
  597         u_short l;
  598 
  599         if (*count < 1 || *count > 32)
  600                 return (SMB_EINVAL);
  601 
  602         AMDPM_LOCK(sc);
  603         amdpm_clear(sc);
  604         if (!amdpm_idle(sc)) {
  605                 AMDPM_UNLOCK(sc);
  606                 return (SMB_EBUSY);
  607         }
  608 
  609         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  610         
  611         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  612 
  613         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  614         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE,
  615             (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
  616                 
  617         if ((error = amdpm_wait(sc)) != SMB_ENOERR)
  618                 goto error;
  619 
  620         len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  621 
  622         /* Read the 32-byte internal buffer */
  623         for (i = 0; i < len; i++) {
  624                 data = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
  625                 if (i < *count)
  626                         buf[i] = data;
  627                 DELAY(2);
  628         }
  629         *count = len;
  630 
  631 error:
  632         AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
  633         AMDPM_UNLOCK(sc);
  634 
  635         return (error);
  636 }
  637 
  638 static devclass_t amdpm_devclass;
  639 
  640 static device_method_t amdpm_methods[] = {
  641         /* Device interface */
  642         DEVMETHOD(device_probe,         amdpm_probe),
  643         DEVMETHOD(device_attach,        amdpm_attach),
  644         DEVMETHOD(device_detach,        amdpm_detach),
  645         
  646         /* SMBus interface */
  647         DEVMETHOD(smbus_callback,       amdpm_callback),
  648         DEVMETHOD(smbus_quick,          amdpm_quick),
  649         DEVMETHOD(smbus_sendb,          amdpm_sendb),
  650         DEVMETHOD(smbus_recvb,          amdpm_recvb),
  651         DEVMETHOD(smbus_writeb,         amdpm_writeb),
  652         DEVMETHOD(smbus_readb,          amdpm_readb),
  653         DEVMETHOD(smbus_writew,         amdpm_writew),
  654         DEVMETHOD(smbus_readw,          amdpm_readw),
  655         DEVMETHOD(smbus_bwrite,         amdpm_bwrite),
  656         DEVMETHOD(smbus_bread,          amdpm_bread),
  657         
  658         { 0, 0 }
  659 };
  660 
  661 static driver_t amdpm_driver = {
  662         "amdpm",
  663         amdpm_methods,
  664         sizeof(struct amdpm_softc),
  665 };
  666 
  667 DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
  668 DRIVER_MODULE(smbus, amdpm, smbus_driver, smbus_devclass, 0, 0);
  669 
  670 MODULE_DEPEND(amdpm, pci, 1, 1, 1);
  671 MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  672 MODULE_VERSION(amdpm, 1);

Cache object: eea067828fa106be00b59db601b797f3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.