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

Cache object: 5ca19c3667836af48481235b3da64f28


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