intpm.c revision 119288
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 119288 2003-08-22 07:20:27Z imp $"); 29116192Sobrien 3043166Snsouch#include <sys/param.h> 3143166Snsouch#include <sys/systm.h> 3243166Snsouch#include <sys/kernel.h> 3343166Snsouch#include <machine/bus_pio.h> 3443166Snsouch#include <machine/bus_memio.h> 3543166Snsouch#include <machine/bus.h> 3643166Snsouch 3743166Snsouch#include <sys/uio.h> 3843166Snsouch#include <sys/module.h> 3943166Snsouch#include <sys/bus.h> 4046651Speter#include <sys/rman.h> 4146651Speter#include <machine/resource.h> 4243166Snsouch#include <dev/smbus/smbconf.h> 4343166Snsouch 4443166Snsouch#include "smbus_if.h" 4543166Snsouch 4643166Snsouch/*This should be removed if force_pci_map_int supported*/ 4743166Snsouch#include <sys/interrupt.h> 4843166Snsouch 49119288Simp#include <dev/pci/pcireg.h> 50119288Simp#include <dev/pci/pcivar.h> 5143166Snsouch#include <pci/intpmreg.h> 5243166Snsouch 5343166Snsouch#include "opt_intpm.h" 5443166Snsouch 5543166Snsouchstatic struct _pcsid 5643166Snsouch{ 5761042Speter u_int32_t type; 5843166Snsouch char *desc; 5943166Snsouch} pci_ids[] = 6043166Snsouch{ 6143166Snsouch { 0x71138086,"Intel 82371AB Power management controller"}, 6288323Spirzyk { 0x719b8086,"Intel 82443MX Power management controller"}, 6374285Speter#if 0 6474285Speter /* Not a good idea yet, this stops isab0 functioning */ 6574285Speter { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"}, 6674285Speter#endif 6743166Snsouch 6843166Snsouch { 0x00000000, NULL } 6943166Snsouch}; 7043166Snsouchstatic int intsmb_probe(device_t); 7143166Snsouchstatic int intsmb_attach(device_t); 7243166Snsouch 7343166Snsouchstatic int intsmb_intr(device_t dev); 7443166Snsouchstatic int intsmb_slvintr(device_t dev); 7543166Snsouchstatic void intsmb_alrintr(device_t dev); 7643166Snsouchstatic int intsmb_callback(device_t dev, int index, caddr_t data); 7743166Snsouchstatic int intsmb_quick(device_t dev, u_char slave, int how); 7843166Snsouchstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 7943166Snsouchstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 8043166Snsouchstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 8143166Snsouchstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 8243166Snsouchstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 8343166Snsouchstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 8443166Snsouchstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 8543166Snsouchstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8643166Snsouchstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8743166Snsouchstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 8843166Snsouchstatic int intsmb_stop(device_t dev); 8943166Snsouchstatic int intsmb_stop_poll(device_t dev); 9043166Snsouchstatic int intsmb_free(device_t dev); 9146651Speterstatic int intpm_probe (device_t dev); 9246651Speterstatic int intpm_attach (device_t dev); 9343166Snsouchstatic devclass_t intsmb_devclass; 9443166Snsouch 9543166Snsouchstatic device_method_t intpm_methods[]={ 9643166Snsouch DEVMETHOD(device_probe,intsmb_probe), 9743166Snsouch DEVMETHOD(device_attach,intsmb_attach), 9843166Snsouch 9949195Smdodd DEVMETHOD(bus_print_child, bus_generic_print_child), 10043166Snsouch 10143166Snsouch DEVMETHOD(smbus_callback,intsmb_callback), 10243166Snsouch DEVMETHOD(smbus_quick,intsmb_quick), 10343166Snsouch DEVMETHOD(smbus_sendb,intsmb_sendb), 10443166Snsouch DEVMETHOD(smbus_recvb,intsmb_recvb), 10543166Snsouch DEVMETHOD(smbus_writeb,intsmb_writeb), 10643166Snsouch DEVMETHOD(smbus_writew,intsmb_writew), 10743166Snsouch DEVMETHOD(smbus_readb,intsmb_readb), 10843166Snsouch DEVMETHOD(smbus_readw,intsmb_readw), 10943166Snsouch DEVMETHOD(smbus_pcall,intsmb_pcall), 11043166Snsouch DEVMETHOD(smbus_bwrite,intsmb_bwrite), 11143166Snsouch DEVMETHOD(smbus_bread,intsmb_bread), 11243166Snsouch {0,0} 11343166Snsouch}; 11443166Snsouch 11546651Speterstruct intpm_pci_softc{ 11643166Snsouch bus_space_tag_t smbst; 11743166Snsouch bus_space_handle_t smbsh; 11843166Snsouch bus_space_tag_t pmst; 11943166Snsouch bus_space_handle_t pmsh; 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); 15493023Snsouch sc->smbus=device_add_child(dev, "smbus", -1); 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 int 18043166Snsouchintsmb_callback(device_t dev, int index, caddr_t data) 18143166Snsouch{ 18243166Snsouch int error = 0; 18343166Snsouch intrmask_t s; 18443166Snsouch s=splnet(); 18543166Snsouch switch (index) { 18643166Snsouch case SMB_REQUEST_BUS: 18743166Snsouch break; 18843166Snsouch case SMB_RELEASE_BUS: 18943166Snsouch break; 19043166Snsouch default: 19143166Snsouch error = EINVAL; 19243166Snsouch } 19343166Snsouch splx(s); 19443166Snsouch return (error); 19543166Snsouch} 19643166Snsouch/*counterpart of smbtx_smb_free*/ 19743166Snsouchstatic int 19843166Snsouchintsmb_free(device_t dev){ 19946651Speter intrmask_t s; 20043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 20143166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 20243166Snsouch PIIX4_SMBHSTSTAT_BUSY) 20343166Snsouch#ifdef ENABLE_ALART 20443166Snsouch ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 20543166Snsouch PIIX4_SMBSLVSTS_BUSY) 20643166Snsouch#endif 20743166Snsouch || sc->isbusy) 20843166Snsouch return EBUSY; 20946651Speter s=splhigh(); 21043166Snsouch sc->isbusy=1; 21143166Snsouch /*Disable Intrrupt in slave part*/ 21243166Snsouch#ifndef ENABLE_ALART 21343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 21443166Snsouch#endif 21543166Snsouch /*Reset INTR Flag to prepare INTR*/ 21643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 21743166Snsouch (PIIX4_SMBHSTSTAT_INTR| 21843166Snsouch PIIX4_SMBHSTSTAT_ERR| 21943166Snsouch PIIX4_SMBHSTSTAT_BUSC| 22043166Snsouch PIIX4_SMBHSTSTAT_FAIL) 22143166Snsouch ); 22246651Speter splx(s); 22343166Snsouch return 0; 22443166Snsouch} 22543166Snsouch 22643166Snsouchstatic int 22743166Snsouchintsmb_intr(device_t dev) 22843166Snsouch{ 22943166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 23043166Snsouch int status; 23143166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 23243166Snsouch if(status&PIIX4_SMBHSTSTAT_BUSY){ 23343166Snsouch return 1; 23443166Snsouch 23543166Snsouch } 23649064Snsouch if(status&(PIIX4_SMBHSTSTAT_INTR| 23743166Snsouch PIIX4_SMBHSTSTAT_ERR| 23843166Snsouch PIIX4_SMBHSTSTAT_BUSC| 23949064Snsouch PIIX4_SMBHSTSTAT_FAIL)){ 24043166Snsouch int tmp; 24143166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 24243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 24343166Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 24449064Snsouch if(sc->isbusy){ 24549064Snsouch sc->isbusy=0; 24649064Snsouch wakeup(sc); 24749064Snsouch } 24843166Snsouch return 0; 24943166Snsouch } 25043166Snsouch return 1;/* Not Completed*/ 25143166Snsouch} 25243166Snsouchstatic int 25343166Snsouchintsmb_slvintr(device_t dev) 25443166Snsouch{ 25543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 25643166Snsouch int status,retval; 25743166Snsouch retval=1; 25843166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 25943166Snsouch if(status&PIIX4_SMBSLVSTS_BUSY) 26043166Snsouch return retval; 26143166Snsouch if(status&PIIX4_SMBSLVSTS_ALART){ 26243166Snsouch intsmb_alrintr(dev); 26343166Snsouch retval=0; 26443166Snsouch }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 26543166Snsouch |PIIX4_SMBSLVSTS_SDW1)){ 26643166Snsouch retval=0; 26743166Snsouch } 26843166Snsouch /*Reset Status Register*/ 26943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 27043166Snsouch PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 27143166Snsouch PIIX4_SMBSLVSTS_SLV); 27243166Snsouch return retval; 27343166Snsouch} 27443166Snsouch 27543166Snsouchstatic void intsmb_alrintr(device_t dev) 27643166Snsouch{ 27743166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 27843166Snsouch int slvcnt; 27943288Sdillon#ifdef ENABLE_ALART 28043288Sdillon int error; 28143288Sdillon#endif 28243288Sdillon 28343166Snsouch /*stop generating INTR from ALART*/ 28443166Snsouch slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 28543166Snsouch#ifdef ENABLE_ALART 28643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 28743166Snsouch slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 28843166Snsouch#endif 28943166Snsouch DELAY(5); 29043166Snsouch /*ask bus who assert it and then ask it what's the matter. */ 29143166Snsouch#ifdef ENABLE_ALART 29243166Snsouch error=intsmb_free(dev); 29343166Snsouch if(!error){ 29443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 29543166Snsouch |LSB); 29643166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 29743166Snsouch if(!(error=intsmb_stop_poll(dev))){ 29878255Speter u_int8_t addr; 29943166Snsouch addr=bus_space_read_1(sc->st,sc->sh, 30043166Snsouch PIIX4_SMBHSTDAT0); 30178255Speter printf("ALART_RESPONSE: 0x%x\n", addr); 30243166Snsouch } 30343166Snsouch }else{ 30443166Snsouch printf("ERROR\n"); 30543166Snsouch } 30643166Snsouch 30743166Snsouch /*Re-enable INTR from ALART*/ 30843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 30943166Snsouch slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 31043166Snsouch DELAY(5); 31143166Snsouch#endif 31243166Snsouch 31343166Snsouch return; 31443166Snsouch} 31543166Snsouchstatic void 31643166Snsouchintsmb_start(device_t dev,unsigned char cmd,int nointr) 31743166Snsouch{ 31843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 31943166Snsouch unsigned char tmp; 32043166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 32143166Snsouch tmp&= 0xe0; 32243166Snsouch tmp |= cmd; 32343166Snsouch tmp |=PIIX4_SMBHSTCNT_START; 32443166Snsouch /*While not in autoconfiguration Intrrupt Enabled*/ 32543166Snsouch if(!cold||!nointr) 32643166Snsouch tmp |=PIIX4_SMBHSTCNT_INTREN; 32743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 32843166Snsouch} 32943166Snsouch 33043166Snsouch/*Polling Code. Polling is not encouraged 33143166Snsouch * because It is required to wait for the device get busy. 33243166Snsouch *(29063505.pdf from Intel) 33343166Snsouch * But during boot,intrrupt cannot be used. 33443166Snsouch * so use polling code while in autoconfiguration. 33543166Snsouch */ 33643166Snsouch 33743166Snsouchstatic int 33843166Snsouchintsmb_stop_poll(device_t dev){ 33943166Snsouch int error,i; 34043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 34149064Snsouch 34243166Snsouch /* 34343166Snsouch * In smbtx driver ,Simply waiting. 34443166Snsouch * This loops 100-200 times. 34543166Snsouch */ 34643166Snsouch for(i=0;i<0x7fff;i++){ 34743166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 34843166Snsouch &PIIX4_SMBHSTSTAT_BUSY)){ 34943166Snsouch break; 35043166Snsouch } 35143166Snsouch } 35243166Snsouch for(i=0;i<0x7fff;i++){ 35343166Snsouch int status; 35443166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 35543166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 35643166Snsouch sc->isbusy=0; 35743166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 35843166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 35943166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 36043166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 36143166Snsouch printf("unknown cause why?"); 36243166Snsouch } 36343166Snsouch return error; 36443166Snsouch } 36543166Snsouch } 36649064Snsouch { 36749064Snsouch int tmp; 36849064Snsouch sc->isbusy=0; 36949064Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 37049064Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 37149064Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 37249064Snsouch } 37343166Snsouch return EIO; 37443166Snsouch} 37543166Snsouch/* 37643166Snsouch *wait for completion and return result. 37743166Snsouch */ 37843166Snsouchstatic int 37943166Snsouchintsmb_stop(device_t dev){ 38043166Snsouch int error; 38146651Speter intrmask_t s; 38243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 38343166Snsouch if(cold){ 38443166Snsouch /*So that it can use device during probing device on SMBus.*/ 38543166Snsouch error=intsmb_stop_poll(dev); 38643166Snsouch return error; 38743166Snsouch }else{ 38843166Snsouch if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 38943166Snsouch int status; 39043166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 39143166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 39243166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 39343166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 39443166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 39543166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 39643166Snsouch printf("intsmb%d:unknown cause why?\n", 39743166Snsouch device_get_unit(dev)); 39843166Snsouch } 39943166Snsouch#ifdef ENABLE_ALART 40043166Snsouch bus_space_write_1(sc->st,sc->sh, 40143166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 40243166Snsouch#endif 40343166Snsouch return error; 40443166Snsouch } 40543166Snsouch } 40643166Snsouch } 40743166Snsouch /*Timeout Procedure*/ 40846651Speter s=splhigh(); 40943166Snsouch sc->isbusy=0; 41043166Snsouch /*Re-enable supressed intrrupt from slave part*/ 41143166Snsouch bus_space_write_1(sc->st,sc->sh, 41243166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 41346651Speter splx(s); 41443166Snsouch return EIO; 41543166Snsouch} 41643166Snsouch 41743166Snsouchstatic int 41843166Snsouchintsmb_quick(device_t dev, u_char slave, int how) 41943166Snsouch{ 42043166Snsouch int error=0; 42143166Snsouch u_char data; 42243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 42343166Snsouch data=slave; 42443166Snsouch /*Quick command is part of Address, I think*/ 42543166Snsouch switch(how){ 42643166Snsouch case SMB_QWRITE: 42743166Snsouch data&=~LSB; 42843166Snsouch break; 42943166Snsouch case SMB_QREAD: 43043166Snsouch data|=LSB; 43143166Snsouch break; 43243166Snsouch default: 43343166Snsouch error=EINVAL; 43443166Snsouch } 43543166Snsouch if(!error){ 43643166Snsouch error=intsmb_free(dev); 43743166Snsouch if(!error){ 43843166Snsouch bus_space_write_1(sc->st,sc->sh, 43943166Snsouch PIIX4_SMBHSTADD,data); 44043166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 44143166Snsouch error=intsmb_stop(dev); 44243166Snsouch } 44343166Snsouch } 44443166Snsouch 44543166Snsouch return (error); 44643166Snsouch} 44743166Snsouch 44843166Snsouchstatic int 44943166Snsouchintsmb_sendb(device_t dev, u_char slave, char byte) 45043166Snsouch{ 45143166Snsouch int error; 45243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 45343166Snsouch error=intsmb_free(dev); 45443166Snsouch if(!error){ 45543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 45643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 45743166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 45843166Snsouch error=intsmb_stop(dev); 45943166Snsouch } 46043166Snsouch return (error); 46143166Snsouch} 46243166Snsouchstatic int 46343166Snsouchintsmb_recvb(device_t dev, u_char slave, char *byte) 46443166Snsouch{ 46543166Snsouch int error; 46643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 46743166Snsouch error=intsmb_free(dev); 46843166Snsouch if(!error){ 46943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 47043166Snsouch |LSB); 47143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 47243166Snsouch if(!(error=intsmb_stop(dev))){ 47343166Snsouch#ifdef RECV_IS_IN_CMD 47443166Snsouch /*Linux SMBus stuff also troubles 47543166Snsouch Because Intel's datasheet will not make clear. 47643166Snsouch */ 47743166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 47843166Snsouch PIIX4_SMBHSTCMD); 47943166Snsouch#else 48043166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 48143166Snsouch PIIX4_SMBHSTDAT0); 48243166Snsouch#endif 48343166Snsouch } 48443166Snsouch } 48543166Snsouch return (error); 48643166Snsouch} 48743166Snsouchstatic int 48843166Snsouchintsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 48943166Snsouch{ 49043166Snsouch int error; 49143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 49243166Snsouch error=intsmb_free(dev); 49343166Snsouch if(!error){ 49443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 49543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 49643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 49743166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 49843166Snsouch error=intsmb_stop(dev); 49943166Snsouch } 50043166Snsouch return (error); 50143166Snsouch} 50243166Snsouchstatic int 50343166Snsouchintsmb_writew(device_t dev, u_char slave, char cmd, short word) 50443166Snsouch{ 50543166Snsouch int error; 50643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 50743166Snsouch error=intsmb_free(dev); 50843166Snsouch if(!error){ 50943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 51043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 51143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 51243166Snsouch word&0xff); 51343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 51443166Snsouch (word>>8)&0xff); 51543166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 51643166Snsouch error=intsmb_stop(dev); 51743166Snsouch } 51843166Snsouch return (error); 51943166Snsouch} 52043166Snsouch 52143166Snsouchstatic int 52243166Snsouchintsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 52343166Snsouch{ 52443166Snsouch int error; 52543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 52643166Snsouch error=intsmb_free(dev); 52743166Snsouch if(!error){ 52843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 52943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 53043166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 53143166Snsouch if(!(error=intsmb_stop(dev))){ 53243166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 53343166Snsouch PIIX4_SMBHSTDAT0); 53443166Snsouch } 53543166Snsouch } 53643166Snsouch return (error); 53743166Snsouch} 53843166Snsouchstatic int 53943166Snsouchintsmb_readw(device_t dev, u_char slave, char cmd, short *word) 54043166Snsouch{ 54143166Snsouch int error; 54243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 54343166Snsouch error=intsmb_free(dev); 54443166Snsouch if(!error){ 54543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 54643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 54743166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 54843166Snsouch if(!(error=intsmb_stop(dev))){ 54943166Snsouch *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 55043166Snsouch *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 55143166Snsouch } 55243166Snsouch } 55343166Snsouch return (error); 55443166Snsouch} 55543166Snsouch/* 55643166Snsouch * Data sheet claims that it implements all function, but also claims 55743166Snsouch * that it implements 7 function and not mention PCALL. So I don't know 55843166Snsouch * whether it will work. 55943166Snsouch */ 56043166Snsouchstatic int 56143166Snsouchintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 56243166Snsouch{ 56343166Snsouch#ifdef PROCCALL_TEST 56443166Snsouch int error; 56543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 56643166Snsouch error=intsmb_free(dev); 56743166Snsouch if(!error){ 56843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 56943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 57043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 57143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 57243166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 57343166Snsouch } 57443166Snsouch if(!(error=intsmb_stop(dev))){ 57543166Snsouch *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 57643166Snsouch *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 57743166Snsouch } 57843166Snsouch return error; 57943166Snsouch#else 58043166Snsouch return 0; 58143166Snsouch#endif 58243166Snsouch} 58343166Snsouchstatic int 58443166Snsouchintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 58543166Snsouch{ 58643166Snsouch int error,i; 58743166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 58843166Snsouch error=intsmb_free(dev); 58943166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 59043166Snsouch error=EINVAL; 59143166Snsouch if(!error){ 59243166Snsouch /*Reset internal array index*/ 59343166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 59443166Snsouch 59543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 59643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 59743166Snsouch for(i=0;i<count;i++){ 59843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 59943166Snsouch } 60043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 60143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 60243166Snsouch error=intsmb_stop(dev); 60343166Snsouch } 60443166Snsouch return (error); 60543166Snsouch} 60643166Snsouch 60743166Snsouchstatic int 60843166Snsouchintsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 60943166Snsouch{ 61043166Snsouch int error,i; 61143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 61243166Snsouch error=intsmb_free(dev); 61343166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 61443166Snsouch error=EINVAL; 61543166Snsouch if(!error){ 61643166Snsouch /*Reset internal array index*/ 61743166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 61843166Snsouch 61943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 62043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 62143166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 62243166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 62343166Snsouch error=intsmb_stop(dev); 62443166Snsouch if(!error){ 62543166Snsouch bzero(buf,count);/*Is it needed?*/ 62643166Snsouch count= bus_space_read_1(sc->st,sc->sh, 62743166Snsouch PIIX4_SMBHSTDAT0); 62843166Snsouch if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 62943166Snsouch for(i=0;i<count;i++){ 63043166Snsouch buf[i]=bus_space_read_1(sc->st, 63143166Snsouch sc->sh, 63243166Snsouch PIIX4_SMBBLKDAT); 63343166Snsouch } 63443166Snsouch } 63543166Snsouch else{ 63643166Snsouch error=EIO; 63743166Snsouch } 63843166Snsouch } 63943166Snsouch } 64043166Snsouch return (error); 64143166Snsouch} 64243166Snsouch 64346651SpeterDRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 64443166Snsouch 64543166Snsouch 64692739Salfredstatic void intpm_intr(void *arg); 64746651Speterstatic int 64846651Speterintpm_attach(device_t dev) 64943166Snsouch{ 65043166Snsouch int value; 65146651Speter int unit=device_get_unit(dev); 65246651Speter void *ih; 65346651Speter int error; 65443166Snsouch char * str; 65543166Snsouch { 65643166Snsouch struct intpm_pci_softc *sciic; 65743166Snsouch device_t smbinterface; 65846651Speter int rid; 65946651Speter struct resource *res; 66046651Speter 66146651Speter sciic=device_get_softc(dev); 66243166Snsouch if(sciic==NULL){ 66346651Speter return ENOMEM; 66443166Snsouch } 66543166Snsouch 66646651Speter rid=PCI_BASE_ADDR_SMB; 66746651Speter res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid, 66846651Speter 0,~0,1,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 */ 73946651Speter return 0; 74046651Speter }else{ 74146651Speter return ENXIO; 74246651Speter } 74346651Speter} 74446651SpeterDRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 74593023SnsouchMODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 74693023SnsouchMODULE_VERSION(intpm, 1); 74746651Speter 74843166Snsouchstatic void intpm_intr(void *arg) 74943166Snsouch{ 75043166Snsouch struct intpm_pci_softc *sc; 75143166Snsouch sc=(struct intpm_pci_softc *)arg; 75243166Snsouch intsmb_intr(sc->smbus); 75343166Snsouch intsmb_slvintr(sc->smbus); 75449064Snsouch 75543166Snsouch} 756