intpm.c revision 49064
143166Snsouch/*- 243166Snsouch * Copyright (c) 1998, 1999 Takanori Watanabe 343166Snsouch * All rights reserved. 443166Snsouch * 543166Snsouch * Redistribution and use in source and binary forms, with or without 643166Snsouch * modification, are permitted provided that the following conditions 743166Snsouch * are met: 843166Snsouch * 1. Redistributions of source code must retain the above copyright 943166Snsouch * notice, this list of conditions and the following disclaimer. 1043166Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1143166Snsouch * notice, this list of conditions and the following disclaimer in the 1243166Snsouch * documentation and/or other materials provided with the distribution. 1343166Snsouch * 1443166Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1543166Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1643166Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1743166Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1843166Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1943166Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2043166Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2143166Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2243166Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2343166Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2443166Snsouch * SUCH DAMAGE. 2543166Snsouch * 2649064Snsouch * $Id: intpm.c,v 1.11 1999/07/03 20:17:06 peter Exp $ 2743166Snsouch */ 2843166Snsouch 2943166Snsouch#include <sys/param.h> 3043166Snsouch#include <sys/systm.h> 3143166Snsouch#include <sys/kernel.h> 3243166Snsouch#include <machine/bus_pio.h> 3343166Snsouch#include <machine/bus_memio.h> 3443166Snsouch#include <machine/bus.h> 3543166Snsouch 3643166Snsouch#include <machine/clock.h> 3743166Snsouch#include <sys/uio.h> 3843166Snsouch#include <sys/module.h> 3943166Snsouch#include <sys/bus.h> 4043166Snsouch#include <sys/conf.h> 4143166Snsouch#include <sys/malloc.h> 4243166Snsouch#include <sys/buf.h> 4346651Speter#include <sys/rman.h> 4446651Speter#include <machine/resource.h> 4543166Snsouch#include <dev/smbus/smbconf.h> 4643166Snsouch 4743166Snsouch#include "smbus_if.h" 4843166Snsouch 4943166Snsouch/*This should be removed if force_pci_map_int supported*/ 5043166Snsouch#include <sys/interrupt.h> 5143166Snsouch 5243166Snsouch#include <pci/pcireg.h> 5343166Snsouch#include <pci/pcivar.h> 5443166Snsouch#include <pci/intpmreg.h> 5543166Snsouch 5643166Snsouch#include "opt_intpm.h" 5743166Snsouch 5843166Snsouchstatic struct _pcsid 5943166Snsouch{ 6043166Snsouch pcidi_t type; 6143166Snsouch char *desc; 6243166Snsouch} pci_ids[] = 6343166Snsouch{ 6443166Snsouch { 0x71138086,"Intel 82371AB Power management controller"}, 6543166Snsouch 6643166Snsouch { 0x00000000, NULL } 6743166Snsouch}; 6843166Snsouchstatic int intsmb_probe(device_t); 6943166Snsouchstatic int intsmb_attach(device_t); 7043166Snsouchstatic void intsmb_print_child(device_t, device_t); 7143166Snsouch 7243166Snsouchstatic int intsmb_intr(device_t dev); 7343166Snsouchstatic int intsmb_slvintr(device_t dev); 7443166Snsouchstatic void intsmb_alrintr(device_t dev); 7543166Snsouchstatic int intsmb_callback(device_t dev, int index, caddr_t data); 7643166Snsouchstatic int intsmb_quick(device_t dev, u_char slave, int how); 7743166Snsouchstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 7843166Snsouchstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 7943166Snsouchstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 8043166Snsouchstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 8143166Snsouchstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 8243166Snsouchstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 8343166Snsouchstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 8443166Snsouchstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8543166Snsouchstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8643166Snsouchstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 8743166Snsouchstatic int intsmb_stop(device_t dev); 8843166Snsouchstatic int intsmb_stop_poll(device_t dev); 8943166Snsouchstatic int intsmb_free(device_t dev); 9046651Speterstatic int intpm_probe (device_t dev); 9146651Speterstatic int intpm_attach (device_t dev); 9243166Snsouchstatic devclass_t intsmb_devclass; 9343166Snsouch 9443166Snsouchstatic device_method_t intpm_methods[]={ 9543166Snsouch DEVMETHOD(device_probe,intsmb_probe), 9643166Snsouch DEVMETHOD(device_attach,intsmb_attach), 9743166Snsouch 9843166Snsouch DEVMETHOD(bus_print_child, intsmb_print_child), 9943166Snsouch 10043166Snsouch DEVMETHOD(smbus_callback,intsmb_callback), 10143166Snsouch DEVMETHOD(smbus_quick,intsmb_quick), 10243166Snsouch DEVMETHOD(smbus_sendb,intsmb_sendb), 10343166Snsouch DEVMETHOD(smbus_recvb,intsmb_recvb), 10443166Snsouch DEVMETHOD(smbus_writeb,intsmb_writeb), 10543166Snsouch DEVMETHOD(smbus_writew,intsmb_writew), 10643166Snsouch DEVMETHOD(smbus_readb,intsmb_readb), 10743166Snsouch DEVMETHOD(smbus_readw,intsmb_readw), 10843166Snsouch DEVMETHOD(smbus_pcall,intsmb_pcall), 10943166Snsouch DEVMETHOD(smbus_bwrite,intsmb_bwrite), 11043166Snsouch DEVMETHOD(smbus_bread,intsmb_bread), 11143166Snsouch {0,0} 11243166Snsouch}; 11343166Snsouch 11446651Speterstruct intpm_pci_softc{ 11543166Snsouch bus_space_tag_t smbst; 11643166Snsouch bus_space_handle_t smbsh; 11743166Snsouch bus_space_tag_t pmst; 11843166Snsouch bus_space_handle_t pmsh; 11943166Snsouch pcici_t cfg; 12043166Snsouch device_t smbus; 12146651Speter}; 12243166Snsouch 12343166Snsouch 12443166Snsouchstruct intsmb_softc{ 12543166Snsouch struct intpm_pci_softc *pci_sc; 12643166Snsouch bus_space_tag_t st; 12743166Snsouch bus_space_handle_t sh; 12843166Snsouch device_t smbus; 12943166Snsouch int isbusy; 13043166Snsouch}; 13146651Speter 13243166Snsouchstatic driver_t intpm_driver = { 13343166Snsouch "intsmb", 13443166Snsouch intpm_methods, 13543166Snsouch sizeof(struct intsmb_softc), 13643166Snsouch}; 13743166Snsouch 13846651Speterstatic devclass_t intpm_devclass; 13946651Speterstatic device_method_t intpm_pci_methods[] = { 14046651Speter DEVMETHOD(device_probe,intpm_probe), 14146651Speter DEVMETHOD(device_attach,intpm_attach), 14246651Speter {0,0} 14343166Snsouch}; 14446651Speterstatic driver_t intpm_pci_driver = { 14546651Speter "intpm", 14646651Speter intpm_pci_methods, 14746651Speter sizeof(struct intpm_pci_softc) 14846651Speter}; 14943166Snsouch 15043166Snsouchstatic int 15143166Snsouchintsmb_probe(device_t dev) 15243166Snsouch{ 15343166Snsouch struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 15443166Snsouch sc->smbus=smbus_alloc_bus(dev); 15543166Snsouch if (!sc->smbus) 15643166Snsouch return (EINVAL); /* XXX don't know what to return else */ 15743166Snsouch device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 15843166Snsouch 15943166Snsouch return (0); /* XXX don't know what to return else */ 16043166Snsouch} 16143166Snsouchstatic int 16243166Snsouchintsmb_attach(device_t dev) 16343166Snsouch{ 16443166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 16546651Speter sc->pci_sc=device_get_softc(device_get_parent(dev)); 16643166Snsouch sc->isbusy=0; 16743166Snsouch sc->sh=sc->pci_sc->smbsh; 16843166Snsouch sc->st=sc->pci_sc->smbst; 16943166Snsouch sc->pci_sc->smbus=dev; 17043166Snsouch device_probe_and_attach(sc->smbus); 17143166Snsouch#ifdef ENABLE_ALART 17243166Snsouch /*Enable Arart*/ 17343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 17443166Snsouch PIIX4_SMBSLVCNT_ALTEN); 17543166Snsouch#endif 17643166Snsouch return (0); 17743166Snsouch} 17843166Snsouch 17943166Snsouchstatic void 18043166Snsouchintsmb_print_child(device_t bus, device_t dev) 18143166Snsouch{ 18243166Snsouch printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 18343166Snsouch return; 18443166Snsouch} 18543166Snsouchstatic int 18643166Snsouchintsmb_callback(device_t dev, int index, caddr_t data) 18743166Snsouch{ 18843166Snsouch int error = 0; 18943166Snsouch intrmask_t s; 19043166Snsouch s=splnet(); 19143166Snsouch switch (index) { 19243166Snsouch case SMB_REQUEST_BUS: 19343166Snsouch break; 19443166Snsouch case SMB_RELEASE_BUS: 19543166Snsouch break; 19643166Snsouch default: 19743166Snsouch error = EINVAL; 19843166Snsouch } 19943166Snsouch splx(s); 20043166Snsouch return (error); 20143166Snsouch} 20243166Snsouch/*counterpart of smbtx_smb_free*/ 20343166Snsouchstatic int 20443166Snsouchintsmb_free(device_t dev){ 20546651Speter intrmask_t s; 20643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 20743166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 20843166Snsouch PIIX4_SMBHSTSTAT_BUSY) 20943166Snsouch#ifdef ENABLE_ALART 21043166Snsouch ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 21143166Snsouch PIIX4_SMBSLVSTS_BUSY) 21243166Snsouch#endif 21343166Snsouch || sc->isbusy) 21443166Snsouch return EBUSY; 21546651Speter s=splhigh(); 21643166Snsouch sc->isbusy=1; 21743166Snsouch /*Disable Intrrupt in slave part*/ 21843166Snsouch#ifndef ENABLE_ALART 21943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 22043166Snsouch#endif 22143166Snsouch /*Reset INTR Flag to prepare INTR*/ 22243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 22343166Snsouch (PIIX4_SMBHSTSTAT_INTR| 22443166Snsouch PIIX4_SMBHSTSTAT_ERR| 22543166Snsouch PIIX4_SMBHSTSTAT_BUSC| 22643166Snsouch PIIX4_SMBHSTSTAT_FAIL) 22743166Snsouch ); 22846651Speter splx(s); 22943166Snsouch return 0; 23043166Snsouch} 23143166Snsouch 23243166Snsouchstatic int 23343166Snsouchintsmb_intr(device_t dev) 23443166Snsouch{ 23543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 23643166Snsouch int status; 23743166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 23843166Snsouch if(status&PIIX4_SMBHSTSTAT_BUSY){ 23943166Snsouch return 1; 24043166Snsouch 24143166Snsouch } 24249064Snsouch if(status&(PIIX4_SMBHSTSTAT_INTR| 24343166Snsouch PIIX4_SMBHSTSTAT_ERR| 24443166Snsouch PIIX4_SMBHSTSTAT_BUSC| 24549064Snsouch PIIX4_SMBHSTSTAT_FAIL)){ 24643166Snsouch int tmp; 24743166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 24843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 24943166Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 25049064Snsouch if(sc->isbusy){ 25149064Snsouch sc->isbusy=0; 25249064Snsouch wakeup(sc); 25349064Snsouch } 25443166Snsouch return 0; 25543166Snsouch } 25643166Snsouch return 1;/* Not Completed*/ 25743166Snsouch} 25843166Snsouchstatic int 25943166Snsouchintsmb_slvintr(device_t dev) 26043166Snsouch{ 26143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 26243166Snsouch int status,retval; 26343166Snsouch retval=1; 26443166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 26543166Snsouch if(status&PIIX4_SMBSLVSTS_BUSY) 26643166Snsouch return retval; 26743166Snsouch if(status&PIIX4_SMBSLVSTS_ALART){ 26843166Snsouch intsmb_alrintr(dev); 26943166Snsouch retval=0; 27043166Snsouch }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 27143166Snsouch |PIIX4_SMBSLVSTS_SDW1)){ 27243166Snsouch retval=0; 27343166Snsouch } 27443166Snsouch /*Reset Status Register*/ 27543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 27643166Snsouch PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 27743166Snsouch PIIX4_SMBSLVSTS_SLV); 27843166Snsouch return retval; 27943166Snsouch} 28043166Snsouch 28143166Snsouchstatic void intsmb_alrintr(device_t dev) 28243166Snsouch{ 28343166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 28443166Snsouch int slvcnt; 28543288Sdillon#ifdef ENABLE_ALART 28643288Sdillon int error; 28743288Sdillon#endif 28843288Sdillon 28943166Snsouch /*stop generating INTR from ALART*/ 29043166Snsouch slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 29143166Snsouch#ifdef ENABLE_ALART 29243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 29343166Snsouch slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 29443166Snsouch#endif 29543166Snsouch DELAY(5); 29643166Snsouch /*ask bus who assert it and then ask it what's the matter. */ 29743166Snsouch#ifdef ENABLE_ALART 29843166Snsouch error=intsmb_free(dev); 29943166Snsouch if(!error){ 30043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 30143166Snsouch |LSB); 30243166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 30343166Snsouch if(!(error=intsmb_stop_poll(dev))){ 30443288Sdillon volatile u_int8_t *addr; 30543166Snsouch addr=bus_space_read_1(sc->st,sc->sh, 30643166Snsouch PIIX4_SMBHSTDAT0); 30743311Sdillon printf("ALART_RESPONSE: %p\n", addr); 30843166Snsouch } 30943166Snsouch }else{ 31043166Snsouch printf("ERROR\n"); 31143166Snsouch } 31243166Snsouch 31343166Snsouch /*Re-enable INTR from ALART*/ 31443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 31543166Snsouch slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 31643166Snsouch DELAY(5); 31743166Snsouch#endif 31843166Snsouch 31943166Snsouch return; 32043166Snsouch} 32143166Snsouchstatic void 32243166Snsouchintsmb_start(device_t dev,unsigned char cmd,int nointr) 32343166Snsouch{ 32443166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 32543166Snsouch unsigned char tmp; 32643166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 32743166Snsouch tmp&= 0xe0; 32843166Snsouch tmp |= cmd; 32943166Snsouch tmp |=PIIX4_SMBHSTCNT_START; 33043166Snsouch /*While not in autoconfiguration Intrrupt Enabled*/ 33143166Snsouch if(!cold||!nointr) 33243166Snsouch tmp |=PIIX4_SMBHSTCNT_INTREN; 33343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 33443166Snsouch} 33543166Snsouch 33643166Snsouch/*Polling Code. Polling is not encouraged 33743166Snsouch * because It is required to wait for the device get busy. 33843166Snsouch *(29063505.pdf from Intel) 33943166Snsouch * But during boot,intrrupt cannot be used. 34043166Snsouch * so use polling code while in autoconfiguration. 34143166Snsouch */ 34243166Snsouch 34343166Snsouchstatic int 34443166Snsouchintsmb_stop_poll(device_t dev){ 34543166Snsouch int error,i; 34643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 34749064Snsouch 34843166Snsouch /* 34943166Snsouch * In smbtx driver ,Simply waiting. 35043166Snsouch * This loops 100-200 times. 35143166Snsouch */ 35243166Snsouch for(i=0;i<0x7fff;i++){ 35343166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 35443166Snsouch &PIIX4_SMBHSTSTAT_BUSY)){ 35543166Snsouch break; 35643166Snsouch } 35743166Snsouch } 35843166Snsouch for(i=0;i<0x7fff;i++){ 35943166Snsouch int status; 36043166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 36143166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 36243166Snsouch sc->isbusy=0; 36343166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 36443166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 36543166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 36643166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 36743166Snsouch printf("unknown cause why?"); 36843166Snsouch } 36943166Snsouch return error; 37043166Snsouch } 37143166Snsouch } 37249064Snsouch { 37349064Snsouch int tmp; 37449064Snsouch sc->isbusy=0; 37549064Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 37649064Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 37749064Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 37849064Snsouch } 37943166Snsouch return EIO; 38043166Snsouch} 38143166Snsouch/* 38243166Snsouch *wait for completion and return result. 38343166Snsouch */ 38443166Snsouchstatic int 38543166Snsouchintsmb_stop(device_t dev){ 38643166Snsouch int error; 38746651Speter intrmask_t s; 38843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 38943166Snsouch if(cold){ 39043166Snsouch /*So that it can use device during probing device on SMBus.*/ 39143166Snsouch error=intsmb_stop_poll(dev); 39243166Snsouch return error; 39343166Snsouch }else{ 39443166Snsouch if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 39543166Snsouch int status; 39643166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 39743166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 39843166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 39943166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 40043166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 40143166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 40243166Snsouch printf("intsmb%d:unknown cause why?\n", 40343166Snsouch device_get_unit(dev)); 40443166Snsouch } 40543166Snsouch#ifdef ENABLE_ALART 40643166Snsouch bus_space_write_1(sc->st,sc->sh, 40743166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 40843166Snsouch#endif 40943166Snsouch return error; 41043166Snsouch } 41143166Snsouch } 41243166Snsouch } 41343166Snsouch /*Timeout Procedure*/ 41446651Speter s=splhigh(); 41543166Snsouch sc->isbusy=0; 41643166Snsouch /*Re-enable supressed intrrupt from slave part*/ 41743166Snsouch bus_space_write_1(sc->st,sc->sh, 41843166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 41946651Speter splx(s); 42043166Snsouch return EIO; 42143166Snsouch} 42243166Snsouch 42343166Snsouchstatic int 42443166Snsouchintsmb_quick(device_t dev, u_char slave, int how) 42543166Snsouch{ 42643166Snsouch int error=0; 42743166Snsouch u_char data; 42843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 42943166Snsouch data=slave; 43043166Snsouch /*Quick command is part of Address, I think*/ 43143166Snsouch switch(how){ 43243166Snsouch case SMB_QWRITE: 43343166Snsouch data&=~LSB; 43443166Snsouch break; 43543166Snsouch case SMB_QREAD: 43643166Snsouch data|=LSB; 43743166Snsouch break; 43843166Snsouch default: 43943166Snsouch error=EINVAL; 44043166Snsouch } 44143166Snsouch if(!error){ 44243166Snsouch error=intsmb_free(dev); 44343166Snsouch if(!error){ 44443166Snsouch bus_space_write_1(sc->st,sc->sh, 44543166Snsouch PIIX4_SMBHSTADD,data); 44643166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 44743166Snsouch error=intsmb_stop(dev); 44843166Snsouch } 44943166Snsouch } 45043166Snsouch 45143166Snsouch return (error); 45243166Snsouch} 45343166Snsouch 45443166Snsouchstatic int 45543166Snsouchintsmb_sendb(device_t dev, u_char slave, char byte) 45643166Snsouch{ 45743166Snsouch int error; 45843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 45943166Snsouch error=intsmb_free(dev); 46043166Snsouch if(!error){ 46143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 46243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 46343166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 46443166Snsouch error=intsmb_stop(dev); 46543166Snsouch } 46643166Snsouch return (error); 46743166Snsouch} 46843166Snsouchstatic int 46943166Snsouchintsmb_recvb(device_t dev, u_char slave, char *byte) 47043166Snsouch{ 47143166Snsouch int error; 47243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 47343166Snsouch error=intsmb_free(dev); 47443166Snsouch if(!error){ 47543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 47643166Snsouch |LSB); 47743166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 47843166Snsouch if(!(error=intsmb_stop(dev))){ 47943166Snsouch#ifdef RECV_IS_IN_CMD 48043166Snsouch /*Linux SMBus stuff also troubles 48143166Snsouch Because Intel's datasheet will not make clear. 48243166Snsouch */ 48343166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 48443166Snsouch PIIX4_SMBHSTCMD); 48543166Snsouch#else 48643166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 48743166Snsouch PIIX4_SMBHSTDAT0); 48843166Snsouch#endif 48943166Snsouch } 49043166Snsouch } 49143166Snsouch return (error); 49243166Snsouch} 49343166Snsouchstatic int 49443166Snsouchintsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 49543166Snsouch{ 49643166Snsouch int error; 49743166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 49843166Snsouch error=intsmb_free(dev); 49943166Snsouch if(!error){ 50043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 50143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 50243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 50343166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 50443166Snsouch error=intsmb_stop(dev); 50543166Snsouch } 50643166Snsouch return (error); 50743166Snsouch} 50843166Snsouchstatic int 50943166Snsouchintsmb_writew(device_t dev, u_char slave, char cmd, short word) 51043166Snsouch{ 51143166Snsouch int error; 51243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 51343166Snsouch error=intsmb_free(dev); 51443166Snsouch if(!error){ 51543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 51643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 51743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 51843166Snsouch word&0xff); 51943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 52043166Snsouch (word>>8)&0xff); 52143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 52243166Snsouch error=intsmb_stop(dev); 52343166Snsouch } 52443166Snsouch return (error); 52543166Snsouch} 52643166Snsouch 52743166Snsouchstatic int 52843166Snsouchintsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 52943166Snsouch{ 53043166Snsouch int error; 53143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 53243166Snsouch error=intsmb_free(dev); 53343166Snsouch if(!error){ 53443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 53543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 53643166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 53743166Snsouch if(!(error=intsmb_stop(dev))){ 53843166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 53943166Snsouch PIIX4_SMBHSTDAT0); 54043166Snsouch } 54143166Snsouch } 54243166Snsouch return (error); 54343166Snsouch} 54443166Snsouchstatic int 54543166Snsouchintsmb_readw(device_t dev, u_char slave, char cmd, short *word) 54643166Snsouch{ 54743166Snsouch int error; 54843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 54943166Snsouch error=intsmb_free(dev); 55043166Snsouch if(!error){ 55143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 55243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 55343166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 55443166Snsouch if(!(error=intsmb_stop(dev))){ 55543166Snsouch *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 55643166Snsouch *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 55743166Snsouch } 55843166Snsouch } 55943166Snsouch return (error); 56043166Snsouch} 56143166Snsouch/* 56243166Snsouch * Data sheet claims that it implements all function, but also claims 56343166Snsouch * that it implements 7 function and not mention PCALL. So I don't know 56443166Snsouch * whether it will work. 56543166Snsouch */ 56643166Snsouchstatic int 56743166Snsouchintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 56843166Snsouch{ 56943166Snsouch#ifdef PROCCALL_TEST 57043166Snsouch int error; 57143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 57243166Snsouch error=intsmb_free(dev); 57343166Snsouch if(!error){ 57443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 57543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 57643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 57743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 57843166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 57943166Snsouch } 58043166Snsouch if(!(error=intsmb_stop(dev))){ 58143166Snsouch *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 58243166Snsouch *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 58343166Snsouch } 58443166Snsouch return error; 58543166Snsouch#else 58643166Snsouch return 0; 58743166Snsouch#endif 58843166Snsouch} 58943166Snsouchstatic int 59043166Snsouchintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 59143166Snsouch{ 59243166Snsouch int error,i; 59343166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 59443166Snsouch error=intsmb_free(dev); 59543166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 59643166Snsouch error=EINVAL; 59743166Snsouch if(!error){ 59843166Snsouch /*Reset internal array index*/ 59943166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 60043166Snsouch 60143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 60243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 60343166Snsouch for(i=0;i<count;i++){ 60443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 60543166Snsouch } 60643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 60743166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 60843166Snsouch error=intsmb_stop(dev); 60943166Snsouch } 61043166Snsouch return (error); 61143166Snsouch} 61243166Snsouch 61343166Snsouchstatic int 61443166Snsouchintsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 61543166Snsouch{ 61643166Snsouch int error,i; 61743166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 61843166Snsouch error=intsmb_free(dev); 61943166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 62043166Snsouch error=EINVAL; 62143166Snsouch if(!error){ 62243166Snsouch /*Reset internal array index*/ 62343166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 62443166Snsouch 62543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 62643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 62743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 62843166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 62943166Snsouch error=intsmb_stop(dev); 63043166Snsouch if(!error){ 63143166Snsouch bzero(buf,count);/*Is it needed?*/ 63243166Snsouch count= bus_space_read_1(sc->st,sc->sh, 63343166Snsouch PIIX4_SMBHSTDAT0); 63443166Snsouch if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 63543166Snsouch for(i=0;i<count;i++){ 63643166Snsouch buf[i]=bus_space_read_1(sc->st, 63743166Snsouch sc->sh, 63843166Snsouch PIIX4_SMBBLKDAT); 63943166Snsouch } 64043166Snsouch } 64143166Snsouch else{ 64243166Snsouch error=EIO; 64343166Snsouch } 64443166Snsouch } 64543166Snsouch } 64643166Snsouch return (error); 64743166Snsouch} 64843166Snsouch 64946651SpeterDRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 65043166Snsouch 65143166Snsouch 65243166Snsouchstatic void intpm_intr __P((void *arg)); 65346651Speterstatic int 65446651Speterintpm_attach(device_t dev) 65543166Snsouch{ 65643166Snsouch int value; 65746651Speter int unit=device_get_unit(dev); 65846651Speter void *ih; 65946651Speter int error; 66043166Snsouch char * str; 66143166Snsouch { 66243166Snsouch struct intpm_pci_softc *sciic; 66343166Snsouch device_t smbinterface; 66446651Speter int rid; 66546651Speter struct resource *res; 66646651Speter 66746651Speter sciic=device_get_softc(dev); 66843166Snsouch if(sciic==NULL){ 66946651Speter return ENOMEM; 67043166Snsouch } 67143166Snsouch 67246651Speter rid=PCI_BASE_ADDR_SMB; 67346651Speter#if 0 67446651Speter res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid, 67546651Speter 0,~0,1,RF_ACTIVE); 67646651Speter if(res==NULL){ 67746651Speter device_printf(dev,"IO FAILED Trying Memory\n"); 67846651Speter res=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0, 67946651Speter 1,RF_ACTIVE); 68046651Speter } 68146651Speter#else 68246651Speter /*Do as I tell!*/ 68346651Speter value=pci_read_config(dev,rid,4); 68446651Speter res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,value&(~1), 68546651Speter (value&(~1))+256,256,RF_ACTIVE); 68646651Speter#endif 68746651Speter if(res==NULL){ 68846651Speter device_printf(dev,"Could not allocate Bus space\n"); 68946651Speter return ENXIO; 69046651Speter } 69146651Speter sciic->smbst=rman_get_bustag(res); 69246651Speter sciic->smbsh=rman_get_bushandle(res); 69346651Speter 69446651Speter device_printf(dev,"%s %x\n", 69546651Speter (sciic->smbst==I386_BUS_SPACE_IO)? 69646651Speter "I/O mapped":"Memory", 69746651Speter sciic->smbsh); 69846651Speter 69943166Snsouch 70043166Snsouch#ifndef NO_CHANGE_PCICONF 70146651Speter pci_write_config(dev,PCIR_INTLINE,0x9,1); 70246651Speter pci_write_config(dev,PCI_HST_CFG_SMB, 70346651Speter PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 70443166Snsouch#endif 70546651Speter value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 70643166Snsouch switch(value&0xe){ 70743166Snsouch case PCI_INTR_SMB_SMI: 70846651Speter str="SMI"; 70943166Snsouch break; 71043166Snsouch case PCI_INTR_SMB_IRQ9: 71143166Snsouch str="IRQ 9"; 71243166Snsouch break; 71343166Snsouch default: 71443166Snsouch str="BOGUS"; 71543166Snsouch } 71646651Speter device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 71746651Speter value=pci_read_config(dev,PCI_REVID_SMB,1); 71843166Snsouch printf("revision %d\n",value); 71943166Snsouch /* 72043166Snsouch * Install intr HANDLER here 72143166Snsouch */ 72246651Speter rid=0; 72346651Speter res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 72446651Speter if(res==NULL){ 72546651Speter device_printf(dev,"could not allocate irq"); 72646651Speter return ENOMEM; 72746651Speter } 72846777Sphk error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih); 72946651Speter if(error){ 73046651Speter device_printf(dev,"Failed to map intr\n"); 73146651Speter return error; 73243166Snsouch } 73346651Speter smbinterface=device_add_child(dev,"intsmb",unit,NULL); 73446651Speter if(!smbinterface){ 73546651Speter printf("intsmb%d:could not add SMBus device\n",unit); 73646651Speter } 73743166Snsouch device_probe_and_attach(smbinterface); 73843166Snsouch } 73946651Speter 74046651Speter value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 74143166Snsouch printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 74246651Speter return 0; 74343166Snsouch} 74446651Speterstatic int 74546651Speterintpm_probe(device_t dev) 74646651Speter{ 74746651Speter struct _pcsid *ep =pci_ids; 74846651Speter u_int32_t device_id=pci_get_devid(dev); 74949064Snsouch 75046651Speter while (ep->type && ep->type != device_id) 75146651Speter ++ep; 75246651Speter if(ep->desc!=NULL){ 75346651Speter device_set_desc(dev,ep->desc); 75446651Speter return 0; 75546651Speter }else{ 75646651Speter return ENXIO; 75746651Speter } 75846651Speter} 75946651SpeterDRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 76046651Speter 76143166Snsouchstatic void intpm_intr(void *arg) 76243166Snsouch{ 76343166Snsouch struct intpm_pci_softc *sc; 76443166Snsouch sc=(struct intpm_pci_softc *)arg; 76543166Snsouch intsmb_intr(sc->smbus); 76643166Snsouch intsmb_slvintr(sc->smbus); 76749064Snsouch 76843166Snsouch} 769