1271b33a6SRui Paulo /*- 2271b33a6SRui Paulo * Copyright (c) 2005 Ruslan Ermilov 3271b33a6SRui Paulo * All rights reserved. 4271b33a6SRui Paulo * 5271b33a6SRui Paulo * Redistribution and use in source and binary forms, with or without 6271b33a6SRui Paulo * modification, are permitted provided that the following conditions 7271b33a6SRui Paulo * are met: 8271b33a6SRui Paulo * 1. Redistributions of source code must retain the above copyright 9271b33a6SRui Paulo * notice, this list of conditions and the following disclaimer. 10271b33a6SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 11271b33a6SRui Paulo * notice, this list of conditions and the following disclaimer in the 12271b33a6SRui Paulo * documentation and/or other materials provided with the distribution. 13271b33a6SRui Paulo * 14271b33a6SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15271b33a6SRui Paulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16271b33a6SRui Paulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17271b33a6SRui Paulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18271b33a6SRui Paulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19271b33a6SRui Paulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20271b33a6SRui Paulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21271b33a6SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22271b33a6SRui Paulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23271b33a6SRui Paulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24271b33a6SRui Paulo * SUCH DAMAGE. 25271b33a6SRui Paulo */ 26271b33a6SRui Paulo 27271b33a6SRui Paulo #include <sys/param.h> 28271b33a6SRui Paulo #include <sys/bus.h> 29271b33a6SRui Paulo #include <sys/kernel.h> 30271b33a6SRui Paulo #include <sys/lock.h> 31271b33a6SRui Paulo #include <sys/module.h> 32271b33a6SRui Paulo #include <sys/mutex.h> 33271b33a6SRui Paulo #include <sys/systm.h> 34271b33a6SRui Paulo 35271b33a6SRui Paulo #include <machine/bus.h> 36271b33a6SRui Paulo #include <machine/resource.h> 37271b33a6SRui Paulo #include <sys/rman.h> 38271b33a6SRui Paulo 39271b33a6SRui Paulo #include <dev/pci/pcivar.h> 40271b33a6SRui Paulo #include <dev/pci/pcireg.h> 41271b33a6SRui Paulo 42271b33a6SRui Paulo #include <dev/smbus/smbconf.h> 43271b33a6SRui Paulo #include "smbus_if.h" 44271b33a6SRui Paulo 45271b33a6SRui Paulo #define AMDSMB_DEBUG(x) if (amdsmb_debug) (x) 46271b33a6SRui Paulo 47271b33a6SRui Paulo #ifdef DEBUG 48271b33a6SRui Paulo static int amdsmb_debug = 1; 49271b33a6SRui Paulo #else 50271b33a6SRui Paulo static int amdsmb_debug = 0; 51271b33a6SRui Paulo #endif 52271b33a6SRui Paulo 53271b33a6SRui Paulo #define AMDSMB_VENDORID_AMD 0x1022 54271b33a6SRui Paulo #define AMDSMB_DEVICEID_AMD8111_SMB2 0x746a 55271b33a6SRui Paulo 56271b33a6SRui Paulo /* 57271b33a6SRui Paulo * ACPI 3.0, Chapter 12, Embedded Controller Interface. 58271b33a6SRui Paulo */ 59271b33a6SRui Paulo #define EC_DATA 0x00 /* data register */ 60271b33a6SRui Paulo #define EC_SC 0x04 /* status of controller */ 61271b33a6SRui Paulo #define EC_CMD 0x04 /* command register */ 62271b33a6SRui Paulo 63271b33a6SRui Paulo #define EC_SC_IBF 0x02 /* data ready for embedded controller */ 64271b33a6SRui Paulo #define EC_SC_OBF 0x01 /* data ready for host */ 65271b33a6SRui Paulo #define EC_CMD_WR 0x81 /* write EC */ 66271b33a6SRui Paulo #define EC_CMD_RD 0x80 /* read EC */ 67271b33a6SRui Paulo 68271b33a6SRui Paulo /* 69271b33a6SRui Paulo * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 70271b33a6SRui Paulo */ 71271b33a6SRui Paulo #define SMB_PRTCL 0x00 /* protocol */ 72271b33a6SRui Paulo #define SMB_STS 0x01 /* status */ 73271b33a6SRui Paulo #define SMB_ADDR 0x02 /* address */ 74271b33a6SRui Paulo #define SMB_CMD 0x03 /* command */ 75271b33a6SRui Paulo #define SMB_DATA 0x04 /* 32 data registers */ 76271b33a6SRui Paulo #define SMB_BCNT 0x24 /* number of data bytes */ 77271b33a6SRui Paulo #define SMB_ALRM_A 0x25 /* alarm address */ 78271b33a6SRui Paulo #define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 79271b33a6SRui Paulo 80271b33a6SRui Paulo #define SMB_STS_DONE 0x80 81271b33a6SRui Paulo #define SMB_STS_ALRM 0x40 82271b33a6SRui Paulo #define SMB_STS_RES 0x20 83271b33a6SRui Paulo #define SMB_STS_STATUS 0x1f 84271b33a6SRui Paulo #define SMB_STS_OK 0x00 /* OK */ 85271b33a6SRui Paulo #define SMB_STS_UF 0x07 /* Unknown Failure */ 86271b33a6SRui Paulo #define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 87271b33a6SRui Paulo #define SMB_STS_DED 0x11 /* Device Error Detected */ 88271b33a6SRui Paulo #define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 89271b33a6SRui Paulo #define SMB_STS_UE 0x13 /* Unknown Error */ 90271b33a6SRui Paulo #define SMB_STS_DAD 0x17 /* Device Access Denied */ 91271b33a6SRui Paulo #define SMB_STS_T 0x18 /* Timeout */ 92271b33a6SRui Paulo #define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 93271b33a6SRui Paulo #define SMB_STS_B 0x1a /* Busy */ 94271b33a6SRui Paulo #define SMB_STS_PEC 0x1f /* PEC (CRC-8) Error */ 95271b33a6SRui Paulo 96271b33a6SRui Paulo #define SMB_PRTCL_WRITE 0x00 97271b33a6SRui Paulo #define SMB_PRTCL_READ 0x01 98271b33a6SRui Paulo #define SMB_PRTCL_QUICK 0x02 99271b33a6SRui Paulo #define SMB_PRTCL_BYTE 0x04 100271b33a6SRui Paulo #define SMB_PRTCL_BYTE_DATA 0x06 101271b33a6SRui Paulo #define SMB_PRTCL_WORD_DATA 0x08 102271b33a6SRui Paulo #define SMB_PRTCL_BLOCK_DATA 0x0a 103271b33a6SRui Paulo #define SMB_PRTCL_PROC_CALL 0x0c 104271b33a6SRui Paulo #define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 105271b33a6SRui Paulo #define SMB_PRTCL_PEC 0x80 106271b33a6SRui Paulo 107271b33a6SRui Paulo struct amdsmb_softc { 108271b33a6SRui Paulo int rid; 109271b33a6SRui Paulo struct resource *res; 110271b33a6SRui Paulo device_t smbus; 111271b33a6SRui Paulo struct mtx lock; 112271b33a6SRui Paulo }; 113271b33a6SRui Paulo 114271b33a6SRui Paulo #define AMDSMB_LOCK(amdsmb) mtx_lock(&(amdsmb)->lock) 115271b33a6SRui Paulo #define AMDSMB_UNLOCK(amdsmb) mtx_unlock(&(amdsmb)->lock) 116271b33a6SRui Paulo #define AMDSMB_LOCK_ASSERT(amdsmb) mtx_assert(&(amdsmb)->lock, MA_OWNED) 117271b33a6SRui Paulo 118271b33a6SRui Paulo #define AMDSMB_ECINB(amdsmb, register) \ 119271b33a6SRui Paulo (bus_read_1(amdsmb->res, register)) 120271b33a6SRui Paulo #define AMDSMB_ECOUTB(amdsmb, register, value) \ 121271b33a6SRui Paulo (bus_write_1(amdsmb->res, register, value)) 122271b33a6SRui Paulo 123271b33a6SRui Paulo static int amdsmb_detach(device_t dev); 124271b33a6SRui Paulo 12569c173e2SWarner Losh struct pci_device_table amdsmb_devs[] = { 12669c173e2SWarner Losh { PCI_DEV(AMDSMB_VENDORID_AMD, AMDSMB_DEVICEID_AMD8111_SMB2), 12769c173e2SWarner Losh PCI_DESCR("AMD-8111 SMBus 2.0 Controller") } 12869c173e2SWarner Losh }; 12969c173e2SWarner Losh 130271b33a6SRui Paulo static int 131271b33a6SRui Paulo amdsmb_probe(device_t dev) 132271b33a6SRui Paulo { 13369c173e2SWarner Losh const struct pci_device_table *tbl; 134271b33a6SRui Paulo 13569c173e2SWarner Losh tbl = PCI_MATCH(dev, amdsmb_devs); 13669c173e2SWarner Losh if (tbl == NULL) 137271b33a6SRui Paulo return (ENXIO); 13869c173e2SWarner Losh device_set_desc(dev, tbl->descr); 13969c173e2SWarner Losh 14069c173e2SWarner Losh return (BUS_PROBE_DEFAULT); 141271b33a6SRui Paulo } 142271b33a6SRui Paulo 143271b33a6SRui Paulo static int 144271b33a6SRui Paulo amdsmb_attach(device_t dev) 145271b33a6SRui Paulo { 146271b33a6SRui Paulo struct amdsmb_softc *amdsmb_sc = device_get_softc(dev); 147271b33a6SRui Paulo 148271b33a6SRui Paulo /* Allocate I/O space */ 149271b33a6SRui Paulo amdsmb_sc->rid = PCIR_BAR(0); 150271b33a6SRui Paulo 151271b33a6SRui Paulo amdsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 152271b33a6SRui Paulo &amdsmb_sc->rid, RF_ACTIVE); 153271b33a6SRui Paulo 154271b33a6SRui Paulo if (amdsmb_sc->res == NULL) { 155271b33a6SRui Paulo device_printf(dev, "could not map i/o space\n"); 156271b33a6SRui Paulo return (ENXIO); 157271b33a6SRui Paulo } 158271b33a6SRui Paulo 159271b33a6SRui Paulo mtx_init(&amdsmb_sc->lock, device_get_nameunit(dev), "amdsmb", MTX_DEF); 160271b33a6SRui Paulo 161271b33a6SRui Paulo /* Allocate a new smbus device */ 162*5b56413dSWarner Losh amdsmb_sc->smbus = device_add_child(dev, "smbus", DEVICE_UNIT_ANY); 163271b33a6SRui Paulo if (!amdsmb_sc->smbus) { 164271b33a6SRui Paulo amdsmb_detach(dev); 165271b33a6SRui Paulo return (EINVAL); 166271b33a6SRui Paulo } 167271b33a6SRui Paulo 168271b33a6SRui Paulo bus_generic_attach(dev); 169271b33a6SRui Paulo 170271b33a6SRui Paulo return (0); 171271b33a6SRui Paulo } 172271b33a6SRui Paulo 173271b33a6SRui Paulo static int 174271b33a6SRui Paulo amdsmb_detach(device_t dev) 175271b33a6SRui Paulo { 176271b33a6SRui Paulo struct amdsmb_softc *amdsmb_sc = device_get_softc(dev); 177271b33a6SRui Paulo 178271b33a6SRui Paulo if (amdsmb_sc->smbus) { 179271b33a6SRui Paulo device_delete_child(dev, amdsmb_sc->smbus); 180271b33a6SRui Paulo amdsmb_sc->smbus = NULL; 181271b33a6SRui Paulo } 182271b33a6SRui Paulo 183271b33a6SRui Paulo mtx_destroy(&amdsmb_sc->lock); 184271b33a6SRui Paulo if (amdsmb_sc->res) 185271b33a6SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, amdsmb_sc->rid, 186271b33a6SRui Paulo amdsmb_sc->res); 187271b33a6SRui Paulo 188271b33a6SRui Paulo return (0); 189271b33a6SRui Paulo } 190271b33a6SRui Paulo 191271b33a6SRui Paulo static int 192271b33a6SRui Paulo amdsmb_callback(device_t dev, int index, void *data) 193271b33a6SRui Paulo { 194271b33a6SRui Paulo int error = 0; 195271b33a6SRui Paulo 196271b33a6SRui Paulo switch (index) { 197271b33a6SRui Paulo case SMB_REQUEST_BUS: 198271b33a6SRui Paulo case SMB_RELEASE_BUS: 199271b33a6SRui Paulo break; 200271b33a6SRui Paulo default: 201271b33a6SRui Paulo error = EINVAL; 202271b33a6SRui Paulo } 203271b33a6SRui Paulo 204271b33a6SRui Paulo return (error); 205271b33a6SRui Paulo } 206271b33a6SRui Paulo 207271b33a6SRui Paulo static int 208271b33a6SRui Paulo amdsmb_ec_wait_write(struct amdsmb_softc *sc) 209271b33a6SRui Paulo { 210271b33a6SRui Paulo int timeout = 500; 211271b33a6SRui Paulo 212271b33a6SRui Paulo while (timeout-- && AMDSMB_ECINB(sc, EC_SC) & EC_SC_IBF) 213271b33a6SRui Paulo DELAY(1); 214271b33a6SRui Paulo if (timeout == 0) { 215271b33a6SRui Paulo device_printf(sc->smbus, "timeout waiting for IBF to clear\n"); 216271b33a6SRui Paulo return (1); 217271b33a6SRui Paulo } 218271b33a6SRui Paulo return (0); 219271b33a6SRui Paulo } 220271b33a6SRui Paulo 221271b33a6SRui Paulo static int 222271b33a6SRui Paulo amdsmb_ec_wait_read(struct amdsmb_softc *sc) 223271b33a6SRui Paulo { 224271b33a6SRui Paulo int timeout = 500; 225271b33a6SRui Paulo 226271b33a6SRui Paulo while (timeout-- && ~AMDSMB_ECINB(sc, EC_SC) & EC_SC_OBF) 227271b33a6SRui Paulo DELAY(1); 228271b33a6SRui Paulo if (timeout == 0) { 229271b33a6SRui Paulo device_printf(sc->smbus, "timeout waiting for OBF to set\n"); 230271b33a6SRui Paulo return (1); 231271b33a6SRui Paulo } 232271b33a6SRui Paulo return (0); 233271b33a6SRui Paulo } 234271b33a6SRui Paulo 235271b33a6SRui Paulo static int 236271b33a6SRui Paulo amdsmb_ec_read(struct amdsmb_softc *sc, u_char addr, u_char *data) 237271b33a6SRui Paulo { 238271b33a6SRui Paulo 239271b33a6SRui Paulo AMDSMB_LOCK_ASSERT(sc); 240271b33a6SRui Paulo if (amdsmb_ec_wait_write(sc)) 241271b33a6SRui Paulo return (1); 242271b33a6SRui Paulo AMDSMB_ECOUTB(sc, EC_CMD, EC_CMD_RD); 243271b33a6SRui Paulo 244271b33a6SRui Paulo if (amdsmb_ec_wait_write(sc)) 245271b33a6SRui Paulo return (1); 246271b33a6SRui Paulo AMDSMB_ECOUTB(sc, EC_DATA, addr); 247271b33a6SRui Paulo 248271b33a6SRui Paulo if (amdsmb_ec_wait_read(sc)) 249271b33a6SRui Paulo return (1); 250271b33a6SRui Paulo *data = AMDSMB_ECINB(sc, EC_DATA); 251271b33a6SRui Paulo 252271b33a6SRui Paulo return (0); 253271b33a6SRui Paulo } 254271b33a6SRui Paulo 255271b33a6SRui Paulo static int 256271b33a6SRui Paulo amdsmb_ec_write(struct amdsmb_softc *sc, u_char addr, u_char data) 257271b33a6SRui Paulo { 258271b33a6SRui Paulo 259271b33a6SRui Paulo AMDSMB_LOCK_ASSERT(sc); 260271b33a6SRui Paulo if (amdsmb_ec_wait_write(sc)) 261271b33a6SRui Paulo return (1); 262271b33a6SRui Paulo AMDSMB_ECOUTB(sc, EC_CMD, EC_CMD_WR); 263271b33a6SRui Paulo 264271b33a6SRui Paulo if (amdsmb_ec_wait_write(sc)) 265271b33a6SRui Paulo return (1); 266271b33a6SRui Paulo AMDSMB_ECOUTB(sc, EC_DATA, addr); 267271b33a6SRui Paulo 268271b33a6SRui Paulo if (amdsmb_ec_wait_write(sc)) 269271b33a6SRui Paulo return (1); 270271b33a6SRui Paulo AMDSMB_ECOUTB(sc, EC_DATA, data); 271271b33a6SRui Paulo 272271b33a6SRui Paulo return (0); 273271b33a6SRui Paulo } 274271b33a6SRui Paulo 275271b33a6SRui Paulo static int 276271b33a6SRui Paulo amdsmb_wait(struct amdsmb_softc *sc) 277271b33a6SRui Paulo { 278271b33a6SRui Paulo u_char sts, temp; 279271b33a6SRui Paulo int error, count; 280271b33a6SRui Paulo 281271b33a6SRui Paulo AMDSMB_LOCK_ASSERT(sc); 282271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_PRTCL, &temp); 283271b33a6SRui Paulo if (temp != 0) 284271b33a6SRui Paulo { 285271b33a6SRui Paulo count = 10000; 286271b33a6SRui Paulo do { 287271b33a6SRui Paulo DELAY(500); 288271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_PRTCL, &temp); 289271b33a6SRui Paulo } while (temp != 0 && count--); 290271b33a6SRui Paulo if (count == 0) 291271b33a6SRui Paulo return (SMB_ETIMEOUT); 292271b33a6SRui Paulo } 293271b33a6SRui Paulo 294271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_STS, &sts); 295271b33a6SRui Paulo sts &= SMB_STS_STATUS; 296271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: STS=0x%x\n", sts)); 297271b33a6SRui Paulo 298271b33a6SRui Paulo switch (sts) { 299271b33a6SRui Paulo case SMB_STS_OK: 300271b33a6SRui Paulo error = SMB_ENOERR; 301271b33a6SRui Paulo break; 302271b33a6SRui Paulo case SMB_STS_DANA: 303271b33a6SRui Paulo error = SMB_ENOACK; 304271b33a6SRui Paulo break; 305271b33a6SRui Paulo case SMB_STS_B: 306271b33a6SRui Paulo error = SMB_EBUSY; 307271b33a6SRui Paulo break; 308271b33a6SRui Paulo case SMB_STS_T: 309271b33a6SRui Paulo error = SMB_ETIMEOUT; 310271b33a6SRui Paulo break; 311271b33a6SRui Paulo case SMB_STS_DCAD: 312271b33a6SRui Paulo case SMB_STS_DAD: 313271b33a6SRui Paulo case SMB_STS_HUP: 314271b33a6SRui Paulo error = SMB_ENOTSUPP; 315271b33a6SRui Paulo break; 316271b33a6SRui Paulo default: 317271b33a6SRui Paulo error = SMB_EBUSERR; 318271b33a6SRui Paulo break; 319271b33a6SRui Paulo } 320271b33a6SRui Paulo 321271b33a6SRui Paulo return (error); 322271b33a6SRui Paulo } 323271b33a6SRui Paulo 324271b33a6SRui Paulo static int 325271b33a6SRui Paulo amdsmb_quick(device_t dev, u_char slave, int how) 326271b33a6SRui Paulo { 327271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 328271b33a6SRui Paulo u_char protocol; 329271b33a6SRui Paulo int error; 330271b33a6SRui Paulo 331271b33a6SRui Paulo protocol = SMB_PRTCL_QUICK; 332271b33a6SRui Paulo 333271b33a6SRui Paulo switch (how) { 334271b33a6SRui Paulo case SMB_QWRITE: 335271b33a6SRui Paulo protocol |= SMB_PRTCL_WRITE; 336271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: QWRITE to 0x%x", slave)); 337271b33a6SRui Paulo break; 338271b33a6SRui Paulo case SMB_QREAD: 339271b33a6SRui Paulo protocol |= SMB_PRTCL_READ; 340271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: QREAD to 0x%x", slave)); 341271b33a6SRui Paulo break; 342271b33a6SRui Paulo default: 343271b33a6SRui Paulo panic("%s: unknown QUICK command (%x)!", __func__, how); 344271b33a6SRui Paulo } 345271b33a6SRui Paulo 346271b33a6SRui Paulo AMDSMB_LOCK(sc); 347271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 348271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, protocol); 349271b33a6SRui Paulo 350271b33a6SRui Paulo error = amdsmb_wait(sc); 351271b33a6SRui Paulo 352271b33a6SRui Paulo AMDSMB_DEBUG(printf(", error=0x%x\n", error)); 353271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 354271b33a6SRui Paulo 355271b33a6SRui Paulo return (error); 356271b33a6SRui Paulo } 357271b33a6SRui Paulo 358271b33a6SRui Paulo static int 359271b33a6SRui Paulo amdsmb_sendb(device_t dev, u_char slave, char byte) 360271b33a6SRui Paulo { 361271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 362271b33a6SRui Paulo int error; 363271b33a6SRui Paulo 364271b33a6SRui Paulo AMDSMB_LOCK(sc); 365271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, byte); 366271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 367271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 368271b33a6SRui Paulo 369271b33a6SRui Paulo error = amdsmb_wait(sc); 370271b33a6SRui Paulo 371271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", 372271b33a6SRui Paulo slave, byte, error)); 373271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 374271b33a6SRui Paulo 375271b33a6SRui Paulo return (error); 376271b33a6SRui Paulo } 377271b33a6SRui Paulo 378271b33a6SRui Paulo static int 379271b33a6SRui Paulo amdsmb_recvb(device_t dev, u_char slave, char *byte) 380271b33a6SRui Paulo { 381271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 382271b33a6SRui Paulo int error; 383271b33a6SRui Paulo 384271b33a6SRui Paulo AMDSMB_LOCK(sc); 385271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 386271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 387271b33a6SRui Paulo 388271b33a6SRui Paulo if ((error = amdsmb_wait(sc)) == SMB_ENOERR) 389271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_DATA, byte); 390271b33a6SRui Paulo 391271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", 392271b33a6SRui Paulo slave, *byte, error)); 393271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 394271b33a6SRui Paulo 395271b33a6SRui Paulo return (error); 396271b33a6SRui Paulo } 397271b33a6SRui Paulo 398271b33a6SRui Paulo static int 399271b33a6SRui Paulo amdsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 400271b33a6SRui Paulo { 401271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 402271b33a6SRui Paulo int error; 403271b33a6SRui Paulo 404271b33a6SRui Paulo AMDSMB_LOCK(sc); 405271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, cmd); 406271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_DATA, byte); 407271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 408271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 409271b33a6SRui Paulo 410271b33a6SRui Paulo error = amdsmb_wait(sc); 411271b33a6SRui Paulo 412271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, " 413271b33a6SRui Paulo "error=0x%x\n", slave, cmd, byte, error)); 414271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 415271b33a6SRui Paulo 416271b33a6SRui Paulo return (error); 417271b33a6SRui Paulo } 418271b33a6SRui Paulo 419271b33a6SRui Paulo static int 420271b33a6SRui Paulo amdsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 421271b33a6SRui Paulo { 422271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 423271b33a6SRui Paulo int error; 424271b33a6SRui Paulo 425271b33a6SRui Paulo AMDSMB_LOCK(sc); 426271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, cmd); 427271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 428271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 429271b33a6SRui Paulo 430271b33a6SRui Paulo if ((error = amdsmb_wait(sc)) == SMB_ENOERR) 431271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_DATA, byte); 432271b33a6SRui Paulo 433271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, " 434271b33a6SRui Paulo "error=0x%x\n", slave, cmd, (unsigned char)*byte, error)); 435271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 436271b33a6SRui Paulo 437271b33a6SRui Paulo return (error); 438271b33a6SRui Paulo } 439271b33a6SRui Paulo 440271b33a6SRui Paulo static int 441271b33a6SRui Paulo amdsmb_writew(device_t dev, u_char slave, char cmd, short word) 442271b33a6SRui Paulo { 443271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 444271b33a6SRui Paulo int error; 445271b33a6SRui Paulo 446271b33a6SRui Paulo AMDSMB_LOCK(sc); 447271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, cmd); 448271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_DATA, word); 449271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_DATA + 1, word >> 8); 450271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 451271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 452271b33a6SRui Paulo 453271b33a6SRui Paulo error = amdsmb_wait(sc); 454271b33a6SRui Paulo 455271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, " 456271b33a6SRui Paulo "error=0x%x\n", slave, cmd, word, error)); 457271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 458271b33a6SRui Paulo 459271b33a6SRui Paulo return (error); 460271b33a6SRui Paulo } 461271b33a6SRui Paulo 462271b33a6SRui Paulo static int 463271b33a6SRui Paulo amdsmb_readw(device_t dev, u_char slave, char cmd, short *word) 464271b33a6SRui Paulo { 465271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 466271b33a6SRui Paulo u_char temp[2]; 467271b33a6SRui Paulo int error; 468271b33a6SRui Paulo 469271b33a6SRui Paulo AMDSMB_LOCK(sc); 470271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, cmd); 471271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 472271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 473271b33a6SRui Paulo 474271b33a6SRui Paulo if ((error = amdsmb_wait(sc)) == SMB_ENOERR) { 475271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_DATA + 0, &temp[0]); 476271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_DATA + 1, &temp[1]); 477271b33a6SRui Paulo *word = temp[0] | (temp[1] << 8); 478271b33a6SRui Paulo } 479271b33a6SRui Paulo 480271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: READW from 0x%x, cmd=0x%x, word=0x%x, " 481271b33a6SRui Paulo "error=0x%x\n", slave, cmd, (unsigned short)*word, error)); 482271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 483271b33a6SRui Paulo 484271b33a6SRui Paulo return (error); 485271b33a6SRui Paulo } 486271b33a6SRui Paulo 487271b33a6SRui Paulo static int 488271b33a6SRui Paulo amdsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 489271b33a6SRui Paulo { 490271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 491271b33a6SRui Paulo u_char i; 492271b33a6SRui Paulo int error; 493271b33a6SRui Paulo 494271b33a6SRui Paulo if (count < 1 || count > 32) 495271b33a6SRui Paulo return (SMB_EINVAL); 496271b33a6SRui Paulo 497271b33a6SRui Paulo AMDSMB_LOCK(sc); 498271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, cmd); 499271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_BCNT, count); 500271b33a6SRui Paulo for (i = 0; i < count; i++) 501271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_DATA + i, buf[i]); 502271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 503271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 504271b33a6SRui Paulo 505271b33a6SRui Paulo error = amdsmb_wait(sc); 506271b33a6SRui Paulo 507271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, " 508271b33a6SRui Paulo "error=0x%x", slave, count, cmd, error)); 509271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 510271b33a6SRui Paulo 511271b33a6SRui Paulo return (error); 512271b33a6SRui Paulo } 513271b33a6SRui Paulo 514271b33a6SRui Paulo static int 515271b33a6SRui Paulo amdsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 516271b33a6SRui Paulo { 517271b33a6SRui Paulo struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 518271b33a6SRui Paulo u_char data, len, i; 519271b33a6SRui Paulo int error; 520271b33a6SRui Paulo 521271b33a6SRui Paulo if (*count < 1 || *count > 32) 522271b33a6SRui Paulo return (SMB_EINVAL); 523271b33a6SRui Paulo 524271b33a6SRui Paulo AMDSMB_LOCK(sc); 525271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_CMD, cmd); 526271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_ADDR, slave); 527271b33a6SRui Paulo amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 528271b33a6SRui Paulo 529271b33a6SRui Paulo if ((error = amdsmb_wait(sc)) == SMB_ENOERR) { 530271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_BCNT, &len); 531271b33a6SRui Paulo for (i = 0; i < len; i++) { 532271b33a6SRui Paulo amdsmb_ec_read(sc, SMB_DATA + i, &data); 533271b33a6SRui Paulo if (i < *count) 534271b33a6SRui Paulo buf[i] = data; 535271b33a6SRui Paulo } 536271b33a6SRui Paulo *count = len; 537271b33a6SRui Paulo } 538271b33a6SRui Paulo 539271b33a6SRui Paulo AMDSMB_DEBUG(printf("amdsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, " 540271b33a6SRui Paulo "error=0x%x", slave, *count, cmd, error)); 541271b33a6SRui Paulo AMDSMB_UNLOCK(sc); 542271b33a6SRui Paulo 543271b33a6SRui Paulo return (error); 544271b33a6SRui Paulo } 545271b33a6SRui Paulo 546271b33a6SRui Paulo static device_method_t amdsmb_methods[] = { 547271b33a6SRui Paulo /* Device interface */ 548271b33a6SRui Paulo DEVMETHOD(device_probe, amdsmb_probe), 549271b33a6SRui Paulo DEVMETHOD(device_attach, amdsmb_attach), 550271b33a6SRui Paulo DEVMETHOD(device_detach, amdsmb_detach), 551271b33a6SRui Paulo 552271b33a6SRui Paulo /* SMBus interface */ 553271b33a6SRui Paulo DEVMETHOD(smbus_callback, amdsmb_callback), 554271b33a6SRui Paulo DEVMETHOD(smbus_quick, amdsmb_quick), 555271b33a6SRui Paulo DEVMETHOD(smbus_sendb, amdsmb_sendb), 556271b33a6SRui Paulo DEVMETHOD(smbus_recvb, amdsmb_recvb), 557271b33a6SRui Paulo DEVMETHOD(smbus_writeb, amdsmb_writeb), 558271b33a6SRui Paulo DEVMETHOD(smbus_readb, amdsmb_readb), 559271b33a6SRui Paulo DEVMETHOD(smbus_writew, amdsmb_writew), 560271b33a6SRui Paulo DEVMETHOD(smbus_readw, amdsmb_readw), 561271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, amdsmb_bwrite), 562271b33a6SRui Paulo DEVMETHOD(smbus_bread, amdsmb_bread), 563271b33a6SRui Paulo { 0, 0 } 564271b33a6SRui Paulo }; 565271b33a6SRui Paulo 566271b33a6SRui Paulo static driver_t amdsmb_driver = { 567271b33a6SRui Paulo "amdsmb", 568271b33a6SRui Paulo amdsmb_methods, 569271b33a6SRui Paulo sizeof(struct amdsmb_softc), 570271b33a6SRui Paulo }; 571271b33a6SRui Paulo 57283a273efSJohn Baldwin DRIVER_MODULE(amdsmb, pci, amdsmb_driver, 0, 0); 573c6d39765SJohn Baldwin DRIVER_MODULE(smbus, amdsmb, smbus_driver, 0, 0); 574271b33a6SRui Paulo 575271b33a6SRui Paulo MODULE_DEPEND(amdsmb, pci, 1, 1, 1); 576271b33a6SRui Paulo MODULE_DEPEND(amdsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 577271b33a6SRui Paulo MODULE_VERSION(amdsmb, 1); 578