alpm.c revision 70606
143973Snsouch/*- 270606Snsouch * Copyright (c) 1998, 1999, 2001 Nicolas Souchu 343973Snsouch * All rights reserved. 443973Snsouch * 543973Snsouch * Redistribution and use in source and binary forms, with or without 643973Snsouch * modification, are permitted provided that the following conditions 743973Snsouch * are met: 843973Snsouch * 1. Redistributions of source code must retain the above copyright 943973Snsouch * notice, this list of conditions and the following disclaimer. 1043973Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1143973Snsouch * notice, this list of conditions and the following disclaimer in the 1243973Snsouch * documentation and/or other materials provided with the distribution. 1343973Snsouch * 1443973Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1543973Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1643973Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1743973Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1843973Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1943973Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2043973Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2143973Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2243973Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2343973Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2443973Snsouch * SUCH DAMAGE. 2543973Snsouch * 2650477Speter * $FreeBSD: head/sys/pci/alpm.c 70606 2001-01-02 21:19:32Z nsouch $ 2743973Snsouch * 2843973Snsouch */ 2943973Snsouch 3043973Snsouch/* 3143973Snsouch * Power Management support for the Acer M15x3 chipsets 3243973Snsouch */ 3343973Snsouch#include <sys/param.h> 3443973Snsouch#include <sys/kernel.h> 3543973Snsouch#include <sys/systm.h> 3643973Snsouch#include <sys/module.h> 3743973Snsouch#include <sys/bus.h> 3843973Snsouch#include <sys/uio.h> 3943973Snsouch 4043973Snsouch 4143973Snsouch#include <machine/bus_pio.h> 4243973Snsouch#include <machine/bus_memio.h> 4343973Snsouch#include <machine/bus.h> 4470606Snsouch#include <machine/resource.h> 4570606Snsouch#include <sys/rman.h> 4643973Snsouch 4743973Snsouch#include <pci/pcivar.h> 4843973Snsouch#include <pci/pcireg.h> 4943973Snsouch 5043973Snsouch#include <dev/iicbus/iiconf.h> 5143973Snsouch#include <dev/smbus/smbconf.h> 5243973Snsouch#include "smbus_if.h" 5343973Snsouch 5443973Snsouch#include "alpm.h" 5543973Snsouch 5643973Snsouch#define ALPM_DEBUG(x) if (alpm_debug) (x) 5743973Snsouch 5843973Snsouch#ifdef DEBUG 5943973Snsouchstatic int alpm_debug = 1; 6043973Snsouch#else 6143973Snsouchstatic int alpm_debug = 0; 6243973Snsouch#endif 6343973Snsouch 6443973Snsouch#define ACER_M1543_PMU_ID 0x710110b9 6543973Snsouch 6643973Snsouch/* Uncomment this line to force another I/O base address for SMB */ 6743973Snsouch/* #define ALPM_SMBIO_BASE_ADDR 0x3a80 */ 6843973Snsouch 6943973Snsouch/* I/O registers offsets - the base address is programmed via the 7043973Snsouch * SMBBA PCI configuration register 7143973Snsouch */ 7243973Snsouch#define SMBSTS 0x0 /* SMBus host/slave status register */ 7343973Snsouch#define SMBCMD 0x1 /* SMBus host/slave command register */ 7443973Snsouch#define SMBSTART 0x2 /* start to generate programmed cycle */ 7543973Snsouch#define SMBHADDR 0x3 /* host address register */ 7643973Snsouch#define SMBHDATA 0x4 /* data A register for host controller */ 7743973Snsouch#define SMBHDATB 0x5 /* data B register for host controller */ 7843973Snsouch#define SMBHBLOCK 0x6 /* block register for host controller */ 7943973Snsouch#define SMBHCMD 0x7 /* command register for host controller */ 8043973Snsouch 8143973Snsouch/* SMBSTS masks */ 8243973Snsouch#define TERMINATE 0x80 8343973Snsouch#define BUS_COLLI 0x40 8443973Snsouch#define DEVICE_ERR 0x20 8543973Snsouch#define SMI_I_STS 0x10 8643973Snsouch#define HST_BSY 0x08 8743973Snsouch#define IDL_STS 0x04 8843973Snsouch#define HSTSLV_STS 0x02 8943973Snsouch#define HSTSLV_BSY 0x01 9043973Snsouch 9143973Snsouch/* SMBCMD masks */ 9243973Snsouch#define SMB_BLK_CLR 0x80 9343973Snsouch#define T_OUT_CMD 0x08 9443973Snsouch#define ABORT_HOST 0x04 9543973Snsouch 9643973Snsouch/* SMBus commands */ 9743973Snsouch#define SMBQUICK 0x00 9843973Snsouch#define SMBSRBYTE 0x10 /* send/receive byte */ 9943973Snsouch#define SMBWRBYTE 0x20 /* write/read byte */ 10043973Snsouch#define SMBWRWORD 0x30 /* write/read word */ 10143973Snsouch#define SMBWRBLOCK 0x40 /* write/read block */ 10243973Snsouch 10343973Snsouch/* PCI configuration registers and masks 10443973Snsouch */ 10543973Snsouch#define COM 0x4 10643973Snsouch#define COM_ENABLE_IO 0x1 10743973Snsouch 10843973Snsouch#define SMBBA 0x14 10943973Snsouch 11043973Snsouch#define ATPC 0x5b 11170606Snsouch#define ATPC_SMBCTRL 0x04 /* XX linux has this as 0x6 */ 11243973Snsouch 11343973Snsouch#define SMBHSI 0xe0 11443973Snsouch#define SMBHSI_SLAVE 0x2 11543973Snsouch#define SMBHSI_HOST 0x1 11643973Snsouch 11743973Snsouch#define SMBHCBC 0xe2 11843973Snsouch#define SMBHCBC_CLOCK 0x70 11943973Snsouch 12043973Snsouch#define SMBCLOCK_149K 0x0 12143973Snsouch#define SMBCLOCK_74K 0x20 12243973Snsouch#define SMBCLOCK_37K 0x40 12343973Snsouch#define SMBCLOCK_223K 0x80 12443973Snsouch#define SMBCLOCK_111K 0xa0 12543973Snsouch#define SMBCLOCK_55K 0xc0 12643973Snsouch 12743973Snsouchstruct alpm_data { 12843973Snsouch int base; 12943973Snsouch bus_space_tag_t smbst; 13043973Snsouch bus_space_handle_t smbsh; 13143973Snsouch}; 13243973Snsouch 13343973Snsouchstruct alsmb_softc { 13443973Snsouch int base; 13543973Snsouch device_t smbus; 13643973Snsouch struct alpm_data *alpm; 13743973Snsouch}; 13843973Snsouch 13943973Snsouch#define ALPM_SMBINB(alsmb,register) \ 14043973Snsouch (bus_space_read_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register)) 14143973Snsouch#define ALPM_SMBOUTB(alsmb,register,value) \ 14243973Snsouch (bus_space_write_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register, value)) 14343973Snsouch 14443973Snsouchstatic int alsmb_probe(device_t); 14543973Snsouchstatic int alsmb_attach(device_t); 14643973Snsouchstatic int alsmb_smb_callback(device_t, int, caddr_t *); 14743973Snsouchstatic int alsmb_smb_quick(device_t dev, u_char slave, int how); 14843973Snsouchstatic int alsmb_smb_sendb(device_t dev, u_char slave, char byte); 14943973Snsouchstatic int alsmb_smb_recvb(device_t dev, u_char slave, char *byte); 15043973Snsouchstatic int alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte); 15143973Snsouchstatic int alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte); 15243973Snsouchstatic int alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word); 15343973Snsouchstatic int alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word); 15443973Snsouchstatic int alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 15543973Snsouchstatic int alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte); 15643973Snsouch 15743973Snsouchstatic devclass_t alsmb_devclass; 15843973Snsouch 15943973Snsouchstatic device_method_t alsmb_methods[] = { 16043973Snsouch /* device interface */ 16143973Snsouch DEVMETHOD(device_probe, alsmb_probe), 16243973Snsouch DEVMETHOD(device_attach, alsmb_attach), 16343973Snsouch 16443973Snsouch /* bus interface */ 16549195Smdodd DEVMETHOD(bus_print_child, bus_generic_print_child), 16643973Snsouch 16743973Snsouch /* smbus interface */ 16843973Snsouch DEVMETHOD(smbus_callback, alsmb_smb_callback), 16943973Snsouch DEVMETHOD(smbus_quick, alsmb_smb_quick), 17043973Snsouch DEVMETHOD(smbus_sendb, alsmb_smb_sendb), 17143973Snsouch DEVMETHOD(smbus_recvb, alsmb_smb_recvb), 17243973Snsouch DEVMETHOD(smbus_writeb, alsmb_smb_writeb), 17343973Snsouch DEVMETHOD(smbus_readb, alsmb_smb_readb), 17443973Snsouch DEVMETHOD(smbus_writew, alsmb_smb_writew), 17543973Snsouch DEVMETHOD(smbus_readw, alsmb_smb_readw), 17643973Snsouch DEVMETHOD(smbus_bwrite, alsmb_smb_bwrite), 17743973Snsouch DEVMETHOD(smbus_bread, alsmb_smb_bread), 17843973Snsouch 17943973Snsouch { 0, 0 } 18043973Snsouch}; 18143973Snsouch 18243973Snsouchstatic driver_t alsmb_driver = { 18343973Snsouch "alsmb", 18443973Snsouch alsmb_methods, 18543973Snsouch sizeof(struct alsmb_softc), 18643973Snsouch}; 18743973Snsouch 18870606Snsouchstatic int alpm_pci_probe(device_t dev); 18970606Snsouchstatic int alpm_pci_attach(device_t dev); 19043973Snsouch 19170606Snsouchstatic devclass_t alpm_devclass; 19243973Snsouch 19370606Snsouchstatic device_method_t alpm_pci_methods[] = { 19470606Snsouch /* device interface */ 19570606Snsouch DEVMETHOD(device_probe, alpm_pci_probe), 19670606Snsouch DEVMETHOD(device_attach, alpm_pci_attach), 19770606Snsouch 19870606Snsouch { 0, 0 } 19970606Snsouch}; 20070606Snsouch 20170606Snsouchstatic driver_t alpm_pci_driver = { 20243973Snsouch "alpm", 20370606Snsouch alpm_pci_methods, 20470606Snsouch sizeof(struct alpm_data) 20543973Snsouch}; 20643973Snsouch 20743973Snsouch 20870606Snsouchstatic int 20970606Snsouchalpm_pci_probe(device_t dev) 21043973Snsouch{ 21170606Snsouch if (pci_get_devid(dev) == ACER_M1543_PMU_ID) { 21270606Snsouch device_set_desc(dev, 21370606Snsouch "AcerLabs M15x3 Power Management Unit"); 21470606Snsouch return 0; 21570606Snsouch } else { 21670606Snsouch return ENXIO; 21770606Snsouch } 21843973Snsouch} 21943973Snsouch 22070606Snsouchstatic int 22170606Snsouchalpm_pci_attach(device_t dev) 22243973Snsouch{ 22370606Snsouch int rid, unit; 22470606Snsouch u_int32_t l; 22543973Snsouch struct alpm_data *alpm; 22670606Snsouch struct resource *res; 22770606Snsouch device_t smbinterface; 22843973Snsouch 22970606Snsouch alpm = device_get_softc(dev); 23070606Snsouch unit = device_get_unit(dev); 23143973Snsouch 23243973Snsouch /* Unlock SMBIO base register access */ 23370606Snsouch l = pci_read_config(dev, ATPC, 1); 23470606Snsouch pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1); 23543973Snsouch 23670606Snsouch /* 23770606Snsouch * XX linux sets clock to 74k, should we? 23870606Snsouch l = pci_read_config(dev, SMBHCBC, 1); 23970606Snsouch l &= 0x1f; 24070606Snsouch l |= SMBCLOCK_74K; 24170606Snsouch pci_write_config(dev, SMBHCBC, l, 1); 24270606Snsouch */ 24370606Snsouch 24443973Snsouch if (bootverbose) { 24570606Snsouch l = pci_read_config(dev, SMBHSI, 1); 24643973Snsouch printf("alsmb%d: %s/%s", unit, 24743973Snsouch (l & SMBHSI_HOST) ? "host":"nohost", 24843973Snsouch (l & SMBHSI_SLAVE) ? "slave":"noslave"); 24943973Snsouch 25070606Snsouch l = pci_read_config(dev, SMBHCBC, 1); 25143973Snsouch switch (l & SMBHCBC_CLOCK) { 25243973Snsouch case SMBCLOCK_149K: 25343973Snsouch printf(" 149K"); 25443973Snsouch break; 25543973Snsouch case SMBCLOCK_74K: 25643973Snsouch printf(" 74K"); 25743973Snsouch break; 25843973Snsouch case SMBCLOCK_37K: 25943973Snsouch printf(" 37K"); 26043973Snsouch break; 26143973Snsouch case SMBCLOCK_223K: 26243973Snsouch printf(" 223K"); 26343973Snsouch break; 26443973Snsouch case SMBCLOCK_111K: 26543973Snsouch printf(" 111K"); 26643973Snsouch break; 26743973Snsouch case SMBCLOCK_55K: 26843973Snsouch printf(" 55K"); 26943973Snsouch break; 27043973Snsouch } 27143973Snsouch } 27243973Snsouch 27343973Snsouch#ifdef ALPM_SMBIO_BASE_ADDR 27470606Snsouch /* XX will this even work anymore? */ 27543973Snsouch /* disable I/O */ 27670606Snsouch l = pci_read_config(dev, COM, 2); 27770606Snsouch pci_write_config(dev, COM, l & ~COM_ENABLE_IO, 2); 27843973Snsouch 27943973Snsouch /* set the I/O base address */ 28070606Snsouch pci_write_config(dev, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); 28143973Snsouch 28243973Snsouch /* enable I/O */ 28370606Snsouch pci_write_config(dev, COM, l | COM_ENABLE_IO, 2); 28443973Snsouch 28543973Snsouch#endif 28670606Snsouch rid = SMBBA; 28770606Snsouch res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 28870606Snsouch 0,~0,1,RF_ACTIVE); 28970606Snsouch if (res == NULL) { 29070606Snsouch device_printf(dev,"Could not allocate Bus space\n"); 29170606Snsouch return ENXIO; 29270606Snsouch } 29370606Snsouch alpm->smbst = rman_get_bustag(res); 29470606Snsouch alpm->smbsh = rman_get_bushandle(res); 29570606Snsouch 29643973Snsouch if (bootverbose) 29743973Snsouch printf(" at 0x%x\n", alpm->smbsh); 29870606Snsouch 29970606Snsouch smbinterface = device_add_child(dev, "alsmb", unit); 30070606Snsouch if (!smbinterface) 30170606Snsouch device_printf(dev, "could not add SMBus device\n"); 30270606Snsouch else 30370606Snsouch device_probe_and_attach(smbinterface); 30470606Snsouch return 0; 30543973Snsouch} 30643973Snsouch 30743973Snsouch/* 30843973Snsouch * Not a real probe, we know the device exists since the device has 30943973Snsouch * been added after the successfull pci probe. 31043973Snsouch */ 31143973Snsouchstatic int 31243973Snsouchalsmb_probe(device_t dev) 31343973Snsouch{ 31443973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 31543973Snsouch 31670606Snsouch /* allocate a new smbus device */ 31770606Snsouch sc->smbus = smbus_alloc_bus(dev); 31870606Snsouch if (!sc->smbus) 31970606Snsouch return (EINVAL); 32043973Snsouch device_set_desc(dev, "Aladdin IV/V/Pro2 SMBus controller"); 32143973Snsouch 32243973Snsouch return (0); 32343973Snsouch} 32443973Snsouch 32543973Snsouchstatic int 32643973Snsouchalsmb_attach(device_t dev) 32743973Snsouch{ 32843973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 32943973Snsouch 33070606Snsouch sc->alpm = device_get_softc(device_get_parent(dev)); 33143973Snsouch 33243973Snsouch /* probe and attach the smbus */ 33343973Snsouch device_probe_and_attach(sc->smbus); 33443973Snsouch 33543973Snsouch return (0); 33643973Snsouch} 33743973Snsouch 33843973Snsouchstatic int 33943973Snsouchalsmb_smb_callback(device_t dev, int index, caddr_t *data) 34043973Snsouch{ 34143973Snsouch int error = 0; 34243973Snsouch 34343973Snsouch switch (index) { 34443973Snsouch case SMB_REQUEST_BUS: 34543973Snsouch case SMB_RELEASE_BUS: 34643973Snsouch /* ok, bus allocation accepted */ 34743973Snsouch break; 34843973Snsouch default: 34943973Snsouch error = EINVAL; 35043973Snsouch } 35143973Snsouch 35243973Snsouch return (error); 35343973Snsouch} 35443973Snsouch 35543973Snsouchstatic int 35643973Snsouchalsmb_clear(struct alsmb_softc *sc) 35743973Snsouch{ 35843973Snsouch ALPM_SMBOUTB(sc, SMBSTS, 0xff); 35943973Snsouch DELAY(10); 36043973Snsouch 36143973Snsouch return (0); 36243973Snsouch} 36343973Snsouch 36443973Snsouch#if 0 36543973Snsouchstatic int 36643973Snsouchalsmb_abort(struct alsmb_softc *sc) 36743973Snsouch{ 36843973Snsouch ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); 36943973Snsouch 37043973Snsouch return (0); 37143973Snsouch} 37243973Snsouch#endif 37343973Snsouch 37443973Snsouchstatic int 37543973Snsouchalsmb_idle(struct alsmb_softc *sc) 37643973Snsouch{ 37743973Snsouch u_char sts; 37843973Snsouch 37943973Snsouch sts = ALPM_SMBINB(sc, SMBSTS); 38043973Snsouch 38143973Snsouch ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts)); 38243973Snsouch 38343973Snsouch return (sts & IDL_STS); 38443973Snsouch} 38543973Snsouch 38643973Snsouch/* 38743973Snsouch * Poll the SMBus controller 38843973Snsouch */ 38943973Snsouchstatic int 39043973Snsouchalsmb_wait(struct alsmb_softc *sc) 39143973Snsouch{ 39243973Snsouch int count = 10000; 39370606Snsouch u_char sts = 0; 39443973Snsouch int error; 39543973Snsouch 39643973Snsouch /* wait for command to complete and SMBus controller is idle */ 39743973Snsouch while(count--) { 39843973Snsouch DELAY(10); 39943973Snsouch sts = ALPM_SMBINB(sc, SMBSTS); 40043973Snsouch if (sts & SMI_I_STS) 40143973Snsouch break; 40243973Snsouch } 40343973Snsouch 40443973Snsouch ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); 40543973Snsouch 40643973Snsouch error = SMB_ENOERR; 40743973Snsouch 40843973Snsouch if (!count) 40943973Snsouch error |= SMB_ETIMEOUT; 41043973Snsouch 41143973Snsouch if (sts & TERMINATE) 41243973Snsouch error |= SMB_EABORT; 41343973Snsouch 41443973Snsouch if (sts & BUS_COLLI) 41543973Snsouch error |= SMB_ENOACK; 41643973Snsouch 41743973Snsouch if (sts & DEVICE_ERR) 41843973Snsouch error |= SMB_EBUSERR; 41943973Snsouch 42043973Snsouch if (error != SMB_ENOERR) 42143973Snsouch alsmb_clear(sc); 42243973Snsouch 42343973Snsouch return (error); 42443973Snsouch} 42543973Snsouch 42643973Snsouchstatic int 42743973Snsouchalsmb_smb_quick(device_t dev, u_char slave, int how) 42843973Snsouch{ 42943973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 43043973Snsouch int error; 43143973Snsouch 43243973Snsouch alsmb_clear(sc); 43343973Snsouch if (!alsmb_idle(sc)) 43443973Snsouch return (EBUSY); 43543973Snsouch 43643973Snsouch switch (how) { 43743973Snsouch case SMB_QWRITE: 43843973Snsouch ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave)); 43943973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 44043973Snsouch break; 44143973Snsouch case SMB_QREAD: 44243973Snsouch ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave)); 44343973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 44443973Snsouch break; 44543973Snsouch default: 44643973Snsouch panic("%s: unknown QUICK command (%x)!", __FUNCTION__, 44743973Snsouch how); 44843973Snsouch } 44943973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); 45043973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 45143973Snsouch 45243973Snsouch error = alsmb_wait(sc); 45343973Snsouch 45443973Snsouch ALPM_DEBUG(printf(", error=0x%x\n", error)); 45543973Snsouch 45643973Snsouch return (error); 45743973Snsouch} 45843973Snsouch 45943973Snsouchstatic int 46043973Snsouchalsmb_smb_sendb(device_t dev, u_char slave, char byte) 46143973Snsouch{ 46243973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 46343973Snsouch int error; 46443973Snsouch 46543973Snsouch alsmb_clear(sc); 46643973Snsouch if (!alsmb_idle(sc)) 46743973Snsouch return (SMB_EBUSY); 46843973Snsouch 46943973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 47043973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 47143973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, byte); 47243973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 47343973Snsouch 47443973Snsouch error = alsmb_wait(sc); 47543973Snsouch 47643973Snsouch ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 47743973Snsouch 47843973Snsouch return (error); 47943973Snsouch} 48043973Snsouch 48143973Snsouchstatic int 48243973Snsouchalsmb_smb_recvb(device_t dev, u_char slave, char *byte) 48343973Snsouch{ 48443973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 48543973Snsouch int error; 48643973Snsouch 48743973Snsouch alsmb_clear(sc); 48843973Snsouch if (!alsmb_idle(sc)) 48943973Snsouch return (SMB_EBUSY); 49043973Snsouch 49143973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 49243973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 49343973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 49443973Snsouch 49543973Snsouch if ((error = alsmb_wait(sc)) == SMB_ENOERR) 49643973Snsouch *byte = ALPM_SMBINB(sc, SMBHDATA); 49743973Snsouch 49843973Snsouch ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 49943973Snsouch 50043973Snsouch return (error); 50143973Snsouch} 50243973Snsouch 50343973Snsouchstatic int 50443973Snsouchalsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) 50543973Snsouch{ 50643973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 50743973Snsouch int error; 50843973Snsouch 50943973Snsouch alsmb_clear(sc); 51043973Snsouch if (!alsmb_idle(sc)) 51143973Snsouch return (SMB_EBUSY); 51243973Snsouch 51343973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 51443973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 51543973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, byte); 51643973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 51743973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 51843973Snsouch 51943973Snsouch error = alsmb_wait(sc); 52043973Snsouch 52143973Snsouch ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 52243973Snsouch 52343973Snsouch return (error); 52443973Snsouch} 52543973Snsouch 52643973Snsouchstatic int 52743973Snsouchalsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) 52843973Snsouch{ 52943973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 53043973Snsouch int error; 53143973Snsouch 53243973Snsouch alsmb_clear(sc); 53343973Snsouch if (!alsmb_idle(sc)) 53443973Snsouch return (SMB_EBUSY); 53543973Snsouch 53643973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 53743973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 53843973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 53943973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 54043973Snsouch 54143973Snsouch if ((error = alsmb_wait(sc)) == SMB_ENOERR) 54243973Snsouch *byte = ALPM_SMBINB(sc, SMBHDATA); 54343973Snsouch 54443973Snsouch ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 54543973Snsouch 54643973Snsouch return (error); 54743973Snsouch} 54843973Snsouch 54943973Snsouchstatic int 55043973Snsouchalsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) 55143973Snsouch{ 55243973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 55343973Snsouch int error; 55443973Snsouch 55543973Snsouch alsmb_clear(sc); 55643973Snsouch if (!alsmb_idle(sc)) 55743973Snsouch return (SMB_EBUSY); 55843973Snsouch 55943973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 56043973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 56143973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); 56243973Snsouch ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); 56343973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 56443973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 56543973Snsouch 56643973Snsouch error = alsmb_wait(sc); 56743973Snsouch 56843973Snsouch ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 56943973Snsouch 57043973Snsouch return (error); 57143973Snsouch} 57243973Snsouch 57343973Snsouchstatic int 57443973Snsouchalsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) 57543973Snsouch{ 57643973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 57743973Snsouch int error; 57843973Snsouch u_char high, low; 57943973Snsouch 58043973Snsouch alsmb_clear(sc); 58143973Snsouch if (!alsmb_idle(sc)) 58243973Snsouch return (SMB_EBUSY); 58343973Snsouch 58443973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 58543973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 58643973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 58743973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 58843973Snsouch 58943973Snsouch if ((error = alsmb_wait(sc)) == SMB_ENOERR) { 59043973Snsouch low = ALPM_SMBINB(sc, SMBHDATA); 59143973Snsouch high = ALPM_SMBINB(sc, SMBHDATB); 59243973Snsouch 59343973Snsouch *word = ((high & 0xff) << 8) | (low & 0xff); 59443973Snsouch } 59543973Snsouch 59643973Snsouch ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 59743973Snsouch 59843973Snsouch return (error); 59943973Snsouch} 60043973Snsouch 60143973Snsouchstatic int 60243973Snsouchalsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 60343973Snsouch{ 60443973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 60543973Snsouch u_char remain, len, i; 60643973Snsouch int error = SMB_ENOERR; 60743973Snsouch 60843973Snsouch alsmb_clear(sc); 60943973Snsouch if(!alsmb_idle(sc)) 61043973Snsouch return (SMB_EBUSY); 61143973Snsouch 61243973Snsouch remain = count; 61343973Snsouch while (remain) { 61443973Snsouch len = min(remain, 32); 61543973Snsouch 61643973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 61743973Snsouch 61843973Snsouch /* set the cmd and reset the 61943973Snsouch * 32-byte long internal buffer */ 62043973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 62143973Snsouch 62243973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, len); 62343973Snsouch 62443973Snsouch /* fill the 32-byte internal buffer */ 62543973Snsouch for (i=0; i<len; i++) { 62643973Snsouch ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]); 62743973Snsouch DELAY(2); 62843973Snsouch } 62943973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 63043973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 63143973Snsouch 63243973Snsouch if ((error = alsmb_wait(sc)) != SMB_ENOERR) 63343973Snsouch goto error; 63443973Snsouch 63543973Snsouch remain -= len; 63643973Snsouch } 63743973Snsouch 63843973Snsoucherror: 63943973Snsouch ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 64043973Snsouch 64143973Snsouch return (error); 64243973Snsouch} 64343973Snsouch 64443973Snsouchstatic int 64543973Snsouchalsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 64643973Snsouch{ 64743973Snsouch struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 64843973Snsouch u_char remain, len, i; 64943973Snsouch int error = SMB_ENOERR; 65043973Snsouch 65143973Snsouch alsmb_clear(sc); 65243973Snsouch if (!alsmb_idle(sc)) 65343973Snsouch return (SMB_EBUSY); 65443973Snsouch 65543973Snsouch remain = count; 65643973Snsouch while (remain) { 65743973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 65843973Snsouch 65943973Snsouch /* set the cmd and reset the 66043973Snsouch * 32-byte long internal buffer */ 66143973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 66243973Snsouch 66343973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 66443973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 66543973Snsouch 66643973Snsouch if ((error = alsmb_wait(sc)) != SMB_ENOERR) 66743973Snsouch goto error; 66843973Snsouch 66943973Snsouch len = ALPM_SMBINB(sc, SMBHDATA); 67043973Snsouch 67143973Snsouch /* read the 32-byte internal buffer */ 67243973Snsouch for (i=0; i<len; i++) { 67343973Snsouch buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK); 67443973Snsouch DELAY(2); 67543973Snsouch } 67643973Snsouch 67743973Snsouch remain -= len; 67843973Snsouch } 67943973Snsoucherror: 68043973Snsouch ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 68143973Snsouch 68243973Snsouch return (error); 68343973Snsouch} 68443973Snsouch 68570606SnsouchDRIVER_MODULE(alpm, pci, alpm_pci_driver, alpm_devclass, 0, 0); 68670606SnsouchDRIVER_MODULE(alsmb, alpm, alsmb_driver, alsmb_devclass, 0, 0); 687