amdpm.c revision 119798
183553Smurray/*- 283553Smurray * Copyright (c) 2000 Matthew C. Forman 383553Smurray * 483553Smurray * Based (heavily) on alpm.c which is: 583553Smurray * 683553Smurray * Copyright (c) 1998, 1999 Nicolas Souchu 783553Smurray * All rights reserved. 883553Smurray * 983553Smurray * Redistribution and use in source and binary forms, with or without 1083553Smurray * modification, are permitted provided that the following conditions 1183553Smurray * are met: 1283553Smurray * 1. Redistributions of source code must retain the above copyright 1383553Smurray * notice, this list of conditions and the following disclaimer. 1483553Smurray * 2. Redistributions in binary form must reproduce the above copyright 1583553Smurray * notice, this list of conditions and the following disclaimer in the 1683553Smurray * documentation and/or other materials provided with the distribution. 1783553Smurray * 1883553Smurray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1983553Smurray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2083553Smurray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2183553Smurray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2283553Smurray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2383553Smurray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2483553Smurray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2583553Smurray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2683553Smurray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2783553Smurray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2883553Smurray * SUCH DAMAGE. 2983553Smurray */ 3083553Smurray 3183553Smurray/* 3283553Smurray * Power management function/SMBus function support for the AMD 756 chip. 3383553Smurray */ 3483553Smurray 35116192Sobrien#include <sys/cdefs.h> 36116192Sobrien__FBSDID("$FreeBSD: head/sys/pci/amdpm.c 119798 2003-09-06 14:04:30Z dfr $"); 37116192Sobrien 3883553Smurray#include <sys/param.h> 3983553Smurray#include <sys/kernel.h> 4083553Smurray#include <sys/systm.h> 4183553Smurray#include <sys/module.h> 4283553Smurray#include <sys/bus.h> 4383553Smurray#include <sys/uio.h> 4483553Smurray 4583553Smurray#include <machine/bus_pio.h> 4683553Smurray#include <machine/bus_memio.h> 4783553Smurray#include <machine/bus.h> 4883553Smurray#include <machine/clock.h> 4983553Smurray#include <machine/resource.h> 5083553Smurray#include <sys/rman.h> 5183553Smurray 52119288Simp#include <dev/pci/pcivar.h> 53119288Simp#include <dev/pci/pcireg.h> 5483553Smurray 5583553Smurray#include <dev/iicbus/iiconf.h> 5683553Smurray#include <dev/smbus/smbconf.h> 5783553Smurray#include "smbus_if.h" 5883553Smurray 5983553Smurray#define AMDPM_DEBUG(x) if (amdpm_debug) (x) 6083553Smurray 6183553Smurray#ifdef DEBUG 6283553Smurraystatic int amdpm_debug = 1; 6383553Smurray#else 6483553Smurraystatic int amdpm_debug = 0; 6583553Smurray#endif 6683553Smurray 6783553Smurray#define AMDPM_VENDORID_AMD 0x1022 6883553Smurray#define AMDPM_DEVICEID_AMD756PM 0x740b 69119655Sdfr#define AMDPM_DEVICEID_AMD766PM 0x7413 70119655Sdfr#define AMDPM_DEVICEID_AMD768PM 0x7443 7183553Smurray 72103764Snsouch/* nVidia nForce chipset */ 73103764Snsouch#define AMDPM_VENDORID_NVIDIA 0x10de 74103764Snsouch#define AMDPM_DEVICEID_NF_SMB 0x01b4 75103764Snsouch 7683553Smurray/* PCI Configuration space registers */ 7783553Smurray#define AMDPCI_PMBASE 0x58 78103764Snsouch#define NFPCI_PMBASE 0x14 7983553Smurray 8083553Smurray#define AMDPCI_GEN_CONFIG_PM 0x41 8183553Smurray#define AMDPCI_PMIOEN (1<<7) 8283553Smurray 8383553Smurray#define AMDPCI_SCIINT_CONFIG_PM 0x42 8483553Smurray#define AMDPCI_SCISEL_IRQ11 11 8583553Smurray 8683553Smurray#define AMDPCI_REVID 0x08 8783553Smurray 8883553Smurray/* 8983553Smurray * I/O registers. 9083553Smurray * Base address programmed via AMDPCI_PMBASE. 9183553Smurray */ 92103764Snsouch 93119796Sdfr#define AMDSMB_GLOBAL_STATUS (0x00) 9483553Smurray#define AMDSMB_GS_TO_STS (1<<5) 9583553Smurray#define AMDSMB_GS_HCYC_STS (1<<4) 9683553Smurray#define AMDSMB_GS_HST_STS (1<<3) 9783553Smurray#define AMDSMB_GS_PRERR_STS (1<<2) 9883553Smurray#define AMDSMB_GS_COL_STS (1<<1) 9983553Smurray#define AMDSMB_GS_ABRT_STS (1<<0) 10083553Smurray#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) 10183553Smurray 102119796Sdfr#define AMDSMB_GLOBAL_ENABLE (0x02) 10383553Smurray#define AMDSMB_GE_ABORT (1<<5) 10483553Smurray#define AMDSMB_GE_HCYC_EN (1<<4) 10583553Smurray#define AMDSMB_GE_HOST_STC (1<<3) 10683553Smurray#define AMDSMB_GE_CYC_QUICK 0 10783553Smurray#define AMDSMB_GE_CYC_BYTE 1 10883553Smurray#define AMDSMB_GE_CYC_BDATA 2 10983553Smurray#define AMDSMB_GE_CYC_WDATA 3 11083553Smurray#define AMDSMB_GE_CYC_PROCCALL 4 11183553Smurray#define AMDSMB_GE_CYC_BLOCK 5 11283553Smurray 113119796Sdfr#define AMDSMB_HSTADDR (0x04) 114119796Sdfr#define AMDSMB_HSTDATA (0x06) 115119796Sdfr#define AMDSMB_HSTCMD (0x08) 116119796Sdfr#define AMDSMB_HSTDFIFO (0x09) 117119796Sdfr#define AMDSMB_HSLVDATA (0x0A) 118119796Sdfr#define AMDSMB_HSLVDA (0x0C) 119119796Sdfr#define AMDSMB_HSLVDDR (0x0E) 120119796Sdfr#define AMDSMB_SNPADDR (0x0F) 12183553Smurray 12283553Smurraystruct amdpm_softc { 12383553Smurray int base; 12483553Smurray int rid; 12583553Smurray struct resource *res; 126103764Snsouch bus_space_tag_t smbst; 127103764Snsouch bus_space_handle_t smbsh; 12883553Smurray 12983553Smurray device_t smbus; 13083553Smurray}; 13183553Smurray 132103764Snsouch#define AMDPM_SMBINB(amdpm,register) \ 133103764Snsouch (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register)) 134103764Snsouch#define AMDPM_SMBOUTB(amdpm,register,value) \ 135103764Snsouch (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value)) 136103764Snsouch#define AMDPM_SMBINW(amdpm,register) \ 137103764Snsouch (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register)) 138103764Snsouch#define AMDPM_SMBOUTW(amdpm,register,value) \ 139103764Snsouch (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value)) 14083553Smurray 14183553Smurraystatic int 14283553Smurrayamdpm_probe(device_t dev) 14383553Smurray{ 14483553Smurray u_long base; 145119796Sdfr u_int16_t vid; 146119655Sdfr u_int16_t did; 147119655Sdfr 148119796Sdfr vid = pci_get_vendor(dev); 149119655Sdfr did = pci_get_device(dev); 150119796Sdfr if ((vid == AMDPM_VENDORID_AMD) && 151119655Sdfr ((did == AMDPM_DEVICEID_AMD756PM) || 152119655Sdfr (did == AMDPM_DEVICEID_AMD766PM) || 153119655Sdfr (did == AMDPM_DEVICEID_AMD768PM))) { 154119798Sdfr device_set_desc(dev, "AMD 756/766/768 Power Management Controller"); 155119798Sdfr 156119798Sdfr /* 157119798Sdfr * We have to do this, since the BIOS won't give us the 158119798Sdfr * resource info (not mine, anyway). 159119798Sdfr */ 160119798Sdfr base = pci_read_config(dev, AMDPCI_PMBASE, 4); 161119798Sdfr base &= 0xff00; 162119798Sdfr bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, 163119798Sdfr base+0xe0, 32); 164119798Sdfr return (0); 16583553Smurray } 166119796Sdfr 167119796Sdfr if ((vid == AMDPM_VENDORID_NVIDIA) && 168119796Sdfr (did == AMDPM_DEVICEID_NF_SMB)) { 169119796Sdfr device_set_desc(dev, "nForce SMBus Controller"); 170119796Sdfr 171119796Sdfr /* 172119796Sdfr * We have to do this, since the BIOS won't give us the 173119796Sdfr * resource info (not mine, anyway). 174119796Sdfr */ 175119796Sdfr base = pci_read_config(dev, NFPCI_PMBASE, 4); 176119796Sdfr base &= 0xff00; 177119796Sdfr bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, 178119796Sdfr base, 32); 179119796Sdfr 180119796Sdfr return (0); 181119796Sdfr } 182119796Sdfr 18383553Smurray return ENXIO; 18483553Smurray} 18583553Smurray 18683553Smurraystatic int 18783553Smurrayamdpm_attach(device_t dev) 18883553Smurray{ 18983553Smurray struct amdpm_softc *amdpm_sc = device_get_softc(dev); 19083553Smurray u_char val_b; 19183553Smurray 19283553Smurray /* Enable I/O block access */ 19383553Smurray val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 19483553Smurray pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 19583553Smurray 19683553Smurray /* Allocate I/O space */ 197119796Sdfr if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD) 198119796Sdfr amdpm_sc->rid = AMDPCI_PMBASE; 199119796Sdfr else 200119796Sdfr amdpm_sc->rid = NFPCI_PMBASE; 20183553Smurray amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE); 20283553Smurray 20383553Smurray if (amdpm_sc->res == NULL) { 20483553Smurray device_printf(dev, "could not map i/o space\n"); 20583553Smurray return (ENXIO); 20683553Smurray } 20783553Smurray 20883553Smurray amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res); 20983553Smurray amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res); 21083553Smurray 211103764Snsouch /* Allocate a new smbus device */ 212103764Snsouch amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 213103764Snsouch if (!amdpm_sc->smbus) 214119798Sdfr return (EINVAL); 215103764Snsouch 216103764Snsouch bus_generic_attach(dev); 217103764Snsouch 21883553Smurray return (0); 21983553Smurray} 22083553Smurray 22183553Smurraystatic int 222103764Snsouchamdpm_detach(device_t dev) 22383553Smurray{ 224103764Snsouch struct amdpm_softc *amdpm_sc = device_get_softc(dev); 22583553Smurray 226103764Snsouch if (amdpm_sc->smbus) { 227119798Sdfr device_delete_child(dev, amdpm_sc->smbus); 228119798Sdfr amdpm_sc->smbus = NULL; 229103764Snsouch } 23093040Snsouch 231103764Snsouch if (amdpm_sc->res) 232119798Sdfr bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, 233119798Sdfr amdpm_sc->res); 23483553Smurray 23583553Smurray return (0); 23683553Smurray} 23783553Smurray 23883553Smurraystatic int 239103764Snsouchamdpm_callback(device_t dev, int index, caddr_t *data) 24083553Smurray{ 24183553Smurray int error = 0; 24283553Smurray 24383553Smurray switch (index) { 24483553Smurray case SMB_REQUEST_BUS: 24583553Smurray case SMB_RELEASE_BUS: 24683553Smurray break; 24783553Smurray default: 24883553Smurray error = EINVAL; 24983553Smurray } 25083553Smurray 25183553Smurray return (error); 25283553Smurray} 25383553Smurray 25483553Smurraystatic int 255103764Snsouchamdpm_clear(struct amdpm_softc *sc) 25683553Smurray{ 25783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); 25883553Smurray DELAY(10); 25983553Smurray 26083553Smurray return (0); 26183553Smurray} 26283553Smurray 26391265Speter#if 0 26483553Smurraystatic int 265103764Snsouchamdpm_abort(struct amdpm_softc *sc) 26683553Smurray{ 26783553Smurray u_short l; 26883553Smurray 26983553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 27083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); 27183553Smurray 27283553Smurray return (0); 27383553Smurray} 27491265Speter#endif 27583553Smurray 27683553Smurraystatic int 277103764Snsouchamdpm_idle(struct amdpm_softc *sc) 27883553Smurray{ 27983553Smurray u_short sts; 28083553Smurray 28183553Smurray sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 28283553Smurray 28383553Smurray AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts)); 28483553Smurray 28583553Smurray return (~(sts & AMDSMB_GS_HST_STS)); 28683553Smurray} 28783553Smurray 28883553Smurray/* 28983553Smurray * Poll the SMBus controller 29083553Smurray */ 29183553Smurraystatic int 292103764Snsouchamdpm_wait(struct amdpm_softc *sc) 29383553Smurray{ 29483553Smurray int count = 10000; 29583553Smurray u_short sts = 0; 29683553Smurray int error; 29783553Smurray 29883553Smurray /* Wait for command to complete (SMBus controller is idle) */ 29983553Smurray while(count--) { 30083553Smurray DELAY(10); 30183553Smurray sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 30283553Smurray if (!(sts & AMDSMB_GS_HST_STS)) 30383553Smurray break; 30483553Smurray } 30583553Smurray 30683553Smurray AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count)); 30783553Smurray 30883553Smurray error = SMB_ENOERR; 30983553Smurray 31083553Smurray if (!count) 31183553Smurray error |= SMB_ETIMEOUT; 31283553Smurray 31383553Smurray if (sts & AMDSMB_GS_ABRT_STS) 31483553Smurray error |= SMB_EABORT; 31583553Smurray 31683553Smurray if (sts & AMDSMB_GS_COL_STS) 31783553Smurray error |= SMB_ENOACK; 31883553Smurray 31983553Smurray if (sts & AMDSMB_GS_PRERR_STS) 32083553Smurray error |= SMB_EBUSERR; 32183553Smurray 32283553Smurray if (error != SMB_ENOERR) 323103764Snsouch amdpm_clear(sc); 32483553Smurray 32583553Smurray return (error); 32683553Smurray} 32783553Smurray 32883553Smurraystatic int 329103764Snsouchamdpm_quick(device_t dev, u_char slave, int how) 33083553Smurray{ 331103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 33283553Smurray int error; 33383553Smurray u_short l; 33483553Smurray 335103764Snsouch amdpm_clear(sc); 336103764Snsouch if (!amdpm_idle(sc)) 33783553Smurray return (EBUSY); 33883553Smurray 33983553Smurray switch (how) { 34083553Smurray case SMB_QWRITE: 34183553Smurray AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave)); 34283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 34383553Smurray break; 34483553Smurray case SMB_QREAD: 34583553Smurray AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave)); 34683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 34783553Smurray break; 34883553Smurray default: 34987599Sobrien panic("%s: unknown QUICK command (%x)!", __func__, how); 35083553Smurray } 35183553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 35283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC); 35383553Smurray 354103764Snsouch error = amdpm_wait(sc); 35583553Smurray 35683553Smurray AMDPM_DEBUG(printf(", error=0x%x\n", error)); 35783553Smurray 35883553Smurray return (error); 35983553Smurray} 36083553Smurray 36183553Smurraystatic int 362103764Snsouchamdpm_sendb(device_t dev, u_char slave, char byte) 36383553Smurray{ 364103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 36583553Smurray int error; 36683553Smurray u_short l; 36783553Smurray 368103764Snsouch amdpm_clear(sc); 369103764Snsouch if (!amdpm_idle(sc)) 37083553Smurray return (SMB_EBUSY); 37183553Smurray 37283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 37383553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 37483553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 37583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 37683553Smurray 377103764Snsouch error = amdpm_wait(sc); 37883553Smurray 37983553Smurray AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 38083553Smurray 38183553Smurray return (error); 38283553Smurray} 38383553Smurray 38483553Smurraystatic int 385103764Snsouchamdpm_recvb(device_t dev, u_char slave, char *byte) 38683553Smurray{ 387103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 38883553Smurray int error; 38983553Smurray u_short l; 39083553Smurray 391103764Snsouch amdpm_clear(sc); 392103764Snsouch if (!amdpm_idle(sc)) 39383553Smurray return (SMB_EBUSY); 39483553Smurray 39583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 39683553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 39783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 39883553Smurray 399103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 40083553Smurray *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 40183553Smurray 40283553Smurray AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 40383553Smurray 40483553Smurray return (error); 40583553Smurray} 40683553Smurray 40783553Smurraystatic int 408103764Snsouchamdpm_writeb(device_t dev, u_char slave, char cmd, char byte) 40983553Smurray{ 410103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 41183553Smurray int error; 41283553Smurray u_short l; 41383553Smurray 414103764Snsouch amdpm_clear(sc); 415103764Snsouch if (!amdpm_idle(sc)) 41683553Smurray return (SMB_EBUSY); 41783553Smurray 41883553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 41983553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 42083553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 42183553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 42283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 42383553Smurray 424103764Snsouch error = amdpm_wait(sc); 42583553Smurray 42683553Smurray AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 42783553Smurray 42883553Smurray return (error); 42983553Smurray} 43083553Smurray 43183553Smurraystatic int 432103764Snsouchamdpm_readb(device_t dev, u_char slave, char cmd, char *byte) 43383553Smurray{ 434103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 43583553Smurray int error; 43683553Smurray u_short l; 43783553Smurray 438103764Snsouch amdpm_clear(sc); 439103764Snsouch if (!amdpm_idle(sc)) 44083553Smurray return (SMB_EBUSY); 44183553Smurray 44283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 44383553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 44483553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 44583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 44683553Smurray 447103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 44883553Smurray *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 44983553Smurray 45083553Smurray AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 45183553Smurray 45283553Smurray return (error); 45383553Smurray} 45483553Smurray 45583553Smurraystatic int 456103764Snsouchamdpm_writew(device_t dev, u_char slave, char cmd, short word) 45783553Smurray{ 458103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 45983553Smurray int error; 46083553Smurray u_short l; 46183553Smurray 462103764Snsouch amdpm_clear(sc); 463103764Snsouch if (!amdpm_idle(sc)) 46483553Smurray return (SMB_EBUSY); 46583553Smurray 46683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 46783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word); 46883553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 46983553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 47083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 47183553Smurray 472103764Snsouch error = amdpm_wait(sc); 47383553Smurray 47483553Smurray AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 47583553Smurray 47683553Smurray return (error); 47783553Smurray} 47883553Smurray 47983553Smurraystatic int 480103764Snsouchamdpm_readw(device_t dev, u_char slave, char cmd, short *word) 48183553Smurray{ 482103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 48383553Smurray int error; 48483553Smurray u_short l; 48583553Smurray 486103764Snsouch amdpm_clear(sc); 487103764Snsouch if (!amdpm_idle(sc)) 48883553Smurray return (SMB_EBUSY); 48983553Smurray 49083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 49183553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 49283553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 49383553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 49483553Smurray 495103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 49683553Smurray *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 49783553Smurray 49883553Smurray AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 49983553Smurray 50083553Smurray return (error); 50183553Smurray} 50283553Smurray 50383553Smurraystatic int 504103764Snsouchamdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 50583553Smurray{ 506103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 50783553Smurray u_char remain, len, i; 50883553Smurray int error = SMB_ENOERR; 50983553Smurray u_short l; 51083553Smurray 511103764Snsouch amdpm_clear(sc); 512103764Snsouch if(!amdpm_idle(sc)) 51383553Smurray return (SMB_EBUSY); 51483553Smurray 51583553Smurray remain = count; 51683553Smurray while (remain) { 51783553Smurray len = min(remain, 32); 51883553Smurray 51983553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 52083553Smurray 52183553Smurray /* 52283553Smurray * Do we have to reset the internal 32-byte buffer? 52383553Smurray * Can't see how to do this from the data sheet. 52483553Smurray */ 52583553Smurray 52683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len); 52783553Smurray 52883553Smurray /* Fill the 32-byte internal buffer */ 52983553Smurray for (i=0; i<len; i++) { 53083553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]); 53183553Smurray DELAY(2); 53283553Smurray } 53383553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 53483553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 53583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 53683553Smurray 537103764Snsouch if ((error = amdpm_wait(sc)) != SMB_ENOERR) 53883553Smurray goto error; 53983553Smurray 54083553Smurray remain -= len; 54183553Smurray } 54283553Smurray 54383553Smurrayerror: 54483553Smurray AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 54583553Smurray 54683553Smurray return (error); 54783553Smurray} 54883553Smurray 54983553Smurraystatic int 550103764Snsouchamdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 55183553Smurray{ 552103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 55383553Smurray u_char remain, len, i; 55483553Smurray int error = SMB_ENOERR; 55583553Smurray u_short l; 55683553Smurray 557103764Snsouch amdpm_clear(sc); 558103764Snsouch if (!amdpm_idle(sc)) 55983553Smurray return (SMB_EBUSY); 56083553Smurray 56183553Smurray remain = count; 56283553Smurray while (remain) { 56383553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 56483553Smurray 56583553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 56683553Smurray 56783553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 56883553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 56983553Smurray 570103764Snsouch if ((error = amdpm_wait(sc)) != SMB_ENOERR) 57183553Smurray goto error; 57283553Smurray 57383553Smurray len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 57483553Smurray 57583553Smurray /* Read the 32-byte internal buffer */ 57683553Smurray for (i=0; i<len; i++) { 57783553Smurray buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO); 57883553Smurray DELAY(2); 57983553Smurray } 58083553Smurray 58183553Smurray remain -= len; 58283553Smurray } 58383553Smurrayerror: 58483553Smurray AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 58583553Smurray 58683553Smurray return (error); 58783553Smurray} 58883553Smurray 58983553Smurraystatic devclass_t amdpm_devclass; 59083553Smurray 59183553Smurraystatic device_method_t amdpm_methods[] = { 59283553Smurray /* Device interface */ 59383553Smurray DEVMETHOD(device_probe, amdpm_probe), 59483553Smurray DEVMETHOD(device_attach, amdpm_attach), 595103764Snsouch DEVMETHOD(device_detach, amdpm_detach), 59683553Smurray 597103764Snsouch /* SMBus interface */ 598103764Snsouch DEVMETHOD(smbus_callback, amdpm_callback), 599103764Snsouch DEVMETHOD(smbus_quick, amdpm_quick), 600103764Snsouch DEVMETHOD(smbus_sendb, amdpm_sendb), 601103764Snsouch DEVMETHOD(smbus_recvb, amdpm_recvb), 602103764Snsouch DEVMETHOD(smbus_writeb, amdpm_writeb), 603103764Snsouch DEVMETHOD(smbus_readb, amdpm_readb), 604103764Snsouch DEVMETHOD(smbus_writew, amdpm_writew), 605103764Snsouch DEVMETHOD(smbus_readw, amdpm_readw), 606103764Snsouch DEVMETHOD(smbus_bwrite, amdpm_bwrite), 607103764Snsouch DEVMETHOD(smbus_bread, amdpm_bread), 608103764Snsouch 60983553Smurray { 0, 0 } 61083553Smurray}; 61183553Smurray 61283553Smurraystatic driver_t amdpm_driver = { 61383553Smurray "amdpm", 61483553Smurray amdpm_methods, 61583553Smurray sizeof(struct amdpm_softc), 61683553Smurray}; 61783553Smurray 61883553SmurrayDRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0); 619103764Snsouch 620113506SmdoddMODULE_DEPEND(amdpm, pci, 1, 1, 1); 62193040SnsouchMODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 62293040SnsouchMODULE_VERSION(amdpm, 1); 623103764Snsouch 624