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

Cache object: 7083a2e70e18ae5a2bf64bfaf05031d8


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