amdpm.c revision 165951
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 165951 2007-01-11 19:56:24Z jhb $"); 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; 126103764Snsouch bus_space_tag_t smbst; 127103764Snsouch bus_space_handle_t smbsh; 12883553Smurray device_t smbus; 129165951Sjhb struct mtx lock; 13083553Smurray}; 13183553Smurray 132165951Sjhb#define AMDPM_LOCK(amdpm) mtx_lock(&(amdpm)->lock) 133165951Sjhb#define AMDPM_UNLOCK(amdpm) mtx_unlock(&(amdpm)->lock) 134165951Sjhb#define AMDPM_LOCK_ASSERT(amdpm) mtx_assert(&(amdpm)->lock, MA_OWNED) 135165951Sjhb 136103764Snsouch#define AMDPM_SMBINB(amdpm,register) \ 137103764Snsouch (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register)) 138103764Snsouch#define AMDPM_SMBOUTB(amdpm,register,value) \ 139103764Snsouch (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value)) 140103764Snsouch#define AMDPM_SMBINW(amdpm,register) \ 141103764Snsouch (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register)) 142103764Snsouch#define AMDPM_SMBOUTW(amdpm,register,value) \ 143103764Snsouch (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value)) 14483553Smurray 145165951Sjhbstatic int amdpm_detach(device_t dev); 146165951Sjhb 14783553Smurraystatic int 14883553Smurrayamdpm_probe(device_t dev) 14983553Smurray{ 15083553Smurray u_long base; 151119796Sdfr u_int16_t vid; 152119655Sdfr u_int16_t did; 153119655Sdfr 154119796Sdfr vid = pci_get_vendor(dev); 155119655Sdfr did = pci_get_device(dev); 156119796Sdfr if ((vid == AMDPM_VENDORID_AMD) && 157119655Sdfr ((did == AMDPM_DEVICEID_AMD756PM) || 158119655Sdfr (did == AMDPM_DEVICEID_AMD766PM) || 159128472Sobrien (did == AMDPM_DEVICEID_AMD768PM) || 160128472Sobrien (did == AMDPM_DEVICEID_AMD8111PM))) { 161128472Sobrien device_set_desc(dev, "AMD 756/766/768/8111 Power Management Controller"); 162119798Sdfr 163153491Sru /* 164119798Sdfr * We have to do this, since the BIOS won't give us the 165119798Sdfr * resource info (not mine, anyway). 166119798Sdfr */ 167119798Sdfr base = pci_read_config(dev, AMDPCI_PMBASE, 4); 168119798Sdfr base &= 0xff00; 169119798Sdfr bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, 170119798Sdfr base+0xe0, 32); 171142398Simp return (BUS_PROBE_DEFAULT); 17283553Smurray } 173119796Sdfr 174153491Sru if ((vid == AMDPM_VENDORID_NVIDIA) && 175153491Sru (did == AMDPM_DEVICEID_NF_SMB)) { 176153491Sru device_set_desc(dev, "nForce SMBus Controller"); 177119796Sdfr 178153491Sru /* 179153491Sru * We have to do this, since the BIOS won't give us the 180153491Sru * resource info (not mine, anyway). 181153491Sru */ 182153491Sru base = pci_read_config(dev, NFPCI_PMBASE, 4); 183153491Sru base &= 0xff00; 184153491Sru bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, 185153491Sru base, 32); 186119796Sdfr 187153491Sru return (BUS_PROBE_DEFAULT); 188119796Sdfr } 189119796Sdfr 19083553Smurray return ENXIO; 19183553Smurray} 19283553Smurray 19383553Smurraystatic int 19483553Smurrayamdpm_attach(device_t dev) 19583553Smurray{ 19683553Smurray struct amdpm_softc *amdpm_sc = device_get_softc(dev); 19783553Smurray u_char val_b; 198153491Sru 19983553Smurray /* Enable I/O block access */ 20083553Smurray val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 20183553Smurray pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 20283553Smurray 20383553Smurray /* Allocate I/O space */ 204119796Sdfr if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD) 205119796Sdfr amdpm_sc->rid = AMDPCI_PMBASE; 206153491Sru else 207153419Sjhb amdpm_sc->rid = NFPCI_PMBASE; 208127135Snjl amdpm_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 209127135Snjl &amdpm_sc->rid, RF_ACTIVE); 210153491Sru 21183553Smurray if (amdpm_sc->res == NULL) { 21283553Smurray device_printf(dev, "could not map i/o space\n"); 21383553Smurray return (ENXIO); 214153491Sru } 21583553Smurray 21683553Smurray amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res); 21783553Smurray amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res); 218165951Sjhb mtx_init(&amdpm_sc->lock, device_get_nameunit(dev), "amdpm", MTX_DEF); 21983553Smurray 220103764Snsouch /* Allocate a new smbus device */ 221103764Snsouch amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 222165951Sjhb if (!amdpm_sc->smbus) { 223165951Sjhb amdpm_detach(dev); 224119798Sdfr return (EINVAL); 225165951Sjhb } 226103764Snsouch 227103764Snsouch bus_generic_attach(dev); 228103764Snsouch 22983553Smurray return (0); 23083553Smurray} 23183553Smurray 23283553Smurraystatic int 233103764Snsouchamdpm_detach(device_t dev) 23483553Smurray{ 235103764Snsouch struct amdpm_softc *amdpm_sc = device_get_softc(dev); 23683553Smurray 237103764Snsouch if (amdpm_sc->smbus) { 238119798Sdfr device_delete_child(dev, amdpm_sc->smbus); 239119798Sdfr amdpm_sc->smbus = NULL; 240103764Snsouch } 24193040Snsouch 242165951Sjhb mtx_destroy(&amdpm_sc->lock); 243103764Snsouch if (amdpm_sc->res) 244119798Sdfr bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, 245119798Sdfr amdpm_sc->res); 24683553Smurray 24783553Smurray return (0); 24883553Smurray} 24983553Smurray 25083553Smurraystatic int 251162234Sjhbamdpm_callback(device_t dev, int index, void *data) 25283553Smurray{ 25383553Smurray int error = 0; 25483553Smurray 25583553Smurray switch (index) { 25683553Smurray case SMB_REQUEST_BUS: 25783553Smurray case SMB_RELEASE_BUS: 25883553Smurray break; 25983553Smurray default: 26083553Smurray error = EINVAL; 26183553Smurray } 26283553Smurray 26383553Smurray return (error); 26483553Smurray} 26583553Smurray 26683553Smurraystatic int 267103764Snsouchamdpm_clear(struct amdpm_softc *sc) 26883553Smurray{ 269165951Sjhb 270165951Sjhb AMDPM_LOCK_ASSERT(sc); 27183553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); 27283553Smurray DELAY(10); 27383553Smurray 27483553Smurray return (0); 27583553Smurray} 27683553Smurray 27791265Speter#if 0 27883553Smurraystatic int 279103764Snsouchamdpm_abort(struct amdpm_softc *sc) 28083553Smurray{ 28183553Smurray u_short l; 282153491Sru 28383553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 28483553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); 28583553Smurray 28683553Smurray return (0); 28783553Smurray} 28891265Speter#endif 28983553Smurray 29083553Smurraystatic int 291103764Snsouchamdpm_idle(struct amdpm_softc *sc) 29283553Smurray{ 29383553Smurray u_short sts; 29483553Smurray 295165951Sjhb AMDPM_LOCK_ASSERT(sc); 29683553Smurray sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 29783553Smurray 29883553Smurray AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts)); 29983553Smurray 30083553Smurray return (~(sts & AMDSMB_GS_HST_STS)); 30183553Smurray} 30283553Smurray 30383553Smurray/* 30483553Smurray * Poll the SMBus controller 30583553Smurray */ 30683553Smurraystatic int 307103764Snsouchamdpm_wait(struct amdpm_softc *sc) 30883553Smurray{ 30983553Smurray int count = 10000; 31083553Smurray u_short sts = 0; 31183553Smurray int error; 31283553Smurray 313165951Sjhb AMDPM_LOCK_ASSERT(sc); 31483553Smurray /* Wait for command to complete (SMBus controller is idle) */ 31583553Smurray while(count--) { 31683553Smurray DELAY(10); 31783553Smurray sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 31883553Smurray if (!(sts & AMDSMB_GS_HST_STS)) 31983553Smurray break; 32083553Smurray } 32183553Smurray 32283553Smurray AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count)); 32383553Smurray 32483553Smurray error = SMB_ENOERR; 32583553Smurray 32683553Smurray if (!count) 32783553Smurray error |= SMB_ETIMEOUT; 32883553Smurray 32983553Smurray if (sts & AMDSMB_GS_ABRT_STS) 33083553Smurray error |= SMB_EABORT; 33183553Smurray 33283553Smurray if (sts & AMDSMB_GS_COL_STS) 33383553Smurray error |= SMB_ENOACK; 33483553Smurray 33583553Smurray if (sts & AMDSMB_GS_PRERR_STS) 33683553Smurray error |= SMB_EBUSERR; 33783553Smurray 33883553Smurray if (error != SMB_ENOERR) 339103764Snsouch amdpm_clear(sc); 34083553Smurray 34183553Smurray return (error); 34283553Smurray} 34383553Smurray 34483553Smurraystatic int 345103764Snsouchamdpm_quick(device_t dev, u_char slave, int how) 34683553Smurray{ 347103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 34883553Smurray int error; 34983553Smurray u_short l; 35083553Smurray 351165951Sjhb AMDPM_LOCK(sc); 352103764Snsouch amdpm_clear(sc); 353165951Sjhb if (!amdpm_idle(sc)) { 354165951Sjhb AMDPM_UNLOCK(sc); 35583553Smurray return (EBUSY); 356165951Sjhb } 35783553Smurray 35883553Smurray switch (how) { 35983553Smurray case SMB_QWRITE: 36083553Smurray AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave)); 36183553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 36283553Smurray break; 36383553Smurray case SMB_QREAD: 36483553Smurray AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave)); 36583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 36683553Smurray break; 36783553Smurray default: 36887599Sobrien panic("%s: unknown QUICK command (%x)!", __func__, how); 36983553Smurray } 37083553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 37183553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC); 37283553Smurray 373103764Snsouch error = amdpm_wait(sc); 37483553Smurray 37583553Smurray AMDPM_DEBUG(printf(", error=0x%x\n", error)); 376165951Sjhb AMDPM_UNLOCK(sc); 37783553Smurray 37883553Smurray return (error); 37983553Smurray} 38083553Smurray 38183553Smurraystatic int 382103764Snsouchamdpm_sendb(device_t dev, u_char slave, char byte) 38383553Smurray{ 384103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 38583553Smurray int error; 38683553Smurray u_short l; 38783553Smurray 388165951Sjhb AMDPM_LOCK(sc); 389103764Snsouch amdpm_clear(sc); 390165951Sjhb if (!amdpm_idle(sc)) { 391165951Sjhb AMDPM_UNLOCK(sc); 39283553Smurray return (SMB_EBUSY); 393165951Sjhb } 39483553Smurray 39583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 39683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 39783553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 39883553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 39983553Smurray 400103764Snsouch error = amdpm_wait(sc); 40183553Smurray 40283553Smurray AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 403165951Sjhb AMDPM_UNLOCK(sc); 40483553Smurray 40583553Smurray return (error); 40683553Smurray} 40783553Smurray 40883553Smurraystatic int 409103764Snsouchamdpm_recvb(device_t dev, u_char slave, char *byte) 41083553Smurray{ 411103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 41283553Smurray int error; 41383553Smurray u_short l; 41483553Smurray 415165951Sjhb AMDPM_LOCK(sc); 416103764Snsouch amdpm_clear(sc); 417165951Sjhb if (!amdpm_idle(sc)) { 418165951Sjhb AMDPM_UNLOCK(sc); 41983553Smurray return (SMB_EBUSY); 420165951Sjhb } 42183553Smurray 42283553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 42383553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 42483553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 42583553Smurray 426103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 42783553Smurray *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 42883553Smurray 42983553Smurray AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 430165951Sjhb AMDPM_UNLOCK(sc); 43183553Smurray 43283553Smurray return (error); 43383553Smurray} 43483553Smurray 43583553Smurraystatic int 436103764Snsouchamdpm_writeb(device_t dev, u_char slave, char cmd, char byte) 43783553Smurray{ 438103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 43983553Smurray int error; 44083553Smurray u_short l; 44183553Smurray 442165951Sjhb AMDPM_LOCK(sc); 443103764Snsouch amdpm_clear(sc); 444165951Sjhb if (!amdpm_idle(sc)) { 445165951Sjhb AMDPM_UNLOCK(sc); 44683553Smurray return (SMB_EBUSY); 447165951Sjhb } 44883553Smurray 44983553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 45083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 45183553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 45283553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 45383553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 45483553Smurray 455103764Snsouch error = amdpm_wait(sc); 45683553Smurray 45783553Smurray AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 458165951Sjhb AMDPM_UNLOCK(sc); 45983553Smurray 46083553Smurray return (error); 46183553Smurray} 46283553Smurray 46383553Smurraystatic int 464103764Snsouchamdpm_readb(device_t dev, u_char slave, char cmd, char *byte) 46583553Smurray{ 466103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 46783553Smurray int error; 46883553Smurray u_short l; 46983553Smurray 470165951Sjhb AMDPM_LOCK(sc); 471103764Snsouch amdpm_clear(sc); 472165951Sjhb if (!amdpm_idle(sc)) { 473165951Sjhb AMDPM_UNLOCK(sc); 47483553Smurray return (SMB_EBUSY); 475165951Sjhb } 47683553Smurray 47783553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 47883553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 47983553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 48083553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 48183553Smurray 482103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 48383553Smurray *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 48483553Smurray 48583553Smurray AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 486165951Sjhb AMDPM_UNLOCK(sc); 48783553Smurray 48883553Smurray return (error); 48983553Smurray} 49083553Smurray 49183553Smurraystatic int 492103764Snsouchamdpm_writew(device_t dev, u_char slave, char cmd, short word) 49383553Smurray{ 494103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 49583553Smurray int error; 49683553Smurray u_short l; 49783553Smurray 498165951Sjhb AMDPM_LOCK(sc); 499103764Snsouch amdpm_clear(sc); 500165951Sjhb if (!amdpm_idle(sc)) { 501165951Sjhb AMDPM_UNLOCK(sc); 50283553Smurray return (SMB_EBUSY); 503165951Sjhb } 50483553Smurray 50583553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 50683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word); 50783553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 50883553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 50983553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 51083553Smurray 511103764Snsouch error = amdpm_wait(sc); 51283553Smurray 51383553Smurray AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 514165951Sjhb AMDPM_UNLOCK(sc); 51583553Smurray 51683553Smurray return (error); 51783553Smurray} 51883553Smurray 51983553Smurraystatic int 520103764Snsouchamdpm_readw(device_t dev, u_char slave, char cmd, short *word) 52183553Smurray{ 522103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 52383553Smurray int error; 52483553Smurray u_short l; 52583553Smurray 526165951Sjhb AMDPM_LOCK(sc); 527103764Snsouch amdpm_clear(sc); 528165951Sjhb if (!amdpm_idle(sc)) { 529165951Sjhb AMDPM_UNLOCK(sc); 53083553Smurray return (SMB_EBUSY); 531165951Sjhb } 53283553Smurray 53383553Smurray AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 53483553Smurray AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 53583553Smurray l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 53683553Smurray AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 53783553Smurray 538103764Snsouch if ((error = amdpm_wait(sc)) == SMB_ENOERR) 53983553Smurray *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 54083553Smurray 54183553Smurray AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 542165951Sjhb AMDPM_UNLOCK(sc); 54383553Smurray 54483553Smurray return (error); 54583553Smurray} 54683553Smurray 54783553Smurraystatic int 548103764Snsouchamdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 54983553Smurray{ 550103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 551162234Sjhb u_char i; 552162234Sjhb int error; 55383553Smurray u_short l; 55483553Smurray 555162234Sjhb if (count < 1 || count > 32) 556162234Sjhb return (SMB_EINVAL); 557165951Sjhb 558165951Sjhb AMDPM_LOCK(sc); 559103764Snsouch amdpm_clear(sc); 560165951Sjhb if (!amdpm_idle(sc)) { 561165951Sjhb AMDPM_UNLOCK(sc); 56283553Smurray return (SMB_EBUSY); 563165951Sjhb } 56483553Smurray 565162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 566153491Sru 567162234Sjhb /* 568162234Sjhb * Do we have to reset the internal 32-byte buffer? 569162234Sjhb * Can't see how to do this from the data sheet. 570162234Sjhb */ 571162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, count); 57283553Smurray 573162234Sjhb /* Fill the 32-byte internal buffer */ 574162234Sjhb for (i = 0; i < count; i++) { 575162234Sjhb AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[i]); 576162234Sjhb DELAY(2); 577162234Sjhb } 578162234Sjhb AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 579162234Sjhb l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 580162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, 581162234Sjhb (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 58283553Smurray 583162234Sjhb error = amdpm_wait(sc); 58483553Smurray 58583553Smurray AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 586165951Sjhb AMDPM_UNLOCK(sc); 58783553Smurray 58883553Smurray return (error); 58983553Smurray} 59083553Smurray 59183553Smurraystatic int 592162234Sjhbamdpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 59383553Smurray{ 594103764Snsouch struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 595162234Sjhb u_char data, len, i; 596162234Sjhb int error; 59783553Smurray u_short l; 59883553Smurray 599162234Sjhb if (*count < 1 || *count > 32) 600162234Sjhb return (SMB_EINVAL); 601165951Sjhb 602165951Sjhb AMDPM_LOCK(sc); 603103764Snsouch amdpm_clear(sc); 604165951Sjhb if (!amdpm_idle(sc)) { 605165951Sjhb AMDPM_UNLOCK(sc); 60683553Smurray return (SMB_EBUSY); 607165951Sjhb } 60883553Smurray 609162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 610153491Sru 611162234Sjhb AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 61283553Smurray 613162234Sjhb l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 614162234Sjhb AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, 615162234Sjhb (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 616153491Sru 617162234Sjhb if ((error = amdpm_wait(sc)) != SMB_ENOERR) 618162234Sjhb goto error; 61983553Smurray 620162234Sjhb len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 62183553Smurray 622162234Sjhb /* Read the 32-byte internal buffer */ 623162234Sjhb for (i = 0; i < len; i++) { 624162234Sjhb data = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO); 625162234Sjhb if (i < *count) 626162234Sjhb buf[i] = data; 627162234Sjhb DELAY(2); 628162234Sjhb } 629162234Sjhb *count = len; 63083553Smurray 63183553Smurrayerror: 632162234Sjhb AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 633165951Sjhb AMDPM_UNLOCK(sc); 63483553Smurray 63583553Smurray return (error); 63683553Smurray} 63783553Smurray 638153491Srustatic devclass_t amdpm_devclass; 63983553Smurray 64083553Smurraystatic device_method_t amdpm_methods[] = { 64183553Smurray /* Device interface */ 64283553Smurray DEVMETHOD(device_probe, amdpm_probe), 64383553Smurray DEVMETHOD(device_attach, amdpm_attach), 644103764Snsouch DEVMETHOD(device_detach, amdpm_detach), 645153491Sru 646103764Snsouch /* SMBus interface */ 647103764Snsouch DEVMETHOD(smbus_callback, amdpm_callback), 648103764Snsouch DEVMETHOD(smbus_quick, amdpm_quick), 649103764Snsouch DEVMETHOD(smbus_sendb, amdpm_sendb), 650103764Snsouch DEVMETHOD(smbus_recvb, amdpm_recvb), 651103764Snsouch DEVMETHOD(smbus_writeb, amdpm_writeb), 652103764Snsouch DEVMETHOD(smbus_readb, amdpm_readb), 653103764Snsouch DEVMETHOD(smbus_writew, amdpm_writew), 654103764Snsouch DEVMETHOD(smbus_readw, amdpm_readw), 655103764Snsouch DEVMETHOD(smbus_bwrite, amdpm_bwrite), 656103764Snsouch DEVMETHOD(smbus_bread, amdpm_bread), 657153491Sru 65883553Smurray { 0, 0 } 65983553Smurray}; 66083553Smurray 66183553Smurraystatic driver_t amdpm_driver = { 66283553Smurray "amdpm", 66383553Smurray amdpm_methods, 66483553Smurray sizeof(struct amdpm_softc), 66583553Smurray}; 66683553Smurray 66783553SmurrayDRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0); 668162234SjhbDRIVER_MODULE(smbus, amdpm, smbus_driver, smbus_devclass, 0, 0); 669103764Snsouch 670113506SmdoddMODULE_DEPEND(amdpm, pci, 1, 1, 1); 67193040SnsouchMODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 67293040SnsouchMODULE_VERSION(amdpm, 1); 673