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

Cache object: 45a02c18bd0d4189f5892a34e8cb5f48


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