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: src/sys/pci/amdpm.c,v 1.13.2.1 2005/03/01 08:11:51 imp Exp $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/kernel.h>
   40 #include <sys/systm.h>
   41 #include <sys/module.h>
   42 #include <sys/bus.h>
   43 #include <sys/uio.h>
   44 
   45 #include <machine/bus_pio.h>
   46 #include <machine/bus_memio.h>
   47 #include <machine/bus.h>
   48 #include <machine/clock.h>
   49 #include <machine/resource.h>
   50 #include <sys/rman.h>
   51 
   52 #include <dev/pci/pcivar.h>
   53 #include <dev/pci/pcireg.h>
   54 
   55 #include <dev/iicbus/iiconf.h>
   56 #include <dev/smbus/smbconf.h>
   57 #include "smbus_if.h"
   58 
   59 #define AMDPM_DEBUG(x)  if (amdpm_debug) (x)
   60 
   61 #ifdef DEBUG
   62 static int amdpm_debug = 1;
   63 #else
   64 static int amdpm_debug = 0;
   65 #endif
   66 
   67 #define AMDPM_VENDORID_AMD 0x1022
   68 #define AMDPM_DEVICEID_AMD756PM 0x740b
   69 #define AMDPM_DEVICEID_AMD766PM 0x7413
   70 #define AMDPM_DEVICEID_AMD768PM 0x7443
   71 #define AMDPM_DEVICEID_AMD8111PM 0x746A
   72 
   73 /* nVidia nForce chipset */
   74 #define AMDPM_VENDORID_NVIDIA 0x10de
   75 #define AMDPM_DEVICEID_NF_SMB 0x01b4
   76 
   77 /* PCI Configuration space registers */
   78 #define AMDPCI_PMBASE 0x58
   79 #define NFPCI_PMBASE  0x14
   80 
   81 #define AMDPCI_GEN_CONFIG_PM 0x41
   82 #define AMDPCI_PMIOEN (1<<7)
   83 
   84 #define AMDPCI_SCIINT_CONFIG_PM 0x42
   85 #define AMDPCI_SCISEL_IRQ11 11
   86 
   87 #define AMDPCI_REVID 0x08
   88 
   89 /*
   90  * I/O registers.
   91  * Base address programmed via AMDPCI_PMBASE.
   92  */
   93 
   94 #define AMDSMB_GLOBAL_STATUS (0x00)
   95 #define AMDSMB_GS_TO_STS (1<<5)
   96 #define AMDSMB_GS_HCYC_STS (1<<4)
   97 #define AMDSMB_GS_HST_STS (1<<3)
   98 #define AMDSMB_GS_PRERR_STS (1<<2)
   99 #define AMDSMB_GS_COL_STS (1<<1)
  100 #define AMDSMB_GS_ABRT_STS (1<<0)
  101 #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)
  102 
  103 #define AMDSMB_GLOBAL_ENABLE (0x02)
  104 #define AMDSMB_GE_ABORT (1<<5)
  105 #define AMDSMB_GE_HCYC_EN (1<<4)
  106 #define AMDSMB_GE_HOST_STC (1<<3)
  107 #define AMDSMB_GE_CYC_QUICK 0
  108 #define AMDSMB_GE_CYC_BYTE 1
  109 #define AMDSMB_GE_CYC_BDATA 2
  110 #define AMDSMB_GE_CYC_WDATA 3
  111 #define AMDSMB_GE_CYC_PROCCALL 4
  112 #define AMDSMB_GE_CYC_BLOCK 5
  113 
  114 #define AMDSMB_HSTADDR  (0x04)
  115 #define AMDSMB_HSTDATA  (0x06)
  116 #define AMDSMB_HSTCMD   (0x08)
  117 #define AMDSMB_HSTDFIFO (0x09)
  118 #define AMDSMB_HSLVDATA (0x0A)
  119 #define AMDSMB_HSLVDA   (0x0C)
  120 #define AMDSMB_HSLVDDR  (0x0E)
  121 #define AMDSMB_SNPADDR  (0x0F)
  122 
  123 struct amdpm_softc {
  124         int base;
  125         int rid;
  126         struct resource *res;
  127         bus_space_tag_t smbst;
  128         bus_space_handle_t smbsh;
  129 
  130         device_t smbus;
  131 };
  132 
  133 #define AMDPM_SMBINB(amdpm,register) \
  134         (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register))
  135 #define AMDPM_SMBOUTB(amdpm,register,value) \
  136         (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value))
  137 #define AMDPM_SMBINW(amdpm,register) \
  138         (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register))
  139 #define AMDPM_SMBOUTW(amdpm,register,value) \
  140         (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value))
  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);
  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);
  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         amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res);
  212         amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res);
  213 
  214         /* Allocate a new smbus device */
  215         amdpm_sc->smbus = device_add_child(dev, "smbus", -1);
  216         if (!amdpm_sc->smbus)
  217                 return (EINVAL);
  218 
  219         bus_generic_attach(dev);
  220 
  221         return (0);
  222 }
  223 
  224 static int
  225 amdpm_detach(device_t dev)
  226 {
  227         struct amdpm_softc *amdpm_sc = device_get_softc(dev);
  228 
  229         if (amdpm_sc->smbus) {
  230                 device_delete_child(dev, amdpm_sc->smbus);
  231                 amdpm_sc->smbus = NULL;
  232         }
  233 
  234         if (amdpm_sc->res)
  235                 bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid,
  236                                      amdpm_sc->res);
  237 
  238         return (0);
  239 }
  240 
  241 static int
  242 amdpm_callback(device_t dev, int index, caddr_t *data)
  243 {
  244         int error = 0;
  245 
  246         switch (index) {
  247         case SMB_REQUEST_BUS:
  248         case SMB_RELEASE_BUS:
  249                 break;
  250         default:
  251                 error = EINVAL;
  252         }
  253 
  254         return (error);
  255 }
  256 
  257 static int
  258 amdpm_clear(struct amdpm_softc *sc)
  259 {
  260         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
  261         DELAY(10);
  262 
  263         return (0);
  264 }
  265 
  266 #if 0
  267 static int
  268 amdpm_abort(struct amdpm_softc *sc)
  269 {
  270         u_short l;
  271         
  272         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  273         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
  274 
  275         return (0);
  276 }
  277 #endif
  278 
  279 static int
  280 amdpm_idle(struct amdpm_softc *sc)
  281 {
  282         u_short sts;
  283 
  284         sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
  285 
  286         AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts));
  287 
  288         return (~(sts & AMDSMB_GS_HST_STS));
  289 }
  290 
  291 /*
  292  * Poll the SMBus controller
  293  */
  294 static int
  295 amdpm_wait(struct amdpm_softc *sc)
  296 {
  297         int count = 10000;
  298         u_short sts = 0;
  299         int error;
  300 
  301         /* Wait for command to complete (SMBus controller is idle) */
  302         while(count--) {
  303                 DELAY(10);
  304                 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
  305                 if (!(sts & AMDSMB_GS_HST_STS))
  306                         break;
  307         }
  308 
  309         AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count));
  310 
  311         error = SMB_ENOERR;
  312 
  313         if (!count)
  314                 error |= SMB_ETIMEOUT;
  315 
  316         if (sts & AMDSMB_GS_ABRT_STS)
  317                 error |= SMB_EABORT;
  318 
  319         if (sts & AMDSMB_GS_COL_STS)
  320                 error |= SMB_ENOACK;
  321 
  322         if (sts & AMDSMB_GS_PRERR_STS)
  323                 error |= SMB_EBUSERR;
  324 
  325         if (error != SMB_ENOERR)
  326                 amdpm_clear(sc);
  327 
  328         return (error);
  329 }
  330 
  331 static int
  332 amdpm_quick(device_t dev, u_char slave, int how)
  333 {
  334         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  335         int error;
  336         u_short l;
  337 
  338         amdpm_clear(sc);
  339         if (!amdpm_idle(sc))
  340                 return (EBUSY);
  341 
  342         switch (how) {
  343         case SMB_QWRITE:
  344                 AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave));
  345                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  346                 break;
  347         case SMB_QREAD:
  348                 AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave));
  349                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  350                 break;
  351         default:
  352                 panic("%s: unknown QUICK command (%x)!", __func__, how);
  353         }
  354         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  355         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
  356 
  357         error = amdpm_wait(sc);
  358 
  359         AMDPM_DEBUG(printf(", error=0x%x\n", error));
  360 
  361         return (error);
  362 }
  363 
  364 static int
  365 amdpm_sendb(device_t dev, u_char slave, char byte)
  366 {
  367         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  368         int error;
  369         u_short l;
  370 
  371         amdpm_clear(sc);
  372         if (!amdpm_idle(sc))
  373                 return (SMB_EBUSY);
  374 
  375         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  376         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
  377         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  378         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
  379 
  380         error = amdpm_wait(sc);
  381 
  382         AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
  383 
  384         return (error);
  385 }
  386 
  387 static int
  388 amdpm_recvb(device_t dev, u_char slave, char *byte)
  389 {
  390         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  391         int error;
  392         u_short l;
  393 
  394         amdpm_clear(sc);
  395         if (!amdpm_idle(sc))
  396                 return (SMB_EBUSY);
  397 
  398         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  399         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  400         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
  401 
  402         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  403                 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  404 
  405         AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
  406 
  407         return (error);
  408 }
  409 
  410 static int
  411 amdpm_writeb(device_t dev, u_char slave, char cmd, char byte)
  412 {
  413         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  414         int error;
  415         u_short l;
  416 
  417         amdpm_clear(sc);
  418         if (!amdpm_idle(sc))
  419                 return (SMB_EBUSY);
  420 
  421         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  422         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
  423         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  424         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  425         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
  426 
  427         error = amdpm_wait(sc);
  428 
  429         AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
  430 
  431         return (error);
  432 }
  433 
  434 static int
  435 amdpm_readb(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_clear(sc);
  442         if (!amdpm_idle(sc))
  443                 return (SMB_EBUSY);
  444 
  445         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  446         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  447         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  448         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
  449 
  450         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  451                 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  452 
  453         AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
  454 
  455         return (error);
  456 }
  457 
  458 static int
  459 amdpm_writew(device_t dev, u_char slave, char cmd, short word)
  460 {
  461         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  462         int error;
  463         u_short l;
  464 
  465         amdpm_clear(sc);
  466         if (!amdpm_idle(sc))
  467                 return (SMB_EBUSY);
  468 
  469         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  470         AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
  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_WDATA | AMDSMB_GE_HOST_STC);
  474 
  475         error = amdpm_wait(sc);
  476 
  477         AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
  478 
  479         return (error);
  480 }
  481 
  482 static int
  483 amdpm_readw(device_t dev, u_char slave, char cmd, short *word)
  484 {
  485         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  486         int error;
  487         u_short l;
  488 
  489         amdpm_clear(sc);
  490         if (!amdpm_idle(sc))
  491                 return (SMB_EBUSY);
  492 
  493         AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  494         AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  495         l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  496         AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
  497 
  498         if ((error = amdpm_wait(sc)) == SMB_ENOERR)
  499                 *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  500 
  501         AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
  502 
  503         return (error);
  504 }
  505 
  506 static int
  507 amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  508 {
  509         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  510         u_char remain, len, i;
  511         int error = SMB_ENOERR;
  512         u_short l;
  513 
  514         amdpm_clear(sc);
  515         if(!amdpm_idle(sc))
  516                 return (SMB_EBUSY);
  517 
  518         remain = count;
  519         while (remain) {
  520                 len = min(remain, 32);
  521 
  522                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
  523         
  524                 /*
  525                  * Do we have to reset the internal 32-byte buffer?
  526                  * Can't see how to do this from the data sheet.
  527                  */
  528 
  529                 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len);
  530 
  531                 /* Fill the 32-byte internal buffer */
  532                 for (i=0; i<len; i++) {
  533                         AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]);
  534                         DELAY(2);
  535                 }
  536                 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  537                 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  538                 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
  539 
  540                 if ((error = amdpm_wait(sc)) != SMB_ENOERR)
  541                         goto error;
  542 
  543                 remain -= len;
  544         }
  545 
  546 error:
  547         AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
  548 
  549         return (error);
  550 }
  551 
  552 static int
  553 amdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  554 {
  555         struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
  556         u_char remain, len, i;
  557         int error = SMB_ENOERR;
  558         u_short l;
  559 
  560         amdpm_clear(sc);
  561         if (!amdpm_idle(sc))
  562                 return (SMB_EBUSY);
  563 
  564         remain = count;
  565         while (remain) {
  566                 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
  567         
  568                 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
  569 
  570                 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
  571                 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
  572                 
  573                 if ((error = amdpm_wait(sc)) != SMB_ENOERR)
  574                         goto error;
  575 
  576                 len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
  577 
  578                 /* Read the 32-byte internal buffer */
  579                 for (i=0; i<len; i++) {
  580                         buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
  581                         DELAY(2);
  582                 }
  583 
  584                 remain -= len;
  585         }
  586 error:
  587         AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
  588 
  589         return (error);
  590 }
  591 
  592 static devclass_t amdpm_devclass;
  593 
  594 static device_method_t amdpm_methods[] = {
  595         /* Device interface */
  596         DEVMETHOD(device_probe,         amdpm_probe),
  597         DEVMETHOD(device_attach,        amdpm_attach),
  598         DEVMETHOD(device_detach,        amdpm_detach),
  599         
  600         /* SMBus interface */
  601         DEVMETHOD(smbus_callback,       amdpm_callback),
  602         DEVMETHOD(smbus_quick,          amdpm_quick),
  603         DEVMETHOD(smbus_sendb,          amdpm_sendb),
  604         DEVMETHOD(smbus_recvb,          amdpm_recvb),
  605         DEVMETHOD(smbus_writeb,         amdpm_writeb),
  606         DEVMETHOD(smbus_readb,          amdpm_readb),
  607         DEVMETHOD(smbus_writew,         amdpm_writew),
  608         DEVMETHOD(smbus_readw,          amdpm_readw),
  609         DEVMETHOD(smbus_bwrite,         amdpm_bwrite),
  610         DEVMETHOD(smbus_bread,          amdpm_bread),
  611         
  612         { 0, 0 }
  613 };
  614 
  615 static driver_t amdpm_driver = {
  616         "amdpm",
  617         amdpm_methods,
  618         sizeof(struct amdpm_softc),
  619 };
  620 
  621 DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
  622 
  623 MODULE_DEPEND(amdpm, pci, 1, 1, 1);
  624 MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  625 MODULE_VERSION(amdpm, 1);
  626 

Cache object: 6df2fe58637bdb570a6ac1f549534cda


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