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$"); 37116192Sobrien 3883553Smurray#include <sys/param.h> 39165951Sjhb#include <sys/bus.h> 4083553Smurray#include <sys/kernel.h> 41165951Sjhb#include <sys/lock.h> 42165951Sjhb#include <sys/module.h> 43165951Sjhb#include <sys/mutex.h> 4483553Smurray#include <sys/systm.h> 4583553Smurray 4683553Smurray#include <machine/bus.h> 4783553Smurray#include <machine/resource.h> 4883553Smurray#include <sys/rman.h> 4983553Smurray 50119288Simp#include <dev/pci/pcivar.h> 51119288Simp#include <dev/pci/pcireg.h> 5283553Smurray 5383553Smurray#include <dev/smbus/smbconf.h> 5483553Smurray#include "smbus_if.h" 5583553Smurray 5683553Smurray#define AMDPM_DEBUG(x) if (amdpm_debug) (x) 5783553Smurray 5883553Smurray#ifdef DEBUG 5983553Smurraystatic int amdpm_debug = 1; 6083553Smurray#else 6183553Smurraystatic int amdpm_debug = 0; 6283553Smurray#endif 6383553Smurray 6483553Smurray#define AMDPM_VENDORID_AMD 0x1022 6583553Smurray#define AMDPM_DEVICEID_AMD756PM 0x740b 66119655Sdfr#define AMDPM_DEVICEID_AMD766PM 0x7413 67119655Sdfr#define AMDPM_DEVICEID_AMD768PM 0x7443 68153479Sru#define AMDPM_DEVICEID_AMD8111PM 0x746B 6983553Smurray 70103764Snsouch/* nVidia nForce chipset */ 71103764Snsouch#define AMDPM_VENDORID_NVIDIA 0x10de 72103764Snsouch#define AMDPM_DEVICEID_NF_SMB 0x01b4 73103764Snsouch 7483553Smurray/* PCI Configuration space registers */ 7583553Smurray#define AMDPCI_PMBASE 0x58 76103764Snsouch#define NFPCI_PMBASE 0x14 7783553Smurray 7883553Smurray#define AMDPCI_GEN_CONFIG_PM 0x41 7983553Smurray#define AMDPCI_PMIOEN (1<<7) 8083553Smurray 8183553Smurray#define AMDPCI_SCIINT_CONFIG_PM 0x42 8283553Smurray#define AMDPCI_SCISEL_IRQ11 11 8383553Smurray 8483553Smurray#define AMDPCI_REVID 0x08 8583553Smurray 8683553Smurray/* 8783553Smurray * I/O registers. 8883553Smurray * Base address programmed via AMDPCI_PMBASE. 8983553Smurray */ 90103764Snsouch 91119796Sdfr#define AMDSMB_GLOBAL_STATUS (0x00) 9283553Smurray#define AMDSMB_GS_TO_STS (1<<5) 9383553Smurray#define AMDSMB_GS_HCYC_STS (1<<4) 9483553Smurray#define AMDSMB_GS_HST_STS (1<<3) 9583553Smurray#define AMDSMB_GS_PRERR_STS (1<<2) 9683553Smurray#define AMDSMB_GS_COL_STS (1<<1) 9783553Smurray#define AMDSMB_GS_ABRT_STS (1<<0) 9883553Smurray#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) 9983553Smurray 100119796Sdfr#define AMDSMB_GLOBAL_ENABLE (0x02) 10183553Smurray#define AMDSMB_GE_ABORT (1<<5) 10283553Smurray#define AMDSMB_GE_HCYC_EN (1<<4) 10383553Smurray#define AMDSMB_GE_HOST_STC (1<<3) 10483553Smurray#define AMDSMB_GE_CYC_QUICK 0 10583553Smurray#define AMDSMB_GE_CYC_BYTE 1 10683553Smurray#define AMDSMB_GE_CYC_BDATA 2 10783553Smurray#define AMDSMB_GE_CYC_WDATA 3 10883553Smurray#define AMDSMB_GE_CYC_PROCCALL 4 10983553Smurray#define AMDSMB_GE_CYC_BLOCK 5 11083553Smurray 111165951Sjhb#define LSB 0x1 /* XXX: Better name: Read/Write? */ 112165951Sjhb 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; 12683553Smurray device_t smbus; 127165951Sjhb struct mtx lock; 12883553Smurray}; 12983553Smurray 130165951Sjhb#define AMDPM_LOCK(amdpm) mtx_lock(&(amdpm)->lock) 131165951Sjhb#define AMDPM_UNLOCK(amdpm) mtx_unlock(&(amdpm)->lock) 132165951Sjhb#define AMDPM_LOCK_ASSERT(amdpm) mtx_assert(&(amdpm)->lock, MA_OWNED) 133165951Sjhb 134103764Snsouch#define AMDPM_SMBINB(amdpm,register) \ 135179622Sjhb (bus_read_1(amdpm->res, register)) 136103764Snsouch#define AMDPM_SMBOUTB(amdpm,register,value) \ 137179622Sjhb (bus_write_1(amdpm->res, register, value)) 138103764Snsouch#define AMDPM_SMBINW(amdpm,register) \ 139179622Sjhb (bus_read_2(amdpm->res, register)) 140103764Snsouch#define AMDPM_SMBOUTW(amdpm,register,value) \ 141179622Sjhb (bus_write_2(amdpm->res, register, value)) 14283553Smurray 143165951Sjhbstatic int amdpm_detach(device_t dev); 144165951Sjhb 14583553Smurraystatic int 14683553Smurrayamdpm_probe(device_t dev) 14783553Smurray{ 14883553Smurray u_long base; 149119796Sdfr u_int16_t vid; 150119655Sdfr u_int16_t did; 151119655Sdfr 152119796Sdfr vid = pci_get_vendor(dev); 153119655Sdfr did = pci_get_device(dev); 154119796Sdfr if ((vid == AMDPM_VENDORID_AMD) && 155119655Sdfr ((did == AMDPM_DEVICEID_AMD756PM) || 156119655Sdfr (did == AMDPM_DEVICEID_AMD766PM) || 157128472Sobrien (did == AMDPM_DEVICEID_AMD768PM) || 158128472Sobrien (did == AMDPM_DEVICEID_AMD8111PM))) { 159128472Sobrien device_set_desc(dev, "AMD 756/766/768/8111 Power Management Controller"); 160119798Sdfr 161153491Sru /* 162119798Sdfr * We have to do this, since the BIOS won't give us the 163119798Sdfr * resource info (not mine, anyway). 164119798Sdfr */ 165119798Sdfr base = pci_read_config(dev, AMDPCI_PMBASE, 4); 166119798Sdfr base &= 0xff00; 167119798Sdfr bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, 168119798Sdfr base+0xe0, 32); 169142398Simp return (BUS_PROBE_DEFAULT); 17083553Smurray } 171119796Sdfr 172153491Sru if ((vid == AMDPM_VENDORID_NVIDIA) && 173153491Sru (did == AMDPM_DEVICEID_NF_SMB)) { 174153491Sru device_set_desc(dev, "nForce SMBus Controller"); 175119796Sdfr 176153491Sru /* 177153491Sru * We have to do this, since the BIOS won't give us the 178153491Sru * resource info (not mine, anyway). 179153491Sru */ 180153491Sru base = pci_read_config(dev, NFPCI_PMBASE, 4); 181153491Sru base &= 0xff00; 182153491Sru bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, 183153491Sru base, 32); 184119796Sdfr 185153491Sru return (BUS_PROBE_DEFAULT); 186119796Sdfr } 187119796Sdfr 18883553Smurray return ENXIO; 18983553Smurray} 19083553Smurray 19183553Smurraystatic int 19283553Smurrayamdpm_attach(device_t dev) 19383553Smurray{ 19483553Smurray struct amdpm_softc *amdpm_sc = device_get_softc(dev); 19583553Smurray u_char val_b; 196153491Sru 19783553Smurray /* Enable I/O block access */ 19883553Smurray val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 19983553Smurray pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 20083553Smurray 20183553Smurray /* Allocate I/O space */ 202119796Sdfr if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD) 203119796Sdfr amdpm_sc->rid = AMDPCI_PMBASE; 204153491Sru else 205153419Sjhb amdpm_sc->rid = NFPCI_PMBASE; 206127135Snjl amdpm_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 207127135Snjl &amdpm_sc->rid, RF_ACTIVE); 208153491Sru 20983553Smurray if (amdpm_sc->res == NULL) { 21083553Smurray device_printf(dev, "could not map i/o space\n"); 21183553Smurray return (ENXIO); 212153491Sru } 21383553Smurray 214165951Sjhb mtx_init(&amdpm_sc->lock, device_get_nameunit(dev), "amdpm", MTX_DEF); 21583553Smurray 216103764Snsouch /* Allocate a new smbus device */ 217103764Snsouch amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 218165951Sjhb if (!amdpm_sc->smbus) { 219165951Sjhb amdpm_detach(dev); 220119798Sdfr return (EINVAL); 221165951Sjhb } 222103764Snsouch 223103764Snsouch bus_generic_attach(dev); 224103764Snsouch 22583553Smurray return (0); 22683553Smurray} 22783553Smurray 22883553Smurraystatic int 229103764Snsouchamdpm_detach(device_t dev) 23083553Smurray{ 231103764Snsouch struct amdpm_softc *amdpm_sc = device_get_softc(dev); 23283553Smurray 233103764Snsouch if (amdpm_sc->smbus) { 234119798Sdfr device_delete_child(dev, amdpm_sc->smbus); 235119798Sdfr amdpm_sc->smbus = NULL; 236103764Snsouch } 23793040Snsouch 238165951Sjhb mtx_destroy(&amdpm_sc->lock); 239103764Snsouch if (amdpm_sc->res) 240119798Sdfr bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, 241119798Sdfr amdpm_sc->res); 24283553Smurray 24383553Smurray return (0); 24483553Smurray} 24583553Smurray 24683553Smurraystatic int 247162234Sjhbamdpm_callback(device_t dev, int index, void *data) 24883553Smurray{ 24983553Smurray int error = 0; 25083553Smurray 25183553Smurray switch (index) { 25283553Smurray case SMB_REQUEST_BUS: 25383553Smurray case SMB_RELEASE_BUS: 25483553Smurray break; 25583553Smurray default: 25683553Smurray error = EINVAL; 25783553Smurray } 25883553Smurray 25983553Smurray return (error); 26083553Smurray} 26183553Smurray 26283553Smurraystatic int 263103764Snsouchamdpm_clear(struct amdpm_softc *sc) 26483553Smurray{ 265165951Sjhb 266165951Sjhb AMDPM_LOCK_ASSERT(sc); 26783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); 26883553Smurray DELAY(10); 26983553Smurray 27083553Smurray return (0); 27183553Smurray} 27283553Smurray 27391265Speter#if 0 27483553Smurraystatic int 275103764Snsouchamdpm_abort(struct amdpm_softc *sc) 27683553Smurray{ 27783553Smurray u_short l; 278153491Sru 27983553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 28083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); 28183553Smurray 28283553Smurray return (0); 28383553Smurray} 28491265Speter#endif 28583553Smurray 28683553Smurraystatic int 287103764Snsouchamdpm_idle(struct amdpm_softc *sc) 28883553Smurray{ 28983553Smurray u_short sts; 29083553Smurray 291165951Sjhb AMDPM_LOCK_ASSERT(sc); 29283553Smurray sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 29383553Smurray 29483553Smurray AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts)); 29583553Smurray 29683553Smurray return (~(sts & AMDSMB_GS_HST_STS)); 29783553Smurray} 29883553Smurray 29983553Smurray/* 30083553Smurray * Poll the SMBus controller 30183553Smurray */ 30283553Smurraystatic int 303103764Snsouchamdpm_wait(struct amdpm_softc *sc) 30483553Smurray{ 30583553Smurray int count = 10000; 30683553Smurray u_short sts = 0; 30783553Smurray int error; 30883553Smurray 309165951Sjhb AMDPM_LOCK_ASSERT(sc); 31083553Smurray /* Wait for command to complete (SMBus controller is idle) */ 31183553Smurray while(count--) { 31283553Smurray DELAY(10); 31383553Smurray sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 31483553Smurray if (!(sts & AMDSMB_GS_HST_STS)) 31583553Smurray break; 31683553Smurray } 31783553Smurray 31883553Smurray AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count)); 31983553Smurray 32083553Smurray error = SMB_ENOERR; 32183553Smurray 32283553Smurray if (!count) 32383553Smurray error |= SMB_ETIMEOUT; 32483553Smurray 32583553Smurray if (sts & AMDSMB_GS_ABRT_STS) 32683553Smurray error |= SMB_EABORT; 32783553Smurray 32883553Smurray if (sts & AMDSMB_GS_COL_STS) 32983553Smurray error |= SMB_ENOACK; 33083553Smurray 33183553Smurray if (sts & AMDSMB_GS_PRERR_STS) 33283553Smurray error |= SMB_EBUSERR; 33383553Smurray 33483553Smurray if (error != SMB_ENOERR) 335103764Snsouch amdpm_clear(sc); 33683553Smurray 33783553Smurray return (error); 33883553Smurray} 33983553Smurray 34083553Smurraystatic int 341103764Snsouchamdpm_quick(device_t dev, u_char slave, int how) 34283553Smurray{ 343103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 34483553Smurray int error; 34583553Smurray u_short l; 34683553Smurray 347165951Sjhb AMDPM_LOCK(sc); 348103764Snsouch amdpm_clear(sc); 349165951Sjhb if (!amdpm_idle(sc)) { 350165951Sjhb AMDPM_UNLOCK(sc); 35183553Smurray return (EBUSY); 352165951Sjhb } 35383553Smurray 35483553Smurray switch (how) { 35583553Smurray case SMB_QWRITE: 35683553Smurray AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave)); 35783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 35883553Smurray break; 35983553Smurray case SMB_QREAD: 36083553Smurray AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave)); 36183553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 36283553Smurray break; 36383553Smurray default: 36487599Sobrien panic("%s: unknown QUICK command (%x)!", __func__, how); 36583553Smurray } 36683553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 36783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC); 36883553Smurray 369103764Snsouch error = amdpm_wait(sc); 37083553Smurray 37183553Smurray AMDPM_DEBUG(printf(", error=0x%x\n", error)); 372165951Sjhb AMDPM_UNLOCK(sc); 37383553Smurray 37483553Smurray return (error); 37583553Smurray} 37683553Smurray 37783553Smurraystatic int 378103764Snsouchamdpm_sendb(device_t dev, u_char slave, char byte) 37983553Smurray{ 380103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 38183553Smurray int error; 38283553Smurray u_short l; 38383553Smurray 384165951Sjhb AMDPM_LOCK(sc); 385103764Snsouch amdpm_clear(sc); 386165951Sjhb if (!amdpm_idle(sc)) { 387165951Sjhb AMDPM_UNLOCK(sc); 38883553Smurray return (SMB_EBUSY); 389165951Sjhb } 39083553Smurray 39183553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 39283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 39383553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 39483553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 39583553Smurray 396103764Snsouch error = amdpm_wait(sc); 39783553Smurray 39883553Smurray AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 399165951Sjhb AMDPM_UNLOCK(sc); 40083553Smurray 40183553Smurray return (error); 40283553Smurray} 40383553Smurray 40483553Smurraystatic int 405103764Snsouchamdpm_recvb(device_t dev, u_char slave, char *byte) 40683553Smurray{ 407103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 40883553Smurray int error; 40983553Smurray u_short l; 41083553Smurray 411165951Sjhb AMDPM_LOCK(sc); 412103764Snsouch amdpm_clear(sc); 413165951Sjhb if (!amdpm_idle(sc)) { 414165951Sjhb AMDPM_UNLOCK(sc); 41583553Smurray return (SMB_EBUSY); 416165951Sjhb } 41783553Smurray 41883553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 41983553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 42083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 42183553Smurray 422103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 42383553Smurray *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 42483553Smurray 42583553Smurray AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 426165951Sjhb AMDPM_UNLOCK(sc); 42783553Smurray 42883553Smurray return (error); 42983553Smurray} 43083553Smurray 43183553Smurraystatic int 432103764Snsouchamdpm_writeb(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 438165951Sjhb AMDPM_LOCK(sc); 439103764Snsouch amdpm_clear(sc); 440165951Sjhb if (!amdpm_idle(sc)) { 441165951Sjhb AMDPM_UNLOCK(sc); 44283553Smurray return (SMB_EBUSY); 443165951Sjhb } 44483553Smurray 44583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 44683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 44783553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 44883553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 44983553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 45083553Smurray 451103764Snsouch error = amdpm_wait(sc); 45283553Smurray 45383553Smurray AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 454165951Sjhb AMDPM_UNLOCK(sc); 45583553Smurray 45683553Smurray return (error); 45783553Smurray} 45883553Smurray 45983553Smurraystatic int 460103764Snsouchamdpm_readb(device_t dev, u_char slave, char cmd, char *byte) 46183553Smurray{ 462103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 46383553Smurray int error; 46483553Smurray u_short l; 46583553Smurray 466165951Sjhb AMDPM_LOCK(sc); 467103764Snsouch amdpm_clear(sc); 468165951Sjhb if (!amdpm_idle(sc)) { 469165951Sjhb AMDPM_UNLOCK(sc); 47083553Smurray return (SMB_EBUSY); 471165951Sjhb } 47283553Smurray 47383553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 47483553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 47583553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 47683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 47783553Smurray 478103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 47983553Smurray *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 48083553Smurray 48183553Smurray AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 482165951Sjhb AMDPM_UNLOCK(sc); 48383553Smurray 48483553Smurray return (error); 48583553Smurray} 48683553Smurray 48783553Smurraystatic int 488103764Snsouchamdpm_writew(device_t dev, u_char slave, char cmd, short word) 48983553Smurray{ 490103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 49183553Smurray int error; 49283553Smurray u_short l; 49383553Smurray 494165951Sjhb AMDPM_LOCK(sc); 495103764Snsouch amdpm_clear(sc); 496165951Sjhb if (!amdpm_idle(sc)) { 497165951Sjhb AMDPM_UNLOCK(sc); 49883553Smurray return (SMB_EBUSY); 499165951Sjhb } 50083553Smurray 50183553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 50283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word); 50383553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 50483553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 50583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 50683553Smurray 507103764Snsouch error = amdpm_wait(sc); 50883553Smurray 50983553Smurray AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 510165951Sjhb AMDPM_UNLOCK(sc); 51183553Smurray 51283553Smurray return (error); 51383553Smurray} 51483553Smurray 51583553Smurraystatic int 516103764Snsouchamdpm_readw(device_t dev, u_char slave, char cmd, short *word) 51783553Smurray{ 518103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 51983553Smurray int error; 52083553Smurray u_short l; 52183553Smurray 522165951Sjhb AMDPM_LOCK(sc); 523103764Snsouch amdpm_clear(sc); 524165951Sjhb if (!amdpm_idle(sc)) { 525165951Sjhb AMDPM_UNLOCK(sc); 52683553Smurray return (SMB_EBUSY); 527165951Sjhb } 52883553Smurray 52983553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 53083553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 53183553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 53283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 53383553Smurray 534103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 53583553Smurray *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 53683553Smurray 53783553Smurray AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 538165951Sjhb AMDPM_UNLOCK(sc); 53983553Smurray 54083553Smurray return (error); 54183553Smurray} 54283553Smurray 54383553Smurraystatic int 544103764Snsouchamdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 54583553Smurray{ 546103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 547162234Sjhb u_char i; 548162234Sjhb int error; 54983553Smurray u_short l; 55083553Smurray 551162234Sjhb if (count < 1 || count > 32) 552162234Sjhb return (SMB_EINVAL); 553165951Sjhb 554165951Sjhb AMDPM_LOCK(sc); 555103764Snsouch amdpm_clear(sc); 556165951Sjhb if (!amdpm_idle(sc)) { 557165951Sjhb AMDPM_UNLOCK(sc); 55883553Smurray return (SMB_EBUSY); 559165951Sjhb } 56083553Smurray 561162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 562153491Sru 563162234Sjhb /* 564162234Sjhb * Do we have to reset the internal 32-byte buffer? 565162234Sjhb * Can't see how to do this from the data sheet. 566162234Sjhb */ 567162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, count); 56883553Smurray 569162234Sjhb /* Fill the 32-byte internal buffer */ 570162234Sjhb for (i = 0; i < count; i++) { 571162234Sjhb AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[i]); 572162234Sjhb DELAY(2); 573162234Sjhb } 574162234Sjhb AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 575162234Sjhb l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 576162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, 577162234Sjhb (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 57883553Smurray 579162234Sjhb error = amdpm_wait(sc); 58083553Smurray 58183553Smurray AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 582165951Sjhb AMDPM_UNLOCK(sc); 58383553Smurray 58483553Smurray return (error); 58583553Smurray} 58683553Smurray 58783553Smurraystatic int 588162234Sjhbamdpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 58983553Smurray{ 590103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 591162234Sjhb u_char data, len, i; 592162234Sjhb int error; 59383553Smurray u_short l; 59483553Smurray 595162234Sjhb if (*count < 1 || *count > 32) 596162234Sjhb return (SMB_EINVAL); 597165951Sjhb 598165951Sjhb AMDPM_LOCK(sc); 599103764Snsouch amdpm_clear(sc); 600165951Sjhb if (!amdpm_idle(sc)) { 601165951Sjhb AMDPM_UNLOCK(sc); 60283553Smurray return (SMB_EBUSY); 603165951Sjhb } 60483553Smurray 605162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 606153491Sru 607162234Sjhb AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 60883553Smurray 609162234Sjhb l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 610162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, 611162234Sjhb (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 612153491Sru 613162234Sjhb if ((error = amdpm_wait(sc)) != SMB_ENOERR) 614162234Sjhb goto error; 61583553Smurray 616162234Sjhb len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 61783553Smurray 618162234Sjhb /* Read the 32-byte internal buffer */ 619162234Sjhb for (i = 0; i < len; i++) { 620162234Sjhb data = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO); 621162234Sjhb if (i < *count) 622162234Sjhb buf[i] = data; 623162234Sjhb DELAY(2); 624162234Sjhb } 625162234Sjhb *count = len; 62683553Smurray 62783553Smurrayerror: 628162234Sjhb AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 629165951Sjhb AMDPM_UNLOCK(sc); 63083553Smurray 63183553Smurray return (error); 63283553Smurray} 63383553Smurray 634153491Srustatic devclass_t amdpm_devclass; 63583553Smurray 63683553Smurraystatic device_method_t amdpm_methods[] = { 63783553Smurray /* Device interface */ 63883553Smurray DEVMETHOD(device_probe, amdpm_probe), 63983553Smurray DEVMETHOD(device_attach, amdpm_attach), 640103764Snsouch DEVMETHOD(device_detach, amdpm_detach), 641153491Sru 642103764Snsouch /* SMBus interface */ 643103764Snsouch DEVMETHOD(smbus_callback, amdpm_callback), 644103764Snsouch DEVMETHOD(smbus_quick, amdpm_quick), 645103764Snsouch DEVMETHOD(smbus_sendb, amdpm_sendb), 646103764Snsouch DEVMETHOD(smbus_recvb, amdpm_recvb), 647103764Snsouch DEVMETHOD(smbus_writeb, amdpm_writeb), 648103764Snsouch DEVMETHOD(smbus_readb, amdpm_readb), 649103764Snsouch DEVMETHOD(smbus_writew, amdpm_writew), 650103764Snsouch DEVMETHOD(smbus_readw, amdpm_readw), 651103764Snsouch DEVMETHOD(smbus_bwrite, amdpm_bwrite), 652103764Snsouch DEVMETHOD(smbus_bread, amdpm_bread), 653153491Sru 65483553Smurray { 0, 0 } 65583553Smurray}; 65683553Smurray 65783553Smurraystatic driver_t amdpm_driver = { 65883553Smurray "amdpm", 65983553Smurray amdpm_methods, 66083553Smurray sizeof(struct amdpm_softc), 66183553Smurray}; 66283553Smurray 66383553SmurrayDRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0); 664162234SjhbDRIVER_MODULE(smbus, amdpm, smbus_driver, smbus_devclass, 0, 0); 665103764Snsouch 666113506SmdoddMODULE_DEPEND(amdpm, pci, 1, 1, 1); 66793040SnsouchMODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 66893040SnsouchMODULE_VERSION(amdpm, 1); 669