1139749Simp/*- 266703Sarchie * ichsmb.c 366703Sarchie * 4119418Sobrien * Author: Archie Cobbs <archie@freebsd.org> 566703Sarchie * Copyright (c) 2000 Whistle Communications, Inc. 666703Sarchie * All rights reserved. 766703Sarchie * 866703Sarchie * Subject to the following obligations and disclaimer of warranty, use and 966703Sarchie * redistribution of this software, in source or object code forms, with or 1066703Sarchie * without modifications are expressly permitted by Whistle Communications; 1166703Sarchie * provided, however, that: 1266703Sarchie * 1. Any and all reproductions of the source or object code must include the 1366703Sarchie * copyright notice above and the following disclaimer of warranties; and 1466703Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1566703Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1666703Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1766703Sarchie * such appears in the above copyright notice or in the software. 1866703Sarchie * 1966703Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2066703Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2166703Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2266703Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2366703Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2466703Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2566703Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2666703Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2766703Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2866703Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2966703Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3066703Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3166703Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3266703Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3366703Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3466703Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3566703Sarchie * OF SUCH DAMAGE. 3666703Sarchie */ 3766703Sarchie 38119418Sobrien#include <sys/cdefs.h> 39119418Sobrien__FBSDID("$FreeBSD$"); 40119418Sobrien 4166703Sarchie/* 4266703Sarchie * Support for the SMBus controller logical device which is part of the 4366703Sarchie * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. 4469689Sarchie * 4569689Sarchie * This driver assumes that the generic SMBus code will ensure that 4669689Sarchie * at most one process at a time calls into the SMBus methods below. 4766703Sarchie */ 4866703Sarchie 4966703Sarchie#include <sys/param.h> 5066703Sarchie#include <sys/systm.h> 5166703Sarchie#include <sys/kernel.h> 5266703Sarchie#include <sys/errno.h> 5374914Sjhb#include <sys/lock.h> 54162234Sjhb#include <sys/module.h> 5569689Sarchie#include <sys/mutex.h> 5666703Sarchie#include <sys/syslog.h> 5766703Sarchie#include <sys/bus.h> 5866703Sarchie 5966703Sarchie#include <machine/bus.h> 6066703Sarchie#include <sys/rman.h> 6166703Sarchie#include <machine/resource.h> 6266703Sarchie 6366703Sarchie#include <dev/smbus/smbconf.h> 6466703Sarchie 6566703Sarchie#include <dev/ichsmb/ichsmb_var.h> 6666703Sarchie#include <dev/ichsmb/ichsmb_reg.h> 6766703Sarchie 6866703Sarchie/* 6966703Sarchie * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. 7066703Sarchie */ 7166703Sarchie#define ICHSMB_DEBUG 0 72143063Sjoerg#if ICHSMB_DEBUG != 0 && defined(__CC_SUPPORTS___FUNC__) 7366703Sarchie#define DBG(fmt, args...) \ 74165951Sjhb do { printf("%s: " fmt, __func__ , ## args); } while (0) 7566703Sarchie#else 7666703Sarchie#define DBG(fmt, args...) do { } while (0) 7766703Sarchie#endif 7866703Sarchie 7966703Sarchie/* 8066703Sarchie * Our child device driver name 8166703Sarchie */ 8266703Sarchie#define DRIVER_SMBUS "smbus" 8366703Sarchie 8466703Sarchie/* 8566703Sarchie * Internal functions 8666703Sarchie */ 8766703Sarchiestatic int ichsmb_wait(sc_p sc); 8866703Sarchie 8966703Sarchie/******************************************************************** 9066703Sarchie BUS-INDEPENDENT BUS METHODS 9166703Sarchie********************************************************************/ 9266703Sarchie 9366703Sarchie/* 9466703Sarchie * Handle probe-time duties that are independent of the bus 9566703Sarchie * our device lives on. 9666703Sarchie */ 9766703Sarchieint 9866703Sarchieichsmb_probe(device_t dev) 9966703Sarchie{ 100143160Simp return (BUS_PROBE_DEFAULT); 10166703Sarchie} 10266703Sarchie 10366703Sarchie/* 10466703Sarchie * Handle attach-time duties that are independent of the bus 10566703Sarchie * our device lives on. 10666703Sarchie */ 10766703Sarchieint 10866703Sarchieichsmb_attach(device_t dev) 10966703Sarchie{ 11066703Sarchie const sc_p sc = device_get_softc(dev); 11166703Sarchie int error; 11266703Sarchie 113165951Sjhb /* Create mutex */ 114165951Sjhb mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF); 115165951Sjhb 116147253Stakawata /* Add child: an instance of the "smbus" device */ 117148497Sbrian if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { 118165951Sjhb device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS); 119165951Sjhb error = ENXIO; 120165951Sjhb goto fail; 121147253Stakawata } 122147253Stakawata 12366703Sarchie /* Clear interrupt conditions */ 124179622Sjhb bus_write_1(sc->io_res, ICH_HST_STA, 0xff); 12566703Sarchie 126165951Sjhb /* Set up interrupt handler */ 127179622Sjhb error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 128166901Spiso NULL, ichsmb_device_intr, sc, &sc->irq_handle); 129165951Sjhb if (error != 0) { 130165951Sjhb device_printf(dev, "can't setup irq\n"); 131165951Sjhb goto fail; 132165951Sjhb } 133165951Sjhb 134165951Sjhb /* Attach "smbus" child */ 13566703Sarchie if ((error = bus_generic_attach(dev)) != 0) { 136165951Sjhb device_printf(dev, "failed to attach child: %d\n", error); 137165951Sjhb goto fail; 13866703Sarchie } 13966703Sarchie 14069689Sarchie return (0); 141165951Sjhb 142165951Sjhbfail: 143165951Sjhb mtx_destroy(&sc->mutex); 144165951Sjhb return (error); 14566703Sarchie} 14666703Sarchie 14766703Sarchie/******************************************************************** 14866703Sarchie SMBUS METHODS 14966703Sarchie********************************************************************/ 15066703Sarchie 15166703Sarchieint 152162234Sjhbichsmb_callback(device_t dev, int index, void *data) 15366703Sarchie{ 15466703Sarchie int smb_error = 0; 15566703Sarchie 15666703Sarchie DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); 15766703Sarchie switch (index) { 15866703Sarchie case SMB_REQUEST_BUS: 15966703Sarchie break; 16066703Sarchie case SMB_RELEASE_BUS: 16166703Sarchie break; 16266703Sarchie default: 16366703Sarchie smb_error = SMB_EABORT; /* XXX */ 16466703Sarchie break; 16566703Sarchie } 16666703Sarchie DBG("smb_error=%d\n", smb_error); 16766703Sarchie return (smb_error); 16866703Sarchie} 16966703Sarchie 17066703Sarchieint 17166703Sarchieichsmb_quick(device_t dev, u_char slave, int how) 17266703Sarchie{ 17366703Sarchie const sc_p sc = device_get_softc(dev); 17466703Sarchie int smb_error; 17566703Sarchie 17666703Sarchie DBG("slave=0x%02x how=%d\n", slave, how); 17766703Sarchie KASSERT(sc->ich_cmd == -1, 17887599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 17966703Sarchie switch (how) { 18066703Sarchie case SMB_QREAD: 18166703Sarchie case SMB_QWRITE: 18272200Sbmilekic mtx_lock(&sc->mutex); 18366703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; 184179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 185188077Sjhb slave | (how == SMB_QREAD ? 18666703Sarchie ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); 187179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 18866703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 18966703Sarchie smb_error = ichsmb_wait(sc); 19072200Sbmilekic mtx_unlock(&sc->mutex); 19166703Sarchie break; 19266703Sarchie default: 19366703Sarchie smb_error = SMB_ENOTSUPP; 19466703Sarchie } 19566703Sarchie DBG("smb_error=%d\n", smb_error); 19666703Sarchie return (smb_error); 19766703Sarchie} 19866703Sarchie 19966703Sarchieint 20066703Sarchieichsmb_sendb(device_t dev, u_char slave, char byte) 20166703Sarchie{ 20266703Sarchie const sc_p sc = device_get_softc(dev); 20366703Sarchie int smb_error; 20466703Sarchie 20566703Sarchie DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); 20666703Sarchie KASSERT(sc->ich_cmd == -1, 20787599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 20872200Sbmilekic mtx_lock(&sc->mutex); 20966703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 210179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 211188077Sjhb slave | ICH_XMIT_SLVA_WRITE); 212179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, byte); 213179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 21466703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 21566703Sarchie smb_error = ichsmb_wait(sc); 21672200Sbmilekic mtx_unlock(&sc->mutex); 21766703Sarchie DBG("smb_error=%d\n", smb_error); 21866703Sarchie return (smb_error); 21966703Sarchie} 22066703Sarchie 22166703Sarchieint 22266703Sarchieichsmb_recvb(device_t dev, u_char slave, char *byte) 22366703Sarchie{ 22466703Sarchie const sc_p sc = device_get_softc(dev); 22566703Sarchie int smb_error; 22666703Sarchie 22766703Sarchie DBG("slave=0x%02x\n", slave); 22866703Sarchie KASSERT(sc->ich_cmd == -1, 22987599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 23072200Sbmilekic mtx_lock(&sc->mutex); 23166703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 232179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 233188077Sjhb slave | ICH_XMIT_SLVA_READ); 234179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 23566703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 23666703Sarchie if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 237179622Sjhb *byte = bus_read_1(sc->io_res, ICH_D0); 23872200Sbmilekic mtx_unlock(&sc->mutex); 23966703Sarchie DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 24066703Sarchie return (smb_error); 24166703Sarchie} 24266703Sarchie 24366703Sarchieint 24466703Sarchieichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 24566703Sarchie{ 24666703Sarchie const sc_p sc = device_get_softc(dev); 24766703Sarchie int smb_error; 24866703Sarchie 24966703Sarchie DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", 25066703Sarchie slave, (u_char)cmd, (u_char)byte); 25166703Sarchie KASSERT(sc->ich_cmd == -1, 25287599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 25372200Sbmilekic mtx_lock(&sc->mutex); 25466703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 255179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 256188077Sjhb slave | ICH_XMIT_SLVA_WRITE); 257179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 258179622Sjhb bus_write_1(sc->io_res, ICH_D0, byte); 259179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 26066703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 26166703Sarchie smb_error = ichsmb_wait(sc); 26272200Sbmilekic mtx_unlock(&sc->mutex); 26366703Sarchie DBG("smb_error=%d\n", smb_error); 26466703Sarchie return (smb_error); 26566703Sarchie} 26666703Sarchie 26766703Sarchieint 26866703Sarchieichsmb_writew(device_t dev, u_char slave, char cmd, short word) 26966703Sarchie{ 27066703Sarchie const sc_p sc = device_get_softc(dev); 27166703Sarchie int smb_error; 27266703Sarchie 27366703Sarchie DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", 27466703Sarchie slave, (u_char)cmd, (u_int16_t)word); 27566703Sarchie KASSERT(sc->ich_cmd == -1, 27687599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 27772200Sbmilekic mtx_lock(&sc->mutex); 27866703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 279179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 280188077Sjhb slave | ICH_XMIT_SLVA_WRITE); 281179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 282179622Sjhb bus_write_1(sc->io_res, ICH_D0, word & 0xff); 283179622Sjhb bus_write_1(sc->io_res, ICH_D1, word >> 8); 284179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 28566703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 28666703Sarchie smb_error = ichsmb_wait(sc); 28772200Sbmilekic mtx_unlock(&sc->mutex); 28866703Sarchie DBG("smb_error=%d\n", smb_error); 28966703Sarchie return (smb_error); 29066703Sarchie} 29166703Sarchie 29266703Sarchieint 29366703Sarchieichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 29466703Sarchie{ 29566703Sarchie const sc_p sc = device_get_softc(dev); 29666703Sarchie int smb_error; 29766703Sarchie 29866703Sarchie DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 29966703Sarchie KASSERT(sc->ich_cmd == -1, 30087599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 30172200Sbmilekic mtx_lock(&sc->mutex); 30266703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 303179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 304188077Sjhb slave | ICH_XMIT_SLVA_READ); 305179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 306179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 30766703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 30866703Sarchie if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 309179622Sjhb *byte = bus_read_1(sc->io_res, ICH_D0); 31072200Sbmilekic mtx_unlock(&sc->mutex); 31166703Sarchie DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 31266703Sarchie return (smb_error); 31366703Sarchie} 31466703Sarchie 31566703Sarchieint 31666703Sarchieichsmb_readw(device_t dev, u_char slave, char cmd, short *word) 31766703Sarchie{ 31866703Sarchie const sc_p sc = device_get_softc(dev); 31966703Sarchie int smb_error; 32066703Sarchie 32166703Sarchie DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 32266703Sarchie KASSERT(sc->ich_cmd == -1, 32387599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 32472200Sbmilekic mtx_lock(&sc->mutex); 32566703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 326179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 327188077Sjhb slave | ICH_XMIT_SLVA_READ); 328179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 329179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 33066703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 33166703Sarchie if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 332179622Sjhb *word = (bus_read_1(sc->io_res, 333179622Sjhb ICH_D0) & 0xff) 334179622Sjhb | (bus_read_1(sc->io_res, 335179622Sjhb ICH_D1) << 8); 33666703Sarchie } 33772200Sbmilekic mtx_unlock(&sc->mutex); 33866703Sarchie DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); 33966703Sarchie return (smb_error); 34066703Sarchie} 34166703Sarchie 34266703Sarchieint 34366703Sarchieichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 34466703Sarchie{ 34566703Sarchie const sc_p sc = device_get_softc(dev); 34666703Sarchie int smb_error; 34766703Sarchie 34866703Sarchie DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", 34966703Sarchie slave, (u_char)cmd, (u_int16_t)sdata); 35066703Sarchie KASSERT(sc->ich_cmd == -1, 35187599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 35272200Sbmilekic mtx_lock(&sc->mutex); 35366703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; 354179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 355188077Sjhb slave | ICH_XMIT_SLVA_WRITE); 356179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 357179622Sjhb bus_write_1(sc->io_res, ICH_D0, sdata & 0xff); 358179622Sjhb bus_write_1(sc->io_res, ICH_D1, sdata >> 8); 359179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 36066703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 36166703Sarchie if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 362179622Sjhb *rdata = (bus_read_1(sc->io_res, 363179622Sjhb ICH_D0) & 0xff) 364179622Sjhb | (bus_read_1(sc->io_res, 365179622Sjhb ICH_D1) << 8); 36666703Sarchie } 36772200Sbmilekic mtx_unlock(&sc->mutex); 36866703Sarchie DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); 36966703Sarchie return (smb_error); 37066703Sarchie} 37166703Sarchie 37266703Sarchieint 37366703Sarchieichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 37466703Sarchie{ 37566703Sarchie const sc_p sc = device_get_softc(dev); 37666703Sarchie int smb_error; 37766703Sarchie 37866703Sarchie DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 37966703Sarchie#if ICHSMB_DEBUG 38066703Sarchie#define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 38166703Sarchie { 38266703Sarchie u_char *p; 38366703Sarchie 38466703Sarchie for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 38566703Sarchie DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 38666703Sarchie " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 38766703Sarchie p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 38866703Sarchie DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 38966703Sarchie DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 39066703Sarchie } 39166703Sarchie } 39266703Sarchie#undef DISP 39366703Sarchie#endif 39466703Sarchie KASSERT(sc->ich_cmd == -1, 39587599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 39666703Sarchie if (count < 1 || count > 32) 397162234Sjhb return (SMB_EINVAL); 39866703Sarchie bcopy(buf, sc->block_data, count); 39966703Sarchie sc->block_count = count; 40066703Sarchie sc->block_index = 1; 40166703Sarchie sc->block_write = 1; 40266703Sarchie 40372200Sbmilekic mtx_lock(&sc->mutex); 40466703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 405179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 406188077Sjhb slave | ICH_XMIT_SLVA_WRITE); 407179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 408179622Sjhb bus_write_1(sc->io_res, ICH_D0, count); 409179622Sjhb bus_write_1(sc->io_res, ICH_BLOCK_DB, buf[0]); 410179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 41166703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 41266703Sarchie smb_error = ichsmb_wait(sc); 41372200Sbmilekic mtx_unlock(&sc->mutex); 41466703Sarchie DBG("smb_error=%d\n", smb_error); 41566703Sarchie return (smb_error); 41666703Sarchie} 41766703Sarchie 41866703Sarchieint 419162234Sjhbichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 42066703Sarchie{ 42166703Sarchie const sc_p sc = device_get_softc(dev); 42266703Sarchie int smb_error; 42366703Sarchie 42466703Sarchie DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 42566703Sarchie KASSERT(sc->ich_cmd == -1, 42687599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 427162234Sjhb if (*count < 1 || *count > 32) 428162234Sjhb return (SMB_EINVAL); 42966703Sarchie bzero(sc->block_data, sizeof(sc->block_data)); 430162234Sjhb sc->block_count = 0; 43166703Sarchie sc->block_index = 0; 43266703Sarchie sc->block_write = 0; 43366703Sarchie 43472200Sbmilekic mtx_lock(&sc->mutex); 43566703Sarchie sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 436179622Sjhb bus_write_1(sc->io_res, ICH_XMIT_SLVA, 437188077Sjhb slave | ICH_XMIT_SLVA_READ); 438179622Sjhb bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 439179622Sjhb bus_write_1(sc->io_res, ICH_D0, *count); /* XXX? */ 440179622Sjhb bus_write_1(sc->io_res, ICH_HST_CNT, 44166703Sarchie ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 442162234Sjhb if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 443162234Sjhb bcopy(sc->block_data, buf, min(sc->block_count, *count)); 444162234Sjhb *count = sc->block_count; 445162234Sjhb } 44672200Sbmilekic mtx_unlock(&sc->mutex); 44766703Sarchie DBG("smb_error=%d\n", smb_error); 44866703Sarchie#if ICHSMB_DEBUG 44966703Sarchie#define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 45066703Sarchie { 45166703Sarchie u_char *p; 45266703Sarchie 45366703Sarchie for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 45466703Sarchie DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 45566703Sarchie " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 45666703Sarchie p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 45766703Sarchie DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 45866703Sarchie DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 45966703Sarchie } 46066703Sarchie } 46166703Sarchie#undef DISP 46266703Sarchie#endif 46366703Sarchie return (smb_error); 46466703Sarchie} 46566703Sarchie 46666703Sarchie/******************************************************************** 46766703Sarchie OTHER FUNCTIONS 46866703Sarchie********************************************************************/ 46966703Sarchie 47066703Sarchie/* 47166703Sarchie * This table describes what interrupts we should ever expect to 47266703Sarchie * see after each ICH command, not including the SMBALERT interrupt. 47366703Sarchie */ 47466703Sarchiestatic const u_int8_t ichsmb_state_irqs[] = { 47566703Sarchie /* quick */ 47666703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 47766703Sarchie /* byte */ 47866703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 47966703Sarchie /* byte data */ 48066703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 48166703Sarchie /* word data */ 48266703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 48366703Sarchie /* process call */ 48466703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 48566703Sarchie /* block */ 48666703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 48766703Sarchie | ICH_HST_STA_BYTE_DONE_STS), 48866703Sarchie /* i2c read (not used) */ 48966703Sarchie (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 49066703Sarchie | ICH_HST_STA_BYTE_DONE_STS) 49166703Sarchie}; 49266703Sarchie 49366703Sarchie/* 49466703Sarchie * Interrupt handler. This handler is bus-independent. Note that our 49566703Sarchie * interrupt may be shared, so we must handle "false" interrupts. 49666703Sarchie */ 49766703Sarchievoid 49866703Sarchieichsmb_device_intr(void *cookie) 49966703Sarchie{ 50066703Sarchie const sc_p sc = cookie; 50166703Sarchie const device_t dev = sc->dev; 50266703Sarchie const int maxloops = 16; 50366703Sarchie u_int8_t status; 50466703Sarchie u_int8_t ok_bits; 50566703Sarchie int cmd_index; 50666703Sarchie int count; 50766703Sarchie 50872200Sbmilekic mtx_lock(&sc->mutex); 50966703Sarchie for (count = 0; count < maxloops; count++) { 51066703Sarchie 51166703Sarchie /* Get and reset status bits */ 512179622Sjhb status = bus_read_1(sc->io_res, ICH_HST_STA); 51366703Sarchie#if ICHSMB_DEBUG 51466703Sarchie if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) 51566703Sarchie || count > 0) { 51666703Sarchie DBG("%d stat=0x%02x\n", count, status); 51766703Sarchie } 51866703Sarchie#endif 51966703Sarchie status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); 52066703Sarchie if (status == 0) 52166703Sarchie break; 52266703Sarchie 52366703Sarchie /* Check for unexpected interrupt */ 52466703Sarchie ok_bits = ICH_HST_STA_SMBALERT_STS; 52566703Sarchie cmd_index = sc->ich_cmd >> 2; 52666703Sarchie if (sc->ich_cmd != -1) { 52766703Sarchie KASSERT(cmd_index < sizeof(ichsmb_state_irqs), 52866703Sarchie ("%s: ich_cmd=%d", device_get_nameunit(dev), 52966703Sarchie sc->ich_cmd)); 53066703Sarchie ok_bits |= ichsmb_state_irqs[cmd_index]; 53166703Sarchie } 53266703Sarchie if ((status & ~ok_bits) != 0) { 533165951Sjhb device_printf(dev, "irq 0x%02x during %d\n", status, 534165951Sjhb cmd_index); 535179622Sjhb bus_write_1(sc->io_res, 53666703Sarchie ICH_HST_STA, (status & ~ok_bits)); 53766703Sarchie continue; 53866703Sarchie } 53966703Sarchie 54066703Sarchie /* Handle SMBALERT interrupt */ 54166703Sarchie if (status & ICH_HST_STA_SMBALERT_STS) { 54266703Sarchie static int smbalert_count = 16; 54366703Sarchie if (smbalert_count > 0) { 544165951Sjhb device_printf(dev, "SMBALERT# rec'd\n"); 54566703Sarchie if (--smbalert_count == 0) { 546165951Sjhb device_printf(dev, 547165951Sjhb "not logging anymore\n"); 54866703Sarchie } 54966703Sarchie } 55066703Sarchie } 55166703Sarchie 55266703Sarchie /* Check for bus error */ 55366703Sarchie if (status & ICH_HST_STA_BUS_ERR) { 55466703Sarchie sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */ 55566703Sarchie goto finished; 55666703Sarchie } 55766703Sarchie 55866703Sarchie /* Check for device error */ 55966703Sarchie if (status & ICH_HST_STA_DEV_ERR) { 56066703Sarchie sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */ 56166703Sarchie goto finished; 56266703Sarchie } 56366703Sarchie 56466703Sarchie /* Check for byte completion in block transfer */ 56566703Sarchie if (status & ICH_HST_STA_BYTE_DONE_STS) { 56666703Sarchie if (sc->block_write) { 56766703Sarchie if (sc->block_index < sc->block_count) { 56866703Sarchie 56966703Sarchie /* Write next byte */ 570179622Sjhb bus_write_1(sc->io_res, 571179622Sjhb ICH_BLOCK_DB, 57266703Sarchie sc->block_data[sc->block_index++]); 57366703Sarchie } 57466703Sarchie } else { 57566703Sarchie 57666703Sarchie /* First interrupt, get the count also */ 57766703Sarchie if (sc->block_index == 0) { 578179622Sjhb sc->block_count = bus_read_1( 579179622Sjhb sc->io_res, ICH_D0); 58066703Sarchie } 58166703Sarchie 58266703Sarchie /* Get next byte, if any */ 58366703Sarchie if (sc->block_index < sc->block_count) { 58466703Sarchie 58566703Sarchie /* Read next byte */ 58666703Sarchie sc->block_data[sc->block_index++] = 587179622Sjhb bus_read_1(sc->io_res, 588179622Sjhb ICH_BLOCK_DB); 58966703Sarchie 59066703Sarchie /* Set "LAST_BYTE" bit before reading 59166703Sarchie the last byte of block data */ 59266703Sarchie if (sc->block_index 59366703Sarchie >= sc->block_count - 1) { 594179622Sjhb bus_write_1(sc->io_res, 595179622Sjhb ICH_HST_CNT, 59666703Sarchie ICH_HST_CNT_LAST_BYTE 59766703Sarchie | ICH_HST_CNT_INTREN 59866703Sarchie | sc->ich_cmd); 59966703Sarchie } 60066703Sarchie } 60166703Sarchie } 60266703Sarchie } 60366703Sarchie 60466703Sarchie /* Check command completion */ 60566703Sarchie if (status & ICH_HST_STA_INTR) { 60666703Sarchie sc->smb_error = SMB_ENOERR; 60766703Sarchiefinished: 60866703Sarchie sc->ich_cmd = -1; 609179622Sjhb bus_write_1(sc->io_res, 61066703Sarchie ICH_HST_STA, status); 61166703Sarchie wakeup(sc); 61266703Sarchie break; 61366703Sarchie } 61466703Sarchie 61566703Sarchie /* Clear status bits and try again */ 616179622Sjhb bus_write_1(sc->io_res, ICH_HST_STA, status); 61766703Sarchie } 61872200Sbmilekic mtx_unlock(&sc->mutex); 61966703Sarchie 62066703Sarchie /* Too many loops? */ 62166703Sarchie if (count == maxloops) { 622165951Sjhb device_printf(dev, "interrupt loop, status=0x%02x\n", 623179622Sjhb bus_read_1(sc->io_res, ICH_HST_STA)); 62466703Sarchie } 62566703Sarchie} 62666703Sarchie 62766703Sarchie/* 62869689Sarchie * Wait for command completion. Assumes mutex is held. 62966703Sarchie * Returns an SMB_* error code. 63066703Sarchie */ 63166703Sarchiestatic int 63266703Sarchieichsmb_wait(sc_p sc) 63366703Sarchie{ 63466703Sarchie const device_t dev = sc->dev; 63566703Sarchie int error, smb_error; 63666703Sarchie 63766703Sarchie KASSERT(sc->ich_cmd != -1, 63887599Sobrien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 63969689Sarchie mtx_assert(&sc->mutex, MA_OWNED); 640153993Sbrian error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4); 64169689Sarchie DBG("msleep -> %d\n", error); 64266703Sarchie switch (error) { 64366703Sarchie case 0: 64466703Sarchie smb_error = sc->smb_error; 64566703Sarchie break; 64666703Sarchie case EWOULDBLOCK: 647165951Sjhb device_printf(dev, "device timeout, status=0x%02x\n", 648179622Sjhb bus_read_1(sc->io_res, ICH_HST_STA)); 64966703Sarchie sc->ich_cmd = -1; 65066703Sarchie smb_error = SMB_ETIMEOUT; 65166703Sarchie break; 65266703Sarchie default: 65366703Sarchie smb_error = SMB_EABORT; 65466703Sarchie break; 65566703Sarchie } 65666703Sarchie return (smb_error); 65766703Sarchie} 65866703Sarchie 65966703Sarchie/* 66066703Sarchie * Release resources associated with device. 66166703Sarchie */ 66266703Sarchievoid 66366703Sarchieichsmb_release_resources(sc_p sc) 66466703Sarchie{ 66566703Sarchie const device_t dev = sc->dev; 66666703Sarchie 66766703Sarchie if (sc->irq_handle != NULL) { 66866703Sarchie bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 66966703Sarchie sc->irq_handle = NULL; 67066703Sarchie } 67166703Sarchie if (sc->irq_res != NULL) { 67266703Sarchie bus_release_resource(dev, 67366703Sarchie SYS_RES_IRQ, sc->irq_rid, sc->irq_res); 67466703Sarchie sc->irq_res = NULL; 67566703Sarchie } 67666703Sarchie if (sc->io_res != NULL) { 67766703Sarchie bus_release_resource(dev, 67866703Sarchie SYS_RES_IOPORT, sc->io_rid, sc->io_res); 67966703Sarchie sc->io_res = NULL; 68066703Sarchie } 68166703Sarchie} 68266703Sarchie 683162234Sjhbint 684162234Sjhbichsmb_detach(device_t dev) 685147253Stakawata{ 686147253Stakawata const sc_p sc = device_get_softc(dev); 687162234Sjhb int error; 688148497Sbrian 689162234Sjhb error = bus_generic_detach(dev); 690162234Sjhb if (error) 691162234Sjhb return (error); 692147253Stakawata device_delete_child(dev, sc->smb); 693147253Stakawata ichsmb_release_resources(sc); 694162234Sjhb mtx_destroy(&sc->mutex); 695147253Stakawata 696147253Stakawata return 0; 697147253Stakawata} 698162234Sjhb 699162234SjhbDRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, 0, 0); 700