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/dev/amdpm/amdpm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
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 #define AMDPM_VENDORID_HYGON 0x1d94
   71 
   72 /* nVidia nForce chipset */
   73 #define AMDPM_VENDORID_NVIDIA 0x10de
   74 #define AMDPM_DEVICEID_NF_SMB 0x01b4
   75 
   76 /* PCI Configuration space registers */
   77 #define AMDPCI_PMBASE 0x58
   78 #define NFPCI_PMBASE  0x14
   79 
   80 #define AMDPCI_GEN_CONFIG_PM 0x41
   81 #define AMDPCI_PMIOEN (1<<7)
   82 
   83 #define AMDPCI_SCIINT_CONFIG_PM 0x42
   84 #define AMDPCI_SCISEL_IRQ11 11
   85 
   86 #define AMDPCI_REVID 0x08
   87 
   88 /*
   89  * I/O registers.
   90  * Base address programmed via AMDPCI_PMBASE.
   91  */
   92 
   93 #define AMDSMB_GLOBAL_STATUS (0x00)
   94 #define AMDSMB_GS_TO_STS (1<<5)
   95 #define AMDSMB_GS_HCYC_STS (1<<4)
   96 #define AMDSMB_GS_HST_STS (1<<3)
   97 #define AMDSMB_GS_PRERR_STS (1<<2)
   98 #define AMDSMB_GS_COL_STS (1<<1)
   99 #define AMDSMB_GS_ABRT_STS (1<<0)
  100 #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)
  101 
  102 #define AMDSMB_GLOBAL_ENABLE (0x02)
  103 #define AMDSMB_GE_ABORT (1<<5)
  104 #define AMDSMB_GE_HCYC_EN (1<<4)
  105 #define AMDSMB_GE_HOST_STC (1<<3)
  106 #define AMDSMB_GE_CYC_QUICK 0
  107 #define AMDSMB_GE_CYC_BYTE 1
  108 #define AMDSMB_GE_CYC_BDATA 2
  109 #define AMDSMB_GE_CYC_WDATA 3
  110 #define AMDSMB_GE_CYC_PROCCALL 4
  111 #define AMDSMB_GE_CYC_BLOCK 5
  112 
  113 #define LSB             0x1     /* XXX: Better name: Read/Write? */
  114 
  115 #define AMDSMB_HSTADDR  (0x04)
  116 #define AMDSMB_HSTDATA  (0x06)
  117 #define AMDSMB_HSTCMD   (0x08)
  118 #define AMDSMB_HSTDFIFO (0x09)
  119 #define AMDSMB_HSLVDATA (0x0A)
  120 #define AMDSMB_HSLVDA   (0x0C)
  121 #define AMDSMB_HSLVDDR  (0x0E)
  122 #define AMDSMB_SNPADDR  (0x0F)
  123 
  124 struct amdpm_softc {
  125         int base;
  126         int rid;
  127         struct resource *res;
  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_read_1(amdpm->res, register))
  138 #define AMDPM_SMBOUTB(amdpm,register,value) \
  139         (bus_write_1(amdpm->res, register, value))
  140 #define AMDPM_SMBINW(amdpm,register) \
  141         (bus_read_2(amdpm->res, register))
  142 #define AMDPM_SMBOUTW(amdpm,register,value) \
  143         (bus_write_2(amdpm->res, 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             pci_get_vendor(dev) == AMDPM_VENDORID_HYGON)
  206                 amdpm_sc->rid = AMDPCI_PMBASE;
  207         else
  208                 amdpm_sc->rid = NFPCI_PMBASE;
  209         amdpm_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  210                 &amdpm_sc->rid, RF_ACTIVE);
  211 
  212         if (amdpm_sc->res == NULL) {
  213                 device_printf(dev, "could not map i/o space\n");
  214                 return (ENXIO);
  215         }            
  216 
  217         mtx_init(&amdpm_sc->lock, device_get_nameunit(dev), "amdpm", MTX_DEF);
  218 
  219         /* Allocate a new smbus device */
  220         amdpm_sc->smbus = device_add_child(dev, "smbus", -1);
  221         if (!amdpm_sc->smbus) {
  222                 amdpm_detach(dev);
  223                 return (EINVAL);
  224         }
  225 
  226         bus_generic_attach(dev);
  227 
  228         return (0);
  229 }
  230 
  231 static int
  232 amdpm_detach(device_t dev)
  233 {
  234         struct amdpm_softc *amdpm_sc = device_get_softc(dev);
  235 
  236         if (amdpm_sc->smbus) {
  237                 device_delete_child(dev, amdpm_sc->smbus);
  238                 amdpm_sc->smbus = NULL;
  239         }
  240 
  241         mtx_destroy(&amdpm_sc->lock);
  242         if (amdpm_sc->res)
  243                 bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid,
  244                                      amdpm_sc->res);
  245 
  246         return (0);
  247 }
  248 
  249 static int
  250 amdpm_callback(device_t dev, int index, void *data)
  251 {
  252         int error = 0;
  253 
  254         switch (index) {
  255         case SMB_REQUEST_BUS:
  256         case SMB_RELEASE_BUS:
  257                 break;
  258         default:
  259                 error = EINVAL;
  260         }
  261 
  262         return (error);
  263 }
  264 
  265 static int
  266 amdpm_clear(struct amdpm_softc *sc)
  267 {
  268 
  269         AMDPM_LOCK_ASSERT(sc);
  270         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
  271         DELAY(10);
  272 
  273         return (0);
  274 }
  275 
  276 #if 0
  277 static int
  278 amdpm_abort(struct amdpm_softc *sc)
  279 {
  280         u_short l;
  281 
  282         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  283         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
  284 
  285         return (0);
  286 }
  287 #endif
  288 
  289 static int
  290 amdpm_idle(struct amdpm_softc *sc)
  291 {
  292         u_short sts;
  293 
  294         AMDPM_LOCK_ASSERT(sc);
  295         sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
  296 
  297         AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts));
  298 
  299         return (~(sts & AMDSMB_GS_HST_STS));
  300 }
  301 
  302 /*
  303  * Poll the SMBus controller
  304  */
  305 static int
  306 amdpm_wait(struct amdpm_softc *sc)
  307 {
  308         int count = 10000;
  309         u_short sts = 0;
  310         int error;
  311 
  312         AMDPM_LOCK_ASSERT(sc);
  313         /* Wait for command to complete (SMBus controller is idle) */
  314         while(count--) {
  315                 DELAY(10);
  316                 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
  317                 if (!(sts & AMDSMB_GS_HST_STS))
  318                         break;
  319         }
  320 
  321         AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count));
  322 
  323         error = SMB_ENOERR;
  324 
  325         if (!count)
  326                 error |= SMB_ETIMEOUT;
  327 
  328         if (sts & AMDSMB_GS_ABRT_STS)
  329                 error |= SMB_EABORT;
  330 
  331         if (sts & AMDSMB_GS_COL_STS)
  332                 error |= SMB_ENOACK;
  333 
  334         if (sts & AMDSMB_GS_PRERR_STS)
  335                 error |= SMB_EBUSERR;
  336 
  337         if (error != SMB_ENOERR)
  338                 amdpm_clear(sc);
  339 
  340         return (error);
  341 }
  342 
  343 static int
  344 amdpm_quick(device_t dev, u_char slave, int how)
  345 {
  346         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  347         int error;
  348         u_short l;
  349 
  350         AMDPM_LOCK(sc);
  351         amdpm_clear(sc);
  352         if (!amdpm_idle(sc)) {
  353                 AMDPM_UNLOCK(sc);
  354                 return (EBUSY);
  355         }
  356 
  357         switch (how) {
  358         case SMB_QWRITE:
  359                 AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave));
  360                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  361                 break;
  362         case SMB_QREAD:
  363                 AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave));
  364                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  365                 break;
  366         default:
  367                 panic("%s: unknown QUICK command (%x)!", __func__, how);
  368         }
  369         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  370         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
  371 
  372         error = amdpm_wait(sc);
  373 
  374         AMDPM_DEBUG(printf(", error=0x%x\n", error));
  375         AMDPM_UNLOCK(sc);
  376 
  377         return (error);
  378 }
  379 
  380 static int
  381 amdpm_sendb(device_t dev, u_char slave, char byte)
  382 {
  383         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  384         int error;
  385         u_short l;
  386 
  387         AMDPM_LOCK(sc);
  388         amdpm_clear(sc);
  389         if (!amdpm_idle(sc)) {
  390                 AMDPM_UNLOCK(sc);
  391                 return (SMB_EBUSY);
  392         }
  393 
  394         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  395         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
  396         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  397         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
  398 
  399         error = amdpm_wait(sc);
  400 
  401         AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
  402         AMDPM_UNLOCK(sc);
  403 
  404         return (error);
  405 }
  406 
  407 static int
  408 amdpm_recvb(device_t dev, u_char slave, char *byte)
  409 {
  410         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  411         int error;
  412         u_short l;
  413 
  414         AMDPM_LOCK(sc);
  415         amdpm_clear(sc);
  416         if (!amdpm_idle(sc)) {
  417                 AMDPM_UNLOCK(sc);
  418                 return (SMB_EBUSY);
  419         }
  420 
  421         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  422         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  423         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
  424 
  425         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  426                 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  427 
  428         AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
  429         AMDPM_UNLOCK(sc);
  430 
  431         return (error);
  432 }
  433 
  434 static int
  435 amdpm_writeb(device_t dev, u_char slave, char cmd, char byte)
  436 {
  437         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  438         int error;
  439         u_short l;
  440 
  441         AMDPM_LOCK(sc);
  442         amdpm_clear(sc);
  443         if (!amdpm_idle(sc)) {
  444                 AMDPM_UNLOCK(sc);
  445                 return (SMB_EBUSY);
  446         }
  447 
  448         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  449         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
  450         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  451         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  452         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
  453 
  454         error = amdpm_wait(sc);
  455 
  456         AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
  457         AMDPM_UNLOCK(sc);
  458 
  459         return (error);
  460 }
  461 
  462 static int
  463 amdpm_readb(device_t dev, u_char slave, char cmd, char *byte)
  464 {
  465         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  466         int error;
  467         u_short l;
  468 
  469         AMDPM_LOCK(sc);
  470         amdpm_clear(sc);
  471         if (!amdpm_idle(sc)) {
  472                 AMDPM_UNLOCK(sc);
  473                 return (SMB_EBUSY);
  474         }
  475 
  476         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  477         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  478         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  479         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
  480 
  481         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  482                 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  483 
  484         AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
  485         AMDPM_UNLOCK(sc);
  486 
  487         return (error);
  488 }
  489 
  490 static int
  491 amdpm_writew(device_t dev, u_char slave, char cmd, short word)
  492 {
  493         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  494         int error;
  495         u_short l;
  496 
  497         AMDPM_LOCK(sc);
  498         amdpm_clear(sc);
  499         if (!amdpm_idle(sc)) {
  500                 AMDPM_UNLOCK(sc);
  501                 return (SMB_EBUSY);
  502         }
  503 
  504         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  505         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
  506         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  507         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  508         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
  509 
  510         error = amdpm_wait(sc);
  511 
  512         AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
  513         AMDPM_UNLOCK(sc);
  514 
  515         return (error);
  516 }
  517 
  518 static int
  519 amdpm_readw(device_t dev, u_char slave, char cmd, short *word)
  520 {
  521         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  522         int error;
  523         u_short l;
  524 
  525         AMDPM_LOCK(sc);
  526         amdpm_clear(sc);
  527         if (!amdpm_idle(sc)) {
  528                 AMDPM_UNLOCK(sc);
  529                 return (SMB_EBUSY);
  530         }
  531 
  532         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  533         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  534         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  535         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
  536 
  537         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  538                 *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  539 
  540         AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
  541         AMDPM_UNLOCK(sc);
  542 
  543         return (error);
  544 }
  545 
  546 static int
  547 amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  548 {
  549         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  550         u_char i;
  551         int error;
  552         u_short l;
  553 
  554         if (count < 1 || count > 32)
  555                 return (SMB_EINVAL);
  556 
  557         AMDPM_LOCK(sc);
  558         amdpm_clear(sc);
  559         if (!amdpm_idle(sc)) {
  560                 AMDPM_UNLOCK(sc);
  561                 return (SMB_EBUSY);
  562         }
  563 
  564         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  565 
  566         /*
  567          * Do we have to reset the internal 32-byte buffer?
  568          * Can't see how to do this from the data sheet.
  569          */
  570         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, count);
  571 
  572         /* Fill the 32-byte internal buffer */
  573         for (i = 0; i < count; i++) {
  574                 AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[i]);
  575                 DELAY(2);
  576         }
  577         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  578         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  579         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE,
  580             (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
  581 
  582         error = amdpm_wait(sc);
  583 
  584         AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
  585         AMDPM_UNLOCK(sc);
  586 
  587         return (error);
  588 }
  589 
  590 static int
  591 amdpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  592 {
  593         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  594         u_char data, len, i;
  595         int error;
  596         u_short l;
  597 
  598         if (*count < 1 || *count > 32)
  599                 return (SMB_EINVAL);
  600 
  601         AMDPM_LOCK(sc);
  602         amdpm_clear(sc);
  603         if (!amdpm_idle(sc)) {
  604                 AMDPM_UNLOCK(sc);
  605                 return (SMB_EBUSY);
  606         }
  607 
  608         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  609 
  610         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  611 
  612         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  613         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE,
  614             (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
  615                 
  616         if ((error = amdpm_wait(sc)) != SMB_ENOERR)
  617                 goto error;
  618 
  619         len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  620 
  621         /* Read the 32-byte internal buffer */
  622         for (i = 0; i < len; i++) {
  623                 data = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
  624                 if (i < *count)
  625                         buf[i] = data;
  626                 DELAY(2);
  627         }
  628         *count = len;
  629 
  630 error:
  631         AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
  632         AMDPM_UNLOCK(sc);
  633 
  634         return (error);
  635 }
  636 
  637 static devclass_t amdpm_devclass;
  638 
  639 static device_method_t amdpm_methods[] = {
  640         /* Device interface */
  641         DEVMETHOD(device_probe,         amdpm_probe),
  642         DEVMETHOD(device_attach,        amdpm_attach),
  643         DEVMETHOD(device_detach,        amdpm_detach),
  644 
  645         /* SMBus interface */
  646         DEVMETHOD(smbus_callback,       amdpm_callback),
  647         DEVMETHOD(smbus_quick,          amdpm_quick),
  648         DEVMETHOD(smbus_sendb,          amdpm_sendb),
  649         DEVMETHOD(smbus_recvb,          amdpm_recvb),
  650         DEVMETHOD(smbus_writeb,         amdpm_writeb),
  651         DEVMETHOD(smbus_readb,          amdpm_readb),
  652         DEVMETHOD(smbus_writew,         amdpm_writew),
  653         DEVMETHOD(smbus_readw,          amdpm_readw),
  654         DEVMETHOD(smbus_bwrite,         amdpm_bwrite),
  655         DEVMETHOD(smbus_bread,          amdpm_bread),
  656         { 0, 0 }
  657 };
  658 
  659 static driver_t amdpm_driver = {
  660         "amdpm",
  661         amdpm_methods,
  662         sizeof(struct amdpm_softc),
  663 };
  664 
  665 DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
  666 DRIVER_MODULE(smbus, amdpm, smbus_driver, smbus_devclass, 0, 0);
  667 
  668 MODULE_DEPEND(amdpm, pci, 1, 1, 1);
  669 MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  670 MODULE_VERSION(amdpm, 1);

Cache object: 7965b2b62b410773db93f8d2da0d5b9e


[ 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.