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

Cache object: 4dd8e4fd427668bd08b062511b19aab6


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