1175533Sru/*- 2175533Sru * Copyright (c) 2005 Ruslan Ermilov 3175533Sru * All rights reserved. 4175533Sru * 5175533Sru * Redistribution and use in source and binary forms, with or without 6175533Sru * modification, are permitted provided that the following conditions 7175533Sru * are met: 8175533Sru * 1. Redistributions of source code must retain the above copyright 9175533Sru * notice, this list of conditions and the following disclaimer. 10175533Sru * 2. Redistributions in binary form must reproduce the above copyright 11175533Sru * notice, this list of conditions and the following disclaimer in the 12175533Sru * documentation and/or other materials provided with the distribution. 13175533Sru * 14175533Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15175533Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16175533Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17175533Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18175533Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19175533Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20175533Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21175533Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22175533Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23175533Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24175533Sru * SUCH DAMAGE. 25175533Sru */ 26175533Sru 27153618Sru#include <sys/cdefs.h> 28153618Sru__FBSDID("$FreeBSD: releng/10.2/sys/pci/amdsmb.c 179622 2008-06-06 18:29:56Z jhb $"); 29153618Sru 30153618Sru#include <sys/param.h> 31165951Sjhb#include <sys/bus.h> 32153618Sru#include <sys/kernel.h> 33165951Sjhb#include <sys/lock.h> 34165951Sjhb#include <sys/module.h> 35165951Sjhb#include <sys/mutex.h> 36153618Sru#include <sys/systm.h> 37153618Sru 38153618Sru#include <machine/bus.h> 39153618Sru#include <machine/resource.h> 40153618Sru#include <sys/rman.h> 41153618Sru 42153618Sru#include <dev/pci/pcivar.h> 43153618Sru#include <dev/pci/pcireg.h> 44153618Sru 45153618Sru#include <dev/smbus/smbconf.h> 46153618Sru#include "smbus_if.h" 47153618Sru 48153618Sru#define AMDSMB_DEBUG(x) if (amdsmb_debug) (x) 49153618Sru 50153618Sru#ifdef DEBUG 51153618Srustatic int amdsmb_debug = 1; 52153618Sru#else 53153618Srustatic int amdsmb_debug = 0; 54153618Sru#endif 55153618Sru 56153618Sru#define AMDSMB_VENDORID_AMD 0x1022 57153618Sru#define AMDSMB_DEVICEID_AMD8111_SMB2 0x746a 58153618Sru 59153618Sru/* 60153618Sru * ACPI 3.0, Chapter 12, Embedded Controller Interface. 61153618Sru */ 62153618Sru#define EC_DATA 0x00 /* data register */ 63153618Sru#define EC_SC 0x04 /* status of controller */ 64153618Sru#define EC_CMD 0x04 /* command register */ 65153618Sru 66153618Sru#define EC_SC_IBF 0x02 /* data ready for embedded controller */ 67153618Sru#define EC_SC_OBF 0x01 /* data ready for host */ 68153618Sru#define EC_CMD_WR 0x81 /* write EC */ 69153618Sru#define EC_CMD_RD 0x80 /* read EC */ 70153618Sru 71153618Sru/* 72153618Sru * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 73153618Sru */ 74153618Sru#define SMB_PRTCL 0x00 /* protocol */ 75153618Sru#define SMB_STS 0x01 /* status */ 76153618Sru#define SMB_ADDR 0x02 /* address */ 77153618Sru#define SMB_CMD 0x03 /* command */ 78153618Sru#define SMB_DATA 0x04 /* 32 data registers */ 79153618Sru#define SMB_BCNT 0x24 /* number of data bytes */ 80153618Sru#define SMB_ALRM_A 0x25 /* alarm address */ 81153618Sru#define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 82153618Sru 83153618Sru#define SMB_STS_DONE 0x80 84153618Sru#define SMB_STS_ALRM 0x40 85153618Sru#define SMB_STS_RES 0x20 86153618Sru#define SMB_STS_STATUS 0x1f 87153618Sru#define SMB_STS_OK 0x00 /* OK */ 88153618Sru#define SMB_STS_UF 0x07 /* Unknown Failure */ 89153618Sru#define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 90153618Sru#define SMB_STS_DED 0x11 /* Device Error Detected */ 91153618Sru#define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 92153618Sru#define SMB_STS_UE 0x13 /* Unknown Error */ 93153618Sru#define SMB_STS_DAD 0x17 /* Device Access Denied */ 94153618Sru#define SMB_STS_T 0x18 /* Timeout */ 95153618Sru#define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 96153618Sru#define SMB_STS_B 0x1a /* Busy */ 97153618Sru#define SMB_STS_PEC 0x1f /* PEC (CRC-8) Error */ 98153618Sru 99153618Sru#define SMB_PRTCL_WRITE 0x00 100153618Sru#define SMB_PRTCL_READ 0x01 101153618Sru#define SMB_PRTCL_QUICK 0x02 102153618Sru#define SMB_PRTCL_BYTE 0x04 103153618Sru#define SMB_PRTCL_BYTE_DATA 0x06 104153618Sru#define SMB_PRTCL_WORD_DATA 0x08 105153618Sru#define SMB_PRTCL_BLOCK_DATA 0x0a 106153618Sru#define SMB_PRTCL_PROC_CALL 0x0c 107153618Sru#define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 108153618Sru#define SMB_PRTCL_PEC 0x80 109153618Sru 110153618Srustruct amdsmb_softc { 111153618Sru int rid; 112153618Sru struct resource *res; 113153618Sru device_t smbus; 114165951Sjhb struct mtx lock; 115153618Sru}; 116153618Sru 117165951Sjhb#define AMDSMB_LOCK(amdsmb) mtx_lock(&(amdsmb)->lock) 118165951Sjhb#define AMDSMB_UNLOCK(amdsmb) mtx_unlock(&(amdsmb)->lock) 119165951Sjhb#define AMDSMB_LOCK_ASSERT(amdsmb) mtx_assert(&(amdsmb)->lock, MA_OWNED) 120165951Sjhb 121165951Sjhb#define AMDSMB_ECINB(amdsmb, register) \ 122179622Sjhb (bus_read_1(amdsmb->res, register)) 123153618Sru#define AMDSMB_ECOUTB(amdsmb, register, value) \ 124179622Sjhb (bus_write_1(amdsmb->res, register, value)) 125153618Sru 126165951Sjhbstatic int amdsmb_detach(device_t dev); 127165951Sjhb 128153618Srustatic int 129153618Sruamdsmb_probe(device_t dev) 130153618Sru{ 131153618Sru u_int16_t vid; 132153618Sru u_int16_t did; 133153618Sru 134153618Sru vid = pci_get_vendor(dev); 135153618Sru did = pci_get_device(dev); 136153618Sru 137153618Sru if (vid == AMDSMB_VENDORID_AMD) { 138153618Sru switch(did) { 139153618Sru case AMDSMB_DEVICEID_AMD8111_SMB2: 140153618Sru device_set_desc(dev, "AMD-8111 SMBus 2.0 Controller"); 141153618Sru return (BUS_PROBE_DEFAULT); 142153618Sru } 143153618Sru } 144153618Sru 145153618Sru return (ENXIO); 146153618Sru} 147153618Sru 148153618Srustatic int 149153618Sruamdsmb_attach(device_t dev) 150153618Sru{ 151153618Sru struct amdsmb_softc *amdsmb_sc = device_get_softc(dev); 152153618Sru 153153618Sru /* Allocate I/O space */ 154153618Sru amdsmb_sc->rid = PCIR_BAR(0); 155153618Sru 156153618Sru amdsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 157153618Sru &amdsmb_sc->rid, RF_ACTIVE); 158153618Sru 159153618Sru if (amdsmb_sc->res == NULL) { 160153618Sru device_printf(dev, "could not map i/o space\n"); 161153618Sru return (ENXIO); 162153618Sru } 163153618Sru 164165951Sjhb mtx_init(&amdsmb_sc->lock, device_get_nameunit(dev), "amdsmb", MTX_DEF); 165153618Sru 166153618Sru /* Allocate a new smbus device */ 167153618Sru amdsmb_sc->smbus = device_add_child(dev, "smbus", -1); 168165951Sjhb if (!amdsmb_sc->smbus) { 169165951Sjhb amdsmb_detach(dev); 170153618Sru return (EINVAL); 171165951Sjhb } 172153618Sru 173153618Sru bus_generic_attach(dev); 174153618Sru 175153618Sru return (0); 176153618Sru} 177153618Sru 178153618Srustatic int 179153618Sruamdsmb_detach(device_t dev) 180153618Sru{ 181153618Sru struct amdsmb_softc *amdsmb_sc = device_get_softc(dev); 182153618Sru 183153618Sru if (amdsmb_sc->smbus) { 184153618Sru device_delete_child(dev, amdsmb_sc->smbus); 185153618Sru amdsmb_sc->smbus = NULL; 186153618Sru } 187153618Sru 188165951Sjhb mtx_destroy(&amdsmb_sc->lock); 189153618Sru if (amdsmb_sc->res) 190153618Sru bus_release_resource(dev, SYS_RES_IOPORT, amdsmb_sc->rid, 191153618Sru amdsmb_sc->res); 192153618Sru 193153618Sru return (0); 194153618Sru} 195153618Sru 196153618Srustatic int 197162234Sjhbamdsmb_callback(device_t dev, int index, void *data) 198153618Sru{ 199153618Sru int error = 0; 200153618Sru 201153618Sru switch (index) { 202153618Sru case SMB_REQUEST_BUS: 203153618Sru case SMB_RELEASE_BUS: 204153618Sru break; 205153618Sru default: 206153618Sru error = EINVAL; 207153618Sru } 208153618Sru 209153618Sru return (error); 210153618Sru} 211153618Sru 212153618Srustatic int 213153618Sruamdsmb_ec_wait_write(struct amdsmb_softc *sc) 214153618Sru{ 215153618Sru int timeout = 500; 216153618Sru 217153618Sru while (timeout-- && AMDSMB_ECINB(sc, EC_SC) & EC_SC_IBF) 218153618Sru DELAY(1); 219153618Sru if (timeout == 0) { 220153618Sru device_printf(sc->smbus, "timeout waiting for IBF to clear\n"); 221153618Sru return (1); 222153618Sru } 223153618Sru return (0); 224153618Sru} 225153618Sru 226153618Srustatic int 227153618Sruamdsmb_ec_wait_read(struct amdsmb_softc *sc) 228153618Sru{ 229153618Sru int timeout = 500; 230153618Sru 231153618Sru while (timeout-- && ~AMDSMB_ECINB(sc, EC_SC) & EC_SC_OBF) 232153618Sru DELAY(1); 233153618Sru if (timeout == 0) { 234153618Sru device_printf(sc->smbus, "timeout waiting for OBF to set\n"); 235153618Sru return (1); 236153618Sru } 237153618Sru return (0); 238153618Sru} 239153618Sru 240153618Srustatic int 241153618Sruamdsmb_ec_read(struct amdsmb_softc *sc, u_char addr, u_char *data) 242153618Sru{ 243153618Sru 244165951Sjhb AMDSMB_LOCK_ASSERT(sc); 245153618Sru if (amdsmb_ec_wait_write(sc)) 246153618Sru return (1); 247153618Sru AMDSMB_ECOUTB(sc, EC_CMD, EC_CMD_RD); 248153618Sru 249153618Sru if (amdsmb_ec_wait_write(sc)) 250153618Sru return (1); 251153618Sru AMDSMB_ECOUTB(sc, EC_DATA, addr); 252153618Sru 253153618Sru if (amdsmb_ec_wait_read(sc)) 254153618Sru return (1); 255153618Sru *data = AMDSMB_ECINB(sc, EC_DATA); 256153618Sru 257153618Sru return (0); 258153618Sru} 259153618Sru 260153618Srustatic int 261153618Sruamdsmb_ec_write(struct amdsmb_softc *sc, u_char addr, u_char data) 262153618Sru{ 263153618Sru 264165951Sjhb AMDSMB_LOCK_ASSERT(sc); 265153618Sru if (amdsmb_ec_wait_write(sc)) 266153618Sru return (1); 267153618Sru AMDSMB_ECOUTB(sc, EC_CMD, EC_CMD_WR); 268153618Sru 269153618Sru if (amdsmb_ec_wait_write(sc)) 270153618Sru return (1); 271153618Sru AMDSMB_ECOUTB(sc, EC_DATA, addr); 272153618Sru 273153618Sru if (amdsmb_ec_wait_write(sc)) 274153618Sru return (1); 275153618Sru AMDSMB_ECOUTB(sc, EC_DATA, data); 276153618Sru 277153618Sru return (0); 278153618Sru} 279153618Sru 280153618Srustatic int 281153618Sruamdsmb_wait(struct amdsmb_softc *sc) 282153618Sru{ 283153618Sru u_char sts, temp; 284153618Sru int error, count; 285153618Sru 286165951Sjhb AMDSMB_LOCK_ASSERT(sc); 287153618Sru amdsmb_ec_read(sc, SMB_PRTCL, &temp); 288153618Sru if (temp != 0) 289153618Sru { 290153618Sru count = 10000; 291153618Sru do { 292153618Sru DELAY(500); 293153618Sru amdsmb_ec_read(sc, SMB_PRTCL, &temp); 294153618Sru } while (temp != 0 && count--); 295153618Sru if (count == 0) 296153618Sru return (SMB_ETIMEOUT); 297153618Sru } 298153618Sru 299153618Sru amdsmb_ec_read(sc, SMB_STS, &sts); 300153618Sru sts &= SMB_STS_STATUS; 301153618Sru AMDSMB_DEBUG(printf("amdsmb: STS=0x%x\n", sts)); 302153618Sru 303153618Sru switch (sts) { 304153618Sru case SMB_STS_OK: 305153618Sru error = SMB_ENOERR; 306153618Sru break; 307153618Sru case SMB_STS_DANA: 308153618Sru error = SMB_ENOACK; 309153618Sru break; 310153618Sru case SMB_STS_B: 311153618Sru error = SMB_EBUSY; 312153618Sru break; 313153618Sru case SMB_STS_T: 314153618Sru error = SMB_ETIMEOUT; 315153618Sru break; 316153618Sru case SMB_STS_DCAD: 317153618Sru case SMB_STS_DAD: 318153618Sru case SMB_STS_HUP: 319153618Sru error = SMB_ENOTSUPP; 320153618Sru break; 321153618Sru default: 322153618Sru error = SMB_EBUSERR; 323153618Sru break; 324153618Sru } 325153618Sru 326153618Sru return (error); 327153618Sru} 328153618Sru 329153618Srustatic int 330153618Sruamdsmb_quick(device_t dev, u_char slave, int how) 331153618Sru{ 332153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 333153618Sru u_char protocol; 334153618Sru int error; 335153618Sru 336153618Sru protocol = SMB_PRTCL_QUICK; 337153618Sru 338153618Sru switch (how) { 339153618Sru case SMB_QWRITE: 340153618Sru protocol |= SMB_PRTCL_WRITE; 341153618Sru AMDSMB_DEBUG(printf("amdsmb: QWRITE to 0x%x", slave)); 342153618Sru break; 343153618Sru case SMB_QREAD: 344153618Sru protocol |= SMB_PRTCL_READ; 345153618Sru AMDSMB_DEBUG(printf("amdsmb: QREAD to 0x%x", slave)); 346153618Sru break; 347153618Sru default: 348153618Sru panic("%s: unknown QUICK command (%x)!", __func__, how); 349153618Sru } 350153618Sru 351165951Sjhb AMDSMB_LOCK(sc); 352153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 353153618Sru amdsmb_ec_write(sc, SMB_PRTCL, protocol); 354153618Sru 355153618Sru error = amdsmb_wait(sc); 356153618Sru 357153618Sru AMDSMB_DEBUG(printf(", error=0x%x\n", error)); 358165951Sjhb AMDSMB_UNLOCK(sc); 359153618Sru 360153618Sru return (error); 361153618Sru} 362153618Sru 363153618Srustatic int 364153618Sruamdsmb_sendb(device_t dev, u_char slave, char byte) 365153618Sru{ 366153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 367153618Sru int error; 368153618Sru 369165951Sjhb AMDSMB_LOCK(sc); 370153618Sru amdsmb_ec_write(sc, SMB_CMD, byte); 371153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 372153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 373153618Sru 374153618Sru error = amdsmb_wait(sc); 375153618Sru 376153618Sru AMDSMB_DEBUG(printf("amdsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", 377153618Sru slave, byte, error)); 378165951Sjhb AMDSMB_UNLOCK(sc); 379153618Sru 380153618Sru return (error); 381153618Sru} 382153618Sru 383153618Srustatic int 384153618Sruamdsmb_recvb(device_t dev, u_char slave, char *byte) 385153618Sru{ 386153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 387153618Sru int error; 388153618Sru 389165951Sjhb AMDSMB_LOCK(sc); 390153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 391153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 392153618Sru 393153618Sru if ((error = amdsmb_wait(sc)) == SMB_ENOERR) 394153618Sru amdsmb_ec_read(sc, SMB_DATA, byte); 395153618Sru 396153618Sru AMDSMB_DEBUG(printf("amdsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", 397153618Sru slave, *byte, error)); 398165951Sjhb AMDSMB_UNLOCK(sc); 399153618Sru 400153618Sru return (error); 401153618Sru} 402153618Sru 403153618Srustatic int 404153618Sruamdsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 405153618Sru{ 406153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 407153618Sru int error; 408153618Sru 409165951Sjhb AMDSMB_LOCK(sc); 410153618Sru amdsmb_ec_write(sc, SMB_CMD, cmd); 411153618Sru amdsmb_ec_write(sc, SMB_DATA, byte); 412153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 413153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 414153618Sru 415153618Sru error = amdsmb_wait(sc); 416153618Sru 417153618Sru AMDSMB_DEBUG(printf("amdsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, " 418153618Sru "error=0x%x\n", slave, cmd, byte, error)); 419165951Sjhb AMDSMB_UNLOCK(sc); 420153618Sru 421153618Sru return (error); 422153618Sru} 423153618Sru 424153618Srustatic int 425153618Sruamdsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 426153618Sru{ 427153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 428153618Sru int error; 429153618Sru 430165951Sjhb AMDSMB_LOCK(sc); 431153618Sru amdsmb_ec_write(sc, SMB_CMD, cmd); 432153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 433153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 434153618Sru 435153618Sru if ((error = amdsmb_wait(sc)) == SMB_ENOERR) 436153618Sru amdsmb_ec_read(sc, SMB_DATA, byte); 437153618Sru 438153618Sru AMDSMB_DEBUG(printf("amdsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, " 439153618Sru "error=0x%x\n", slave, cmd, (unsigned char)*byte, error)); 440165951Sjhb AMDSMB_UNLOCK(sc); 441153618Sru 442153618Sru return (error); 443153618Sru} 444153618Sru 445153618Srustatic int 446153618Sruamdsmb_writew(device_t dev, u_char slave, char cmd, short word) 447153618Sru{ 448153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 449153618Sru int error; 450153618Sru 451165951Sjhb AMDSMB_LOCK(sc); 452153618Sru amdsmb_ec_write(sc, SMB_CMD, cmd); 453153618Sru amdsmb_ec_write(sc, SMB_DATA, word); 454153618Sru amdsmb_ec_write(sc, SMB_DATA + 1, word >> 8); 455153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 456153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 457153618Sru 458153618Sru error = amdsmb_wait(sc); 459153618Sru 460153618Sru AMDSMB_DEBUG(printf("amdsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, " 461153618Sru "error=0x%x\n", slave, cmd, word, error)); 462165951Sjhb AMDSMB_UNLOCK(sc); 463153618Sru 464153618Sru return (error); 465153618Sru} 466153618Sru 467153618Srustatic int 468153618Sruamdsmb_readw(device_t dev, u_char slave, char cmd, short *word) 469153618Sru{ 470153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 471153618Sru u_char temp[2]; 472153618Sru int error; 473153618Sru 474165951Sjhb AMDSMB_LOCK(sc); 475153618Sru amdsmb_ec_write(sc, SMB_CMD, cmd); 476153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 477153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 478153618Sru 479153618Sru if ((error = amdsmb_wait(sc)) == SMB_ENOERR) { 480153618Sru amdsmb_ec_read(sc, SMB_DATA + 0, &temp[0]); 481153618Sru amdsmb_ec_read(sc, SMB_DATA + 1, &temp[1]); 482153618Sru *word = temp[0] | (temp[1] << 8); 483153618Sru } 484153618Sru 485153618Sru AMDSMB_DEBUG(printf("amdsmb: READW from 0x%x, cmd=0x%x, word=0x%x, " 486153618Sru "error=0x%x\n", slave, cmd, (unsigned short)*word, error)); 487165951Sjhb AMDSMB_UNLOCK(sc); 488153618Sru 489153618Sru return (error); 490153618Sru} 491153618Sru 492153618Srustatic int 493153618Sruamdsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 494153618Sru{ 495153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 496162234Sjhb u_char i; 497153618Sru int error; 498153618Sru 499162234Sjhb if (count < 1 || count > 32) 500162234Sjhb return (SMB_EINVAL); 501165951Sjhb 502165951Sjhb AMDSMB_LOCK(sc); 503153618Sru amdsmb_ec_write(sc, SMB_CMD, cmd); 504162234Sjhb amdsmb_ec_write(sc, SMB_BCNT, count); 505162234Sjhb for (i = 0; i < count; i++) 506153618Sru amdsmb_ec_write(sc, SMB_DATA + i, buf[i]); 507153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 508153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 509153618Sru 510153618Sru error = amdsmb_wait(sc); 511153618Sru 512153618Sru AMDSMB_DEBUG(printf("amdsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, " 513153618Sru "error=0x%x", slave, count, cmd, error)); 514165951Sjhb AMDSMB_UNLOCK(sc); 515153618Sru 516153618Sru return (error); 517153618Sru} 518153618Sru 519153618Srustatic int 520162234Sjhbamdsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 521153618Sru{ 522153618Sru struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev); 523162234Sjhb u_char data, len, i; 524153618Sru int error; 525153618Sru 526162234Sjhb if (*count < 1 || *count > 32) 527162234Sjhb return (SMB_EINVAL); 528165951Sjhb 529165951Sjhb AMDSMB_LOCK(sc); 530153618Sru amdsmb_ec_write(sc, SMB_CMD, cmd); 531153618Sru amdsmb_ec_write(sc, SMB_ADDR, slave); 532153618Sru amdsmb_ec_write(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 533153618Sru 534153618Sru if ((error = amdsmb_wait(sc)) == SMB_ENOERR) { 535153618Sru amdsmb_ec_read(sc, SMB_BCNT, &len); 536162234Sjhb for (i = 0; i < len; i++) { 537162234Sjhb amdsmb_ec_read(sc, SMB_DATA + i, &data); 538162234Sjhb if (i < *count) 539162234Sjhb buf[i] = data; 540162234Sjhb } 541162234Sjhb *count = len; 542153618Sru } 543153618Sru 544153618Sru AMDSMB_DEBUG(printf("amdsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, " 545162234Sjhb "error=0x%x", slave, *count, cmd, error)); 546165951Sjhb AMDSMB_UNLOCK(sc); 547153618Sru 548153618Sru return (error); 549153618Sru} 550153618Sru 551153618Srustatic device_method_t amdsmb_methods[] = { 552153618Sru /* Device interface */ 553153618Sru DEVMETHOD(device_probe, amdsmb_probe), 554153618Sru DEVMETHOD(device_attach, amdsmb_attach), 555153618Sru DEVMETHOD(device_detach, amdsmb_detach), 556153618Sru 557153618Sru /* SMBus interface */ 558153618Sru DEVMETHOD(smbus_callback, amdsmb_callback), 559153618Sru DEVMETHOD(smbus_quick, amdsmb_quick), 560153618Sru DEVMETHOD(smbus_sendb, amdsmb_sendb), 561153618Sru DEVMETHOD(smbus_recvb, amdsmb_recvb), 562153618Sru DEVMETHOD(smbus_writeb, amdsmb_writeb), 563153618Sru DEVMETHOD(smbus_readb, amdsmb_readb), 564153618Sru DEVMETHOD(smbus_writew, amdsmb_writew), 565153618Sru DEVMETHOD(smbus_readw, amdsmb_readw), 566153618Sru DEVMETHOD(smbus_bwrite, amdsmb_bwrite), 567153618Sru DEVMETHOD(smbus_bread, amdsmb_bread), 568153618Sru 569153618Sru { 0, 0 } 570153618Sru}; 571153618Sru 572153618Srustatic devclass_t amdsmb_devclass; 573153618Sru 574153618Srustatic driver_t amdsmb_driver = { 575153618Sru "amdsmb", 576153618Sru amdsmb_methods, 577153618Sru sizeof(struct amdsmb_softc), 578153618Sru}; 579153618Sru 580153618SruDRIVER_MODULE(amdsmb, pci, amdsmb_driver, amdsmb_devclass, 0, 0); 581162234SjhbDRIVER_MODULE(smbus, amdsmb, smbus_driver, smbus_devclass, 0, 0); 582153618Sru 583153618SruMODULE_DEPEND(amdsmb, pci, 1, 1, 1); 584153618SruMODULE_DEPEND(amdsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 585153618SruMODULE_VERSION(amdsmb, 1); 586