intpm.c revision 162234
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 */ 2643166Snsouch 27116192Sobrien#include <sys/cdefs.h> 28116192Sobrien__FBSDID("$FreeBSD: head/sys/pci/intpm.c 162234 2006-09-11 20:52:41Z jhb $"); 29116192Sobrien 3043166Snsouch#include <sys/param.h> 3143166Snsouch#include <sys/systm.h> 3243166Snsouch#include <sys/kernel.h> 3343166Snsouch#include <machine/bus.h> 3443166Snsouch 3543166Snsouch#include <sys/uio.h> 3643166Snsouch#include <sys/module.h> 3743166Snsouch#include <sys/bus.h> 3846651Speter#include <sys/rman.h> 3946651Speter#include <machine/resource.h> 4043166Snsouch#include <dev/smbus/smbconf.h> 4143166Snsouch 4243166Snsouch#include "smbus_if.h" 4343166Snsouch 4443166Snsouch/*This should be removed if force_pci_map_int supported*/ 4543166Snsouch#include <sys/interrupt.h> 4643166Snsouch 47119288Simp#include <dev/pci/pcireg.h> 48119288Simp#include <dev/pci/pcivar.h> 4943166Snsouch#include <pci/intpmreg.h> 5043166Snsouch 5143166Snsouch#include "opt_intpm.h" 5243166Snsouch 5343166Snsouchstatic struct _pcsid 5443166Snsouch{ 5561042Speter u_int32_t type; 5643166Snsouch char *desc; 5743166Snsouch} pci_ids[] = 5843166Snsouch{ 5943166Snsouch { 0x71138086,"Intel 82371AB Power management controller"}, 6088323Spirzyk { 0x719b8086,"Intel 82443MX Power management controller"}, 6174285Speter#if 0 6274285Speter /* Not a good idea yet, this stops isab0 functioning */ 6374285Speter { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"}, 6474285Speter#endif 6543166Snsouch 6643166Snsouch { 0x00000000, NULL } 6743166Snsouch}; 6843166Snsouchstatic int intsmb_probe(device_t); 6943166Snsouchstatic int intsmb_attach(device_t); 7043166Snsouch 7143166Snsouchstatic int intsmb_intr(device_t dev); 7243166Snsouchstatic int intsmb_slvintr(device_t dev); 7343166Snsouchstatic void intsmb_alrintr(device_t dev); 74162234Sjhbstatic int intsmb_callback(device_t dev, int index, void *data); 7543166Snsouchstatic int intsmb_quick(device_t dev, u_char slave, int how); 7643166Snsouchstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 7743166Snsouchstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 7843166Snsouchstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 7943166Snsouchstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 8043166Snsouchstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 8143166Snsouchstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 8243166Snsouchstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 8343166Snsouchstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 84162234Sjhbstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); 8543166Snsouchstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 8643166Snsouchstatic int intsmb_stop(device_t dev); 8743166Snsouchstatic int intsmb_stop_poll(device_t dev); 8843166Snsouchstatic int intsmb_free(device_t dev); 8946651Speterstatic int intpm_probe (device_t dev); 9046651Speterstatic int intpm_attach (device_t dev); 9143166Snsouchstatic devclass_t intsmb_devclass; 9243166Snsouch 9343166Snsouchstatic device_method_t intpm_methods[]={ 9443166Snsouch DEVMETHOD(device_probe,intsmb_probe), 9543166Snsouch DEVMETHOD(device_attach,intsmb_attach), 9643166Snsouch 9749195Smdodd DEVMETHOD(bus_print_child, bus_generic_print_child), 9843166Snsouch 9943166Snsouch DEVMETHOD(smbus_callback,intsmb_callback), 10043166Snsouch DEVMETHOD(smbus_quick,intsmb_quick), 10143166Snsouch DEVMETHOD(smbus_sendb,intsmb_sendb), 10243166Snsouch DEVMETHOD(smbus_recvb,intsmb_recvb), 10343166Snsouch DEVMETHOD(smbus_writeb,intsmb_writeb), 10443166Snsouch DEVMETHOD(smbus_writew,intsmb_writew), 10543166Snsouch DEVMETHOD(smbus_readb,intsmb_readb), 10643166Snsouch DEVMETHOD(smbus_readw,intsmb_readw), 10743166Snsouch DEVMETHOD(smbus_pcall,intsmb_pcall), 10843166Snsouch DEVMETHOD(smbus_bwrite,intsmb_bwrite), 10943166Snsouch DEVMETHOD(smbus_bread,intsmb_bread), 11043166Snsouch {0,0} 11143166Snsouch}; 11243166Snsouch 11346651Speterstruct intpm_pci_softc{ 11443166Snsouch bus_space_tag_t smbst; 11543166Snsouch bus_space_handle_t smbsh; 11643166Snsouch bus_space_tag_t pmst; 11743166Snsouch bus_space_handle_t pmsh; 11843166Snsouch device_t smbus; 11946651Speter}; 12043166Snsouch 12143166Snsouch 12243166Snsouchstruct intsmb_softc{ 12343166Snsouch struct intpm_pci_softc *pci_sc; 12443166Snsouch bus_space_tag_t st; 12543166Snsouch bus_space_handle_t sh; 12643166Snsouch device_t smbus; 12743166Snsouch int isbusy; 12843166Snsouch}; 12946651Speter 13043166Snsouchstatic driver_t intpm_driver = { 13143166Snsouch "intsmb", 13243166Snsouch intpm_methods, 13343166Snsouch sizeof(struct intsmb_softc), 13443166Snsouch}; 13543166Snsouch 13646651Speterstatic devclass_t intpm_devclass; 13746651Speterstatic device_method_t intpm_pci_methods[] = { 13846651Speter DEVMETHOD(device_probe,intpm_probe), 13946651Speter DEVMETHOD(device_attach,intpm_attach), 14046651Speter {0,0} 14143166Snsouch}; 14246651Speterstatic driver_t intpm_pci_driver = { 14346651Speter "intpm", 14446651Speter intpm_pci_methods, 14546651Speter sizeof(struct intpm_pci_softc) 14646651Speter}; 14743166Snsouch 14843166Snsouchstatic int 14943166Snsouchintsmb_probe(device_t dev) 15043166Snsouch{ 15143166Snsouch struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 15293023Snsouch sc->smbus=device_add_child(dev, "smbus", -1); 15343166Snsouch if (!sc->smbus) 15443166Snsouch return (EINVAL); /* XXX don't know what to return else */ 15543166Snsouch device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 15643166Snsouch 157142398Simp return (BUS_PROBE_DEFAULT); /* XXX don't know what to return else */ 15843166Snsouch} 15943166Snsouchstatic int 16043166Snsouchintsmb_attach(device_t dev) 16143166Snsouch{ 16243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 16346651Speter sc->pci_sc=device_get_softc(device_get_parent(dev)); 16443166Snsouch sc->isbusy=0; 16543166Snsouch sc->sh=sc->pci_sc->smbsh; 16643166Snsouch sc->st=sc->pci_sc->smbst; 16743166Snsouch sc->pci_sc->smbus=dev; 16843166Snsouch device_probe_and_attach(sc->smbus); 16943166Snsouch#ifdef ENABLE_ALART 17043166Snsouch /*Enable Arart*/ 17143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 17243166Snsouch PIIX4_SMBSLVCNT_ALTEN); 17343166Snsouch#endif 17443166Snsouch return (0); 17543166Snsouch} 17643166Snsouch 17743166Snsouchstatic int 178162234Sjhbintsmb_callback(device_t dev, int index, void *data) 17943166Snsouch{ 18043166Snsouch int error = 0; 18143166Snsouch intrmask_t s; 18243166Snsouch s=splnet(); 18343166Snsouch switch (index) { 18443166Snsouch case SMB_REQUEST_BUS: 18543166Snsouch break; 18643166Snsouch case SMB_RELEASE_BUS: 18743166Snsouch break; 18843166Snsouch default: 18943166Snsouch error = EINVAL; 19043166Snsouch } 19143166Snsouch splx(s); 19243166Snsouch return (error); 19343166Snsouch} 19443166Snsouch/*counterpart of smbtx_smb_free*/ 19543166Snsouchstatic int 19643166Snsouchintsmb_free(device_t dev){ 19746651Speter intrmask_t s; 19843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 19943166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 20043166Snsouch PIIX4_SMBHSTSTAT_BUSY) 20143166Snsouch#ifdef ENABLE_ALART 20243166Snsouch ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 20343166Snsouch PIIX4_SMBSLVSTS_BUSY) 20443166Snsouch#endif 20543166Snsouch || sc->isbusy) 20643166Snsouch return EBUSY; 20746651Speter s=splhigh(); 20843166Snsouch sc->isbusy=1; 20943166Snsouch /*Disable Intrrupt in slave part*/ 21043166Snsouch#ifndef ENABLE_ALART 21143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 21243166Snsouch#endif 21343166Snsouch /*Reset INTR Flag to prepare INTR*/ 21443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 21543166Snsouch (PIIX4_SMBHSTSTAT_INTR| 21643166Snsouch PIIX4_SMBHSTSTAT_ERR| 21743166Snsouch PIIX4_SMBHSTSTAT_BUSC| 21843166Snsouch PIIX4_SMBHSTSTAT_FAIL) 21943166Snsouch ); 22046651Speter splx(s); 22143166Snsouch return 0; 22243166Snsouch} 22343166Snsouch 22443166Snsouchstatic int 22543166Snsouchintsmb_intr(device_t dev) 22643166Snsouch{ 22743166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 22843166Snsouch int status; 22943166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 23043166Snsouch if(status&PIIX4_SMBHSTSTAT_BUSY){ 23143166Snsouch return 1; 23243166Snsouch 23343166Snsouch } 23449064Snsouch if(status&(PIIX4_SMBHSTSTAT_INTR| 23543166Snsouch PIIX4_SMBHSTSTAT_ERR| 23643166Snsouch PIIX4_SMBHSTSTAT_BUSC| 23749064Snsouch PIIX4_SMBHSTSTAT_FAIL)){ 23843166Snsouch int tmp; 23943166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 24043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 24143166Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 24249064Snsouch if(sc->isbusy){ 24349064Snsouch sc->isbusy=0; 24449064Snsouch wakeup(sc); 24549064Snsouch } 24643166Snsouch return 0; 24743166Snsouch } 24843166Snsouch return 1;/* Not Completed*/ 24943166Snsouch} 25043166Snsouchstatic int 25143166Snsouchintsmb_slvintr(device_t dev) 25243166Snsouch{ 25343166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 25443166Snsouch int status,retval; 25543166Snsouch retval=1; 25643166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 25743166Snsouch if(status&PIIX4_SMBSLVSTS_BUSY) 25843166Snsouch return retval; 25943166Snsouch if(status&PIIX4_SMBSLVSTS_ALART){ 26043166Snsouch intsmb_alrintr(dev); 26143166Snsouch retval=0; 26243166Snsouch }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 26343166Snsouch |PIIX4_SMBSLVSTS_SDW1)){ 26443166Snsouch retval=0; 26543166Snsouch } 26643166Snsouch /*Reset Status Register*/ 26743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 26843166Snsouch PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 26943166Snsouch PIIX4_SMBSLVSTS_SLV); 27043166Snsouch return retval; 27143166Snsouch} 27243166Snsouch 27343166Snsouchstatic void intsmb_alrintr(device_t dev) 27443166Snsouch{ 27543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 27643166Snsouch int slvcnt; 27743288Sdillon#ifdef ENABLE_ALART 27843288Sdillon int error; 27943288Sdillon#endif 28043288Sdillon 28143166Snsouch /*stop generating INTR from ALART*/ 28243166Snsouch slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 28343166Snsouch#ifdef ENABLE_ALART 28443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 28543166Snsouch slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 28643166Snsouch#endif 28743166Snsouch DELAY(5); 28843166Snsouch /*ask bus who assert it and then ask it what's the matter. */ 28943166Snsouch#ifdef ENABLE_ALART 29043166Snsouch error=intsmb_free(dev); 29143166Snsouch if(!error){ 29243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 29343166Snsouch |LSB); 29443166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 29543166Snsouch if(!(error=intsmb_stop_poll(dev))){ 29678255Speter u_int8_t addr; 29743166Snsouch addr=bus_space_read_1(sc->st,sc->sh, 29843166Snsouch PIIX4_SMBHSTDAT0); 29978255Speter printf("ALART_RESPONSE: 0x%x\n", addr); 30043166Snsouch } 30143166Snsouch }else{ 30243166Snsouch printf("ERROR\n"); 30343166Snsouch } 30443166Snsouch 30543166Snsouch /*Re-enable INTR from ALART*/ 30643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 30743166Snsouch slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 30843166Snsouch DELAY(5); 30943166Snsouch#endif 31043166Snsouch 31143166Snsouch return; 31243166Snsouch} 31343166Snsouchstatic void 31443166Snsouchintsmb_start(device_t dev,unsigned char cmd,int nointr) 31543166Snsouch{ 31643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 31743166Snsouch unsigned char tmp; 31843166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 31943166Snsouch tmp&= 0xe0; 32043166Snsouch tmp |= cmd; 32143166Snsouch tmp |=PIIX4_SMBHSTCNT_START; 32243166Snsouch /*While not in autoconfiguration Intrrupt Enabled*/ 32343166Snsouch if(!cold||!nointr) 32443166Snsouch tmp |=PIIX4_SMBHSTCNT_INTREN; 32543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 32643166Snsouch} 32743166Snsouch 32843166Snsouch/*Polling Code. Polling is not encouraged 32943166Snsouch * because It is required to wait for the device get busy. 33043166Snsouch *(29063505.pdf from Intel) 33143166Snsouch * But during boot,intrrupt cannot be used. 33243166Snsouch * so use polling code while in autoconfiguration. 33343166Snsouch */ 33443166Snsouch 33543166Snsouchstatic int 33643166Snsouchintsmb_stop_poll(device_t dev){ 33743166Snsouch int error,i; 33843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 33949064Snsouch 34043166Snsouch /* 34143166Snsouch * In smbtx driver ,Simply waiting. 34243166Snsouch * This loops 100-200 times. 34343166Snsouch */ 34443166Snsouch for(i=0;i<0x7fff;i++){ 34543166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 34643166Snsouch &PIIX4_SMBHSTSTAT_BUSY)){ 34743166Snsouch break; 34843166Snsouch } 34943166Snsouch } 35043166Snsouch for(i=0;i<0x7fff;i++){ 35143166Snsouch int status; 35243166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 35343166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 35443166Snsouch sc->isbusy=0; 35543166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 35643166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 35743166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 35843166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 35943166Snsouch printf("unknown cause why?"); 36043166Snsouch } 36143166Snsouch return error; 36243166Snsouch } 36343166Snsouch } 36449064Snsouch { 36549064Snsouch int tmp; 36649064Snsouch sc->isbusy=0; 36749064Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 36849064Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 36949064Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 37049064Snsouch } 37143166Snsouch return EIO; 37243166Snsouch} 37343166Snsouch/* 37443166Snsouch *wait for completion and return result. 37543166Snsouch */ 37643166Snsouchstatic int 37743166Snsouchintsmb_stop(device_t dev){ 37843166Snsouch int error; 37946651Speter intrmask_t s; 38043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 38143166Snsouch if(cold){ 38243166Snsouch /*So that it can use device during probing device on SMBus.*/ 38343166Snsouch error=intsmb_stop_poll(dev); 38443166Snsouch return error; 38543166Snsouch }else{ 38643166Snsouch if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 38743166Snsouch int status; 38843166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 38943166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 39043166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 39143166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 39243166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 39343166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 39443166Snsouch printf("intsmb%d:unknown cause why?\n", 39543166Snsouch device_get_unit(dev)); 39643166Snsouch } 39743166Snsouch#ifdef ENABLE_ALART 39843166Snsouch bus_space_write_1(sc->st,sc->sh, 39943166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 40043166Snsouch#endif 40143166Snsouch return error; 40243166Snsouch } 40343166Snsouch } 40443166Snsouch } 40543166Snsouch /*Timeout Procedure*/ 40646651Speter s=splhigh(); 40743166Snsouch sc->isbusy=0; 40843166Snsouch /*Re-enable supressed intrrupt from slave part*/ 40943166Snsouch bus_space_write_1(sc->st,sc->sh, 41043166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 41146651Speter splx(s); 41243166Snsouch return EIO; 41343166Snsouch} 41443166Snsouch 41543166Snsouchstatic int 41643166Snsouchintsmb_quick(device_t dev, u_char slave, int how) 41743166Snsouch{ 41843166Snsouch int error=0; 41943166Snsouch u_char data; 42043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 42143166Snsouch data=slave; 42243166Snsouch /*Quick command is part of Address, I think*/ 42343166Snsouch switch(how){ 42443166Snsouch case SMB_QWRITE: 42543166Snsouch data&=~LSB; 42643166Snsouch break; 42743166Snsouch case SMB_QREAD: 42843166Snsouch data|=LSB; 42943166Snsouch break; 43043166Snsouch default: 43143166Snsouch error=EINVAL; 43243166Snsouch } 43343166Snsouch if(!error){ 43443166Snsouch error=intsmb_free(dev); 43543166Snsouch if(!error){ 43643166Snsouch bus_space_write_1(sc->st,sc->sh, 43743166Snsouch PIIX4_SMBHSTADD,data); 43843166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 43943166Snsouch error=intsmb_stop(dev); 44043166Snsouch } 44143166Snsouch } 44243166Snsouch 44343166Snsouch return (error); 44443166Snsouch} 44543166Snsouch 44643166Snsouchstatic int 44743166Snsouchintsmb_sendb(device_t dev, u_char slave, char byte) 44843166Snsouch{ 44943166Snsouch int error; 45043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 45143166Snsouch error=intsmb_free(dev); 45243166Snsouch if(!error){ 45343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 45443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 45543166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 45643166Snsouch error=intsmb_stop(dev); 45743166Snsouch } 45843166Snsouch return (error); 45943166Snsouch} 46043166Snsouchstatic int 46143166Snsouchintsmb_recvb(device_t dev, u_char slave, char *byte) 46243166Snsouch{ 46343166Snsouch int error; 46443166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 46543166Snsouch error=intsmb_free(dev); 46643166Snsouch if(!error){ 46743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 46843166Snsouch |LSB); 46943166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 47043166Snsouch if(!(error=intsmb_stop(dev))){ 47143166Snsouch#ifdef RECV_IS_IN_CMD 47243166Snsouch /*Linux SMBus stuff also troubles 47343166Snsouch Because Intel's datasheet will not make clear. 47443166Snsouch */ 47543166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 47643166Snsouch PIIX4_SMBHSTCMD); 47743166Snsouch#else 47843166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 47943166Snsouch PIIX4_SMBHSTDAT0); 48043166Snsouch#endif 48143166Snsouch } 48243166Snsouch } 48343166Snsouch return (error); 48443166Snsouch} 48543166Snsouchstatic int 48643166Snsouchintsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 48743166Snsouch{ 48843166Snsouch int error; 48943166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 49043166Snsouch error=intsmb_free(dev); 49143166Snsouch if(!error){ 49243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 49343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 49443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 49543166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 49643166Snsouch error=intsmb_stop(dev); 49743166Snsouch } 49843166Snsouch return (error); 49943166Snsouch} 50043166Snsouchstatic int 50143166Snsouchintsmb_writew(device_t dev, u_char slave, char cmd, short word) 50243166Snsouch{ 50343166Snsouch int error; 50443166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 50543166Snsouch error=intsmb_free(dev); 50643166Snsouch if(!error){ 50743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 50843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 50943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 51043166Snsouch word&0xff); 51143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 51243166Snsouch (word>>8)&0xff); 51343166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 51443166Snsouch error=intsmb_stop(dev); 51543166Snsouch } 51643166Snsouch return (error); 51743166Snsouch} 51843166Snsouch 51943166Snsouchstatic int 52043166Snsouchintsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 52143166Snsouch{ 52243166Snsouch int error; 52343166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 52443166Snsouch error=intsmb_free(dev); 52543166Snsouch if(!error){ 52643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 52743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 52843166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 52943166Snsouch if(!(error=intsmb_stop(dev))){ 53043166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 53143166Snsouch PIIX4_SMBHSTDAT0); 53243166Snsouch } 53343166Snsouch } 53443166Snsouch return (error); 53543166Snsouch} 53643166Snsouchstatic int 53743166Snsouchintsmb_readw(device_t dev, u_char slave, char cmd, short *word) 53843166Snsouch{ 53943166Snsouch int error; 54043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 54143166Snsouch error=intsmb_free(dev); 54243166Snsouch if(!error){ 54343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 54443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 54543166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 54643166Snsouch if(!(error=intsmb_stop(dev))){ 54743166Snsouch *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 54843166Snsouch *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 54943166Snsouch } 55043166Snsouch } 55143166Snsouch return (error); 55243166Snsouch} 55343166Snsouch/* 55443166Snsouch * Data sheet claims that it implements all function, but also claims 55543166Snsouch * that it implements 7 function and not mention PCALL. So I don't know 55643166Snsouch * whether it will work. 55743166Snsouch */ 55843166Snsouchstatic int 55943166Snsouchintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 56043166Snsouch{ 56143166Snsouch#ifdef PROCCALL_TEST 56243166Snsouch int error; 56343166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 56443166Snsouch error=intsmb_free(dev); 56543166Snsouch if(!error){ 56643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 56743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 56843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 56943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 57043166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 57143166Snsouch } 57243166Snsouch if(!(error=intsmb_stop(dev))){ 57343166Snsouch *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 57443166Snsouch *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 57543166Snsouch } 57643166Snsouch return error; 57743166Snsouch#else 57843166Snsouch return 0; 57943166Snsouch#endif 58043166Snsouch} 58143166Snsouchstatic int 58243166Snsouchintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 58343166Snsouch{ 58443166Snsouch int error,i; 58543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 58643166Snsouch error=intsmb_free(dev); 58743166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 588162234Sjhb error=SMB_EINVAL; 58943166Snsouch if(!error){ 59043166Snsouch /*Reset internal array index*/ 59143166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 59243166Snsouch 59343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 59443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 59543166Snsouch for(i=0;i<count;i++){ 59643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 59743166Snsouch } 59843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 59943166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 60043166Snsouch error=intsmb_stop(dev); 60143166Snsouch } 60243166Snsouch return (error); 60343166Snsouch} 60443166Snsouch 60543166Snsouchstatic int 606162234Sjhbintsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 60743166Snsouch{ 60843166Snsouch int error,i; 609162234Sjhb u_char data, nread; 61043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 61143166Snsouch error=intsmb_free(dev); 612162234Sjhb if(*count>SMBBLOCKTRANS_MAX||*count==0) 613162234Sjhb error=SMB_EINVAL; 61443166Snsouch if(!error){ 61543166Snsouch /*Reset internal array index*/ 61643166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 61743166Snsouch 61843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 61943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 620162234Sjhb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,*count); 62143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 62243166Snsouch error=intsmb_stop(dev); 62343166Snsouch if(!error){ 624162234Sjhb nread= bus_space_read_1(sc->st,sc->sh, 62543166Snsouch PIIX4_SMBHSTDAT0); 626162234Sjhb if(nread!=0&&nread<=SMBBLOCKTRANS_MAX){ 627162234Sjhb for(i=0;i<nread;i++){ 628162234Sjhb data = bus_space_read_1(sc->st, 62943166Snsouch sc->sh, 63043166Snsouch PIIX4_SMBBLKDAT); 631162234Sjhb if (i < *count) 632162234Sjhb buf[i] = data; 63343166Snsouch } 634162234Sjhb *count = nread; 63543166Snsouch } 63643166Snsouch else{ 63743166Snsouch error=EIO; 63843166Snsouch } 63943166Snsouch } 64043166Snsouch } 64143166Snsouch return (error); 64243166Snsouch} 64343166Snsouch 64446651SpeterDRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 64543166Snsouch 64643166Snsouch 64792739Salfredstatic void intpm_intr(void *arg); 64846651Speterstatic int 64946651Speterintpm_attach(device_t dev) 65043166Snsouch{ 65143166Snsouch int value; 65246651Speter int unit=device_get_unit(dev); 65346651Speter void *ih; 65446651Speter int error; 65543166Snsouch char * str; 65643166Snsouch { 65743166Snsouch struct intpm_pci_softc *sciic; 65843166Snsouch device_t smbinterface; 65946651Speter int rid; 66046651Speter struct resource *res; 66146651Speter 66246651Speter sciic=device_get_softc(dev); 66343166Snsouch if(sciic==NULL){ 66446651Speter return ENOMEM; 66543166Snsouch } 66643166Snsouch 66746651Speter rid=PCI_BASE_ADDR_SMB; 668127135Snjl res=bus_alloc_resource_any(dev,SYS_RES_IOPORT,&rid,RF_ACTIVE); 66946651Speter if(res==NULL){ 67046651Speter device_printf(dev,"Could not allocate Bus space\n"); 67146651Speter return ENXIO; 67246651Speter } 67346651Speter sciic->smbst=rman_get_bustag(res); 67446651Speter sciic->smbsh=rman_get_bushandle(res); 67546651Speter 676106628Sjhb#ifdef __i386__ 677111547Snyan device_printf(dev,"%s %lx\n", 67846651Speter (sciic->smbst==I386_BUS_SPACE_IO)? 67946651Speter "I/O mapped":"Memory", 680111547Snyan rman_get_start(res)); 681106628Sjhb#endif 68246651Speter 68343166Snsouch 68443166Snsouch#ifndef NO_CHANGE_PCICONF 68546651Speter pci_write_config(dev,PCIR_INTLINE,0x9,1); 68646651Speter pci_write_config(dev,PCI_HST_CFG_SMB, 68746651Speter PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 68843166Snsouch#endif 68946651Speter value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 69043166Snsouch switch(value&0xe){ 69143166Snsouch case PCI_INTR_SMB_SMI: 69246651Speter str="SMI"; 69343166Snsouch break; 69443166Snsouch case PCI_INTR_SMB_IRQ9: 69543166Snsouch str="IRQ 9"; 69643166Snsouch break; 69743166Snsouch default: 69843166Snsouch str="BOGUS"; 69943166Snsouch } 70046651Speter device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 70146651Speter value=pci_read_config(dev,PCI_REVID_SMB,1); 70243166Snsouch printf("revision %d\n",value); 70343166Snsouch /* 70443166Snsouch * Install intr HANDLER here 70543166Snsouch */ 70646651Speter rid=0; 70746651Speter res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 70846651Speter if(res==NULL){ 70946651Speter device_printf(dev,"could not allocate irq"); 71046651Speter return ENOMEM; 71146651Speter } 71246777Sphk error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih); 71346651Speter if(error){ 71446651Speter device_printf(dev,"Failed to map intr\n"); 71546651Speter return error; 71643166Snsouch } 71754073Smdodd smbinterface=device_add_child(dev,"intsmb",unit); 71846651Speter if(!smbinterface){ 71946651Speter printf("intsmb%d:could not add SMBus device\n",unit); 72046651Speter } 72143166Snsouch device_probe_and_attach(smbinterface); 72243166Snsouch } 72346651Speter 72446651Speter value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 72543166Snsouch printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 72646651Speter return 0; 72743166Snsouch} 72846651Speterstatic int 72946651Speterintpm_probe(device_t dev) 73046651Speter{ 73146651Speter struct _pcsid *ep =pci_ids; 73246651Speter u_int32_t device_id=pci_get_devid(dev); 73349064Snsouch 73446651Speter while (ep->type && ep->type != device_id) 73546651Speter ++ep; 73646651Speter if(ep->desc!=NULL){ 73746651Speter device_set_desc(dev,ep->desc); 73852590Sdfr bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */ 739142398Simp return (BUS_PROBE_DEFAULT); 74046651Speter }else{ 74146651Speter return ENXIO; 74246651Speter } 74346651Speter} 74446651SpeterDRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 745162234SjhbDRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0); 74693023SnsouchMODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 74793023SnsouchMODULE_VERSION(intpm, 1); 74846651Speter 74943166Snsouchstatic void intpm_intr(void *arg) 75043166Snsouch{ 75143166Snsouch struct intpm_pci_softc *sc; 75243166Snsouch sc=(struct intpm_pci_softc *)arg; 75343166Snsouch intsmb_intr(sc->smbus); 75443166Snsouch intsmb_slvintr(sc->smbus); 75549064Snsouch 75643166Snsouch} 757