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

Cache object: 010c822e6b4130f5f6627a817b2657b5


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