intpm.c revision 46651
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 * 2646651Speter * $Id: intpm.c,v 1.7 1999/05/06 22:04:21 peter Exp $ 2743166Snsouch */ 2843166Snsouch 2943166Snsouch#include "pci.h" 3043166Snsouch#include "intpm.h" 3143166Snsouch 3243166Snsouch#if NPCI > 0 3343166Snsouch#if NINTPM >0 3443166Snsouch#include <sys/param.h> 3543166Snsouch#include <sys/systm.h> 3643166Snsouch#include <sys/kernel.h> 3743166Snsouch#include <machine/bus_pio.h> 3843166Snsouch#include <machine/bus_memio.h> 3943166Snsouch#include <machine/bus.h> 4043166Snsouch 4143166Snsouch#include <machine/clock.h> 4243166Snsouch#include <sys/uio.h> 4343166Snsouch#include <sys/module.h> 4443166Snsouch#include <sys/bus.h> 4543166Snsouch#include <sys/conf.h> 4643166Snsouch#include <sys/malloc.h> 4743166Snsouch#include <sys/buf.h> 4846651Speter#include <sys/rman.h> 4946651Speter#include <machine/resource.h> 5043166Snsouch#include <dev/smbus/smbconf.h> 5143166Snsouch 5243166Snsouch#include "smbus_if.h" 5343166Snsouch 5443166Snsouch/*This should be removed if force_pci_map_int supported*/ 5543166Snsouch#include <sys/interrupt.h> 5643166Snsouch 5743166Snsouch#include <pci/pcireg.h> 5843166Snsouch#include <pci/pcivar.h> 5943166Snsouch#include <pci/intpmreg.h> 6043166Snsouch 6143166Snsouch#include "opt_intpm.h" 6243166Snsouch 6343166Snsouchstatic struct _pcsid 6443166Snsouch{ 6543166Snsouch pcidi_t type; 6643166Snsouch char *desc; 6743166Snsouch} pci_ids[] = 6843166Snsouch{ 6943166Snsouch { 0x71138086,"Intel 82371AB Power management controller"}, 7043166Snsouch 7143166Snsouch { 0x00000000, NULL } 7243166Snsouch}; 7343166Snsouchstatic int intsmb_probe(device_t); 7443166Snsouchstatic int intsmb_attach(device_t); 7543166Snsouchstatic void intsmb_print_child(device_t, device_t); 7643166Snsouch 7743166Snsouchstatic int intsmb_intr(device_t dev); 7843166Snsouchstatic int intsmb_slvintr(device_t dev); 7943166Snsouchstatic void intsmb_alrintr(device_t dev); 8043166Snsouchstatic int intsmb_callback(device_t dev, int index, caddr_t data); 8143166Snsouchstatic int intsmb_quick(device_t dev, u_char slave, int how); 8243166Snsouchstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 8343166Snsouchstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 8443166Snsouchstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 8543166Snsouchstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 8643166Snsouchstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 8743166Snsouchstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 8843166Snsouchstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 8943166Snsouchstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 9043166Snsouchstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 9143166Snsouchstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 9243166Snsouchstatic int intsmb_stop(device_t dev); 9343166Snsouchstatic int intsmb_stop_poll(device_t dev); 9443166Snsouchstatic int intsmb_free(device_t dev); 9546651Speterstatic int intpm_probe (device_t dev); 9646651Speterstatic int intpm_attach (device_t dev); 9743166Snsouchstatic devclass_t intsmb_devclass; 9843166Snsouch 9943166Snsouchstatic device_method_t intpm_methods[]={ 10043166Snsouch DEVMETHOD(device_probe,intsmb_probe), 10143166Snsouch DEVMETHOD(device_attach,intsmb_attach), 10243166Snsouch 10343166Snsouch DEVMETHOD(bus_print_child, intsmb_print_child), 10443166Snsouch 10543166Snsouch DEVMETHOD(smbus_callback,intsmb_callback), 10643166Snsouch DEVMETHOD(smbus_quick,intsmb_quick), 10743166Snsouch DEVMETHOD(smbus_sendb,intsmb_sendb), 10843166Snsouch DEVMETHOD(smbus_recvb,intsmb_recvb), 10943166Snsouch DEVMETHOD(smbus_writeb,intsmb_writeb), 11043166Snsouch DEVMETHOD(smbus_writew,intsmb_writew), 11143166Snsouch DEVMETHOD(smbus_readb,intsmb_readb), 11243166Snsouch DEVMETHOD(smbus_readw,intsmb_readw), 11343166Snsouch DEVMETHOD(smbus_pcall,intsmb_pcall), 11443166Snsouch DEVMETHOD(smbus_bwrite,intsmb_bwrite), 11543166Snsouch DEVMETHOD(smbus_bread,intsmb_bread), 11643166Snsouch {0,0} 11743166Snsouch}; 11843166Snsouch 11946651Speterstruct intpm_pci_softc{ 12043166Snsouch bus_space_tag_t smbst; 12143166Snsouch bus_space_handle_t smbsh; 12243166Snsouch bus_space_tag_t pmst; 12343166Snsouch bus_space_handle_t pmsh; 12443166Snsouch pcici_t cfg; 12543166Snsouch device_t smbus; 12646651Speter}; 12743166Snsouch 12843166Snsouch 12943166Snsouchstruct intsmb_softc{ 13043166Snsouch struct intpm_pci_softc *pci_sc; 13143166Snsouch bus_space_tag_t st; 13243166Snsouch bus_space_handle_t sh; 13343166Snsouch device_t smbus; 13443166Snsouch int isbusy; 13543166Snsouch}; 13646651Speter 13743166Snsouchstatic driver_t intpm_driver = { 13843166Snsouch "intsmb", 13943166Snsouch intpm_methods, 14043166Snsouch DRIVER_TYPE_MISC, 14143166Snsouch sizeof(struct intsmb_softc), 14243166Snsouch}; 14343166Snsouch 14446651Speterstatic devclass_t intpm_devclass; 14546651Speterstatic device_method_t intpm_pci_methods[] = { 14646651Speter DEVMETHOD(device_probe,intpm_probe), 14746651Speter DEVMETHOD(device_attach,intpm_attach), 14846651Speter {0,0} 14943166Snsouch}; 15046651Speterstatic driver_t intpm_pci_driver = { 15146651Speter "intpm", 15246651Speter intpm_pci_methods, 15346651Speter DRIVER_TYPE_MISC, 15446651Speter sizeof(struct intpm_pci_softc) 15546651Speter}; 15643166Snsouch 15743166Snsouchstatic int 15843166Snsouchintsmb_probe(device_t dev) 15943166Snsouch{ 16043166Snsouch struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 16143166Snsouch sc->smbus=smbus_alloc_bus(dev); 16243166Snsouch if (!sc->smbus) 16343166Snsouch return (EINVAL); /* XXX don't know what to return else */ 16443166Snsouch device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 16543166Snsouch 16643166Snsouch return (0); /* XXX don't know what to return else */ 16743166Snsouch} 16843166Snsouchstatic int 16943166Snsouchintsmb_attach(device_t dev) 17043166Snsouch{ 17143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 17246651Speter sc->pci_sc=device_get_softc(device_get_parent(dev)); 17343166Snsouch sc->isbusy=0; 17443166Snsouch sc->sh=sc->pci_sc->smbsh; 17543166Snsouch sc->st=sc->pci_sc->smbst; 17643166Snsouch sc->pci_sc->smbus=dev; 17743166Snsouch device_probe_and_attach(sc->smbus); 17843166Snsouch#ifdef ENABLE_ALART 17943166Snsouch /*Enable Arart*/ 18043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 18143166Snsouch PIIX4_SMBSLVCNT_ALTEN); 18243166Snsouch#endif 18343166Snsouch return (0); 18443166Snsouch} 18543166Snsouch 18643166Snsouchstatic void 18743166Snsouchintsmb_print_child(device_t bus, device_t dev) 18843166Snsouch{ 18943166Snsouch printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 19043166Snsouch return; 19143166Snsouch} 19243166Snsouchstatic int 19343166Snsouchintsmb_callback(device_t dev, int index, caddr_t data) 19443166Snsouch{ 19543166Snsouch int error = 0; 19643166Snsouch intrmask_t s; 19743166Snsouch s=splnet(); 19843166Snsouch switch (index) { 19943166Snsouch case SMB_REQUEST_BUS: 20043166Snsouch break; 20143166Snsouch case SMB_RELEASE_BUS: 20243166Snsouch break; 20343166Snsouch default: 20443166Snsouch error = EINVAL; 20543166Snsouch } 20643166Snsouch splx(s); 20743166Snsouch return (error); 20843166Snsouch} 20943166Snsouch/*counterpart of smbtx_smb_free*/ 21043166Snsouchstatic int 21143166Snsouchintsmb_free(device_t dev){ 21246651Speter intrmask_t s; 21343166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 21443166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 21543166Snsouch PIIX4_SMBHSTSTAT_BUSY) 21643166Snsouch#ifdef ENABLE_ALART 21743166Snsouch ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 21843166Snsouch PIIX4_SMBSLVSTS_BUSY) 21943166Snsouch#endif 22043166Snsouch || sc->isbusy) 22143166Snsouch return EBUSY; 22246651Speter s=splhigh(); 22343166Snsouch sc->isbusy=1; 22443166Snsouch /*Disable Intrrupt in slave part*/ 22543166Snsouch#ifndef ENABLE_ALART 22643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 22743166Snsouch#endif 22843166Snsouch /*Reset INTR Flag to prepare INTR*/ 22943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 23043166Snsouch (PIIX4_SMBHSTSTAT_INTR| 23143166Snsouch PIIX4_SMBHSTSTAT_ERR| 23243166Snsouch PIIX4_SMBHSTSTAT_BUSC| 23343166Snsouch PIIX4_SMBHSTSTAT_FAIL) 23443166Snsouch ); 23546651Speter splx(s); 23643166Snsouch return 0; 23743166Snsouch} 23843166Snsouch 23943166Snsouchstatic int 24043166Snsouchintsmb_intr(device_t dev) 24143166Snsouch{ 24243166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 24343166Snsouch int status; 24443166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 24543166Snsouch if(status&PIIX4_SMBHSTSTAT_BUSY){ 24643166Snsouch return 1; 24743166Snsouch 24843166Snsouch } 24943166Snsouch if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR| 25043166Snsouch PIIX4_SMBHSTSTAT_ERR| 25143166Snsouch PIIX4_SMBHSTSTAT_BUSC| 25243166Snsouch PIIX4_SMBHSTSTAT_FAIL))){ 25343166Snsouch int tmp; 25443166Snsouch sc->isbusy=0; 25543166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 25643166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 25743166Snsouch tmp&~PIIX4_SMBHSTCNT_INTREN); 25843166Snsouch wakeup(sc); 25943166Snsouch return 0; 26043166Snsouch } 26143166Snsouch return 1;/* Not Completed*/ 26243166Snsouch} 26343166Snsouchstatic int 26443166Snsouchintsmb_slvintr(device_t dev) 26543166Snsouch{ 26643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 26743166Snsouch int status,retval; 26843166Snsouch retval=1; 26943166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 27043166Snsouch if(status&PIIX4_SMBSLVSTS_BUSY) 27143166Snsouch return retval; 27243166Snsouch if(status&PIIX4_SMBSLVSTS_ALART){ 27343166Snsouch intsmb_alrintr(dev); 27443166Snsouch retval=0; 27543166Snsouch }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 27643166Snsouch |PIIX4_SMBSLVSTS_SDW1)){ 27743166Snsouch retval=0; 27843166Snsouch } 27943166Snsouch /*Reset Status Register*/ 28043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 28143166Snsouch PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 28243166Snsouch PIIX4_SMBSLVSTS_SLV); 28343166Snsouch return retval; 28443166Snsouch} 28543166Snsouch 28643166Snsouchstatic void intsmb_alrintr(device_t dev) 28743166Snsouch{ 28843166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 28943166Snsouch int slvcnt; 29043288Sdillon#ifdef ENABLE_ALART 29143288Sdillon int error; 29243288Sdillon#endif 29343288Sdillon 29443166Snsouch /*stop generating INTR from ALART*/ 29543166Snsouch slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 29643166Snsouch#ifdef ENABLE_ALART 29743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 29843166Snsouch slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 29943166Snsouch#endif 30043166Snsouch DELAY(5); 30143166Snsouch /*ask bus who assert it and then ask it what's the matter. */ 30243166Snsouch#ifdef ENABLE_ALART 30343166Snsouch error=intsmb_free(dev); 30443166Snsouch if(!error){ 30543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 30643166Snsouch |LSB); 30743166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 30843166Snsouch if(!(error=intsmb_stop_poll(dev))){ 30943288Sdillon volatile u_int8_t *addr; 31043166Snsouch addr=bus_space_read_1(sc->st,sc->sh, 31143166Snsouch PIIX4_SMBHSTDAT0); 31243311Sdillon printf("ALART_RESPONSE: %p\n", addr); 31343166Snsouch } 31443166Snsouch }else{ 31543166Snsouch printf("ERROR\n"); 31643166Snsouch } 31743166Snsouch 31843166Snsouch /*Re-enable INTR from ALART*/ 31943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 32043166Snsouch slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 32143166Snsouch DELAY(5); 32243166Snsouch#endif 32343166Snsouch 32443166Snsouch return; 32543166Snsouch} 32643166Snsouchstatic void 32743166Snsouchintsmb_start(device_t dev,unsigned char cmd,int nointr) 32843166Snsouch{ 32943166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 33043166Snsouch unsigned char tmp; 33143166Snsouch tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 33243166Snsouch tmp&= 0xe0; 33343166Snsouch tmp |= cmd; 33443166Snsouch tmp |=PIIX4_SMBHSTCNT_START; 33543166Snsouch /*While not in autoconfiguration Intrrupt Enabled*/ 33643166Snsouch if(!cold||!nointr) 33743166Snsouch tmp |=PIIX4_SMBHSTCNT_INTREN; 33843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 33943166Snsouch} 34043166Snsouch 34143166Snsouch/*Polling Code. Polling is not encouraged 34243166Snsouch * because It is required to wait for the device get busy. 34343166Snsouch *(29063505.pdf from Intel) 34443166Snsouch * But during boot,intrrupt cannot be used. 34543166Snsouch * so use polling code while in autoconfiguration. 34643166Snsouch */ 34743166Snsouch 34843166Snsouchstatic int 34943166Snsouchintsmb_stop_poll(device_t dev){ 35043166Snsouch int error,i; 35143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 35243166Snsouch /* 35343166Snsouch * In smbtx driver ,Simply waiting. 35443166Snsouch * This loops 100-200 times. 35543166Snsouch */ 35643166Snsouch for(i=0;i<0x7fff;i++){ 35743166Snsouch if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 35843166Snsouch &PIIX4_SMBHSTSTAT_BUSY)){ 35943166Snsouch break; 36043166Snsouch } 36143166Snsouch } 36243166Snsouch for(i=0;i<0x7fff;i++){ 36343166Snsouch int status; 36443166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 36543166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 36643166Snsouch sc->isbusy=0; 36743166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 36843166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 36943166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 37043166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 37143166Snsouch printf("unknown cause why?"); 37243166Snsouch } 37343166Snsouch return error; 37443166Snsouch } 37543166Snsouch } 37643166Snsouch sc->isbusy=0; 37743166Snsouch return EIO; 37843166Snsouch} 37943166Snsouch/* 38043166Snsouch *wait for completion and return result. 38143166Snsouch */ 38243166Snsouchstatic int 38343166Snsouchintsmb_stop(device_t dev){ 38443166Snsouch int error; 38546651Speter intrmask_t s; 38643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 38743166Snsouch if(cold){ 38843166Snsouch /*So that it can use device during probing device on SMBus.*/ 38943166Snsouch error=intsmb_stop_poll(dev); 39043166Snsouch return error; 39143166Snsouch }else{ 39243166Snsouch if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 39343166Snsouch int status; 39443166Snsouch status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 39543166Snsouch if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 39643166Snsouch error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 39743166Snsouch (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 39843166Snsouch (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 39943166Snsouch if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 40043166Snsouch printf("intsmb%d:unknown cause why?\n", 40143166Snsouch device_get_unit(dev)); 40243166Snsouch } 40343166Snsouch#ifdef ENABLE_ALART 40443166Snsouch bus_space_write_1(sc->st,sc->sh, 40543166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 40643166Snsouch#endif 40743166Snsouch return error; 40843166Snsouch } 40943166Snsouch } 41043166Snsouch } 41143166Snsouch /*Timeout Procedure*/ 41246651Speter s=splhigh(); 41343166Snsouch sc->isbusy=0; 41443166Snsouch /*Re-enable supressed intrrupt from slave part*/ 41543166Snsouch bus_space_write_1(sc->st,sc->sh, 41643166Snsouch PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 41746651Speter splx(s); 41843166Snsouch return EIO; 41943166Snsouch} 42043166Snsouch 42143166Snsouchstatic int 42243166Snsouchintsmb_quick(device_t dev, u_char slave, int how) 42343166Snsouch{ 42443166Snsouch int error=0; 42543166Snsouch u_char data; 42643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 42743166Snsouch data=slave; 42843166Snsouch /*Quick command is part of Address, I think*/ 42943166Snsouch switch(how){ 43043166Snsouch case SMB_QWRITE: 43143166Snsouch data&=~LSB; 43243166Snsouch break; 43343166Snsouch case SMB_QREAD: 43443166Snsouch data|=LSB; 43543166Snsouch break; 43643166Snsouch default: 43743166Snsouch error=EINVAL; 43843166Snsouch } 43943166Snsouch if(!error){ 44043166Snsouch error=intsmb_free(dev); 44143166Snsouch if(!error){ 44243166Snsouch bus_space_write_1(sc->st,sc->sh, 44343166Snsouch PIIX4_SMBHSTADD,data); 44443166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 44543166Snsouch error=intsmb_stop(dev); 44643166Snsouch } 44743166Snsouch } 44843166Snsouch 44943166Snsouch return (error); 45043166Snsouch} 45143166Snsouch 45243166Snsouchstatic int 45343166Snsouchintsmb_sendb(device_t dev, u_char slave, char byte) 45443166Snsouch{ 45543166Snsouch int error; 45643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 45743166Snsouch error=intsmb_free(dev); 45843166Snsouch if(!error){ 45943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 46043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 46143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 46243166Snsouch error=intsmb_stop(dev); 46343166Snsouch } 46443166Snsouch return (error); 46543166Snsouch} 46643166Snsouchstatic int 46743166Snsouchintsmb_recvb(device_t dev, u_char slave, char *byte) 46843166Snsouch{ 46943166Snsouch int error; 47043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 47143166Snsouch error=intsmb_free(dev); 47243166Snsouch if(!error){ 47343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 47443166Snsouch |LSB); 47543166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 47643166Snsouch if(!(error=intsmb_stop(dev))){ 47743166Snsouch#ifdef RECV_IS_IN_CMD 47843166Snsouch /*Linux SMBus stuff also troubles 47943166Snsouch Because Intel's datasheet will not make clear. 48043166Snsouch */ 48143166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 48243166Snsouch PIIX4_SMBHSTCMD); 48343166Snsouch#else 48443166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 48543166Snsouch PIIX4_SMBHSTDAT0); 48643166Snsouch#endif 48743166Snsouch } 48843166Snsouch } 48943166Snsouch return (error); 49043166Snsouch} 49143166Snsouchstatic int 49243166Snsouchintsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 49343166Snsouch{ 49443166Snsouch int error; 49543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 49643166Snsouch error=intsmb_free(dev); 49743166Snsouch if(!error){ 49843166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 49943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 50043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 50143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 50243166Snsouch error=intsmb_stop(dev); 50343166Snsouch } 50443166Snsouch return (error); 50543166Snsouch} 50643166Snsouchstatic int 50743166Snsouchintsmb_writew(device_t dev, u_char slave, char cmd, short word) 50843166Snsouch{ 50943166Snsouch int error; 51043166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 51143166Snsouch error=intsmb_free(dev); 51243166Snsouch if(!error){ 51343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 51443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 51543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 51643166Snsouch word&0xff); 51743166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 51843166Snsouch (word>>8)&0xff); 51943166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 52043166Snsouch error=intsmb_stop(dev); 52143166Snsouch } 52243166Snsouch return (error); 52343166Snsouch} 52443166Snsouch 52543166Snsouchstatic int 52643166Snsouchintsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 52743166Snsouch{ 52843166Snsouch int error; 52943166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 53043166Snsouch error=intsmb_free(dev); 53143166Snsouch if(!error){ 53243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 53343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 53443166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 53543166Snsouch if(!(error=intsmb_stop(dev))){ 53643166Snsouch *byte=bus_space_read_1(sc->st,sc->sh, 53743166Snsouch PIIX4_SMBHSTDAT0); 53843166Snsouch } 53943166Snsouch } 54043166Snsouch return (error); 54143166Snsouch} 54243166Snsouchstatic int 54343166Snsouchintsmb_readw(device_t dev, u_char slave, char cmd, short *word) 54443166Snsouch{ 54543166Snsouch int error; 54643166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 54743166Snsouch error=intsmb_free(dev); 54843166Snsouch if(!error){ 54943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 55043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 55143166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 55243166Snsouch if(!(error=intsmb_stop(dev))){ 55343166Snsouch *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 55443166Snsouch *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 55543166Snsouch } 55643166Snsouch } 55743166Snsouch return (error); 55843166Snsouch} 55943166Snsouch/* 56043166Snsouch * Data sheet claims that it implements all function, but also claims 56143166Snsouch * that it implements 7 function and not mention PCALL. So I don't know 56243166Snsouch * whether it will work. 56343166Snsouch */ 56443166Snsouchstatic int 56543166Snsouchintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 56643166Snsouch{ 56743166Snsouch#ifdef PROCCALL_TEST 56843166Snsouch int error; 56943166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 57043166Snsouch error=intsmb_free(dev); 57143166Snsouch if(!error){ 57243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 57343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 57443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 57543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 57643166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 57743166Snsouch } 57843166Snsouch if(!(error=intsmb_stop(dev))){ 57943166Snsouch *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 58043166Snsouch *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 58143166Snsouch } 58243166Snsouch return error; 58343166Snsouch#else 58443166Snsouch return 0; 58543166Snsouch#endif 58643166Snsouch} 58743166Snsouchstatic int 58843166Snsouchintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 58943166Snsouch{ 59043166Snsouch int error,i; 59143166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 59243166Snsouch error=intsmb_free(dev); 59343166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 59443166Snsouch error=EINVAL; 59543166Snsouch if(!error){ 59643166Snsouch /*Reset internal array index*/ 59743166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 59843166Snsouch 59943166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 60043166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 60143166Snsouch for(i=0;i<count;i++){ 60243166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 60343166Snsouch } 60443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 60543166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 60643166Snsouch error=intsmb_stop(dev); 60743166Snsouch } 60843166Snsouch return (error); 60943166Snsouch} 61043166Snsouch 61143166Snsouchstatic int 61243166Snsouchintsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 61343166Snsouch{ 61443166Snsouch int error,i; 61543166Snsouch struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 61643166Snsouch error=intsmb_free(dev); 61743166Snsouch if(count>SMBBLOCKTRANS_MAX||count==0) 61843166Snsouch error=EINVAL; 61943166Snsouch if(!error){ 62043166Snsouch /*Reset internal array index*/ 62143166Snsouch bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 62243166Snsouch 62343166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 62443166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 62543166Snsouch bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 62643166Snsouch intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 62743166Snsouch error=intsmb_stop(dev); 62843166Snsouch if(!error){ 62943166Snsouch bzero(buf,count);/*Is it needed?*/ 63043166Snsouch count= bus_space_read_1(sc->st,sc->sh, 63143166Snsouch PIIX4_SMBHSTDAT0); 63243166Snsouch if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 63343166Snsouch for(i=0;i<count;i++){ 63443166Snsouch buf[i]=bus_space_read_1(sc->st, 63543166Snsouch sc->sh, 63643166Snsouch PIIX4_SMBBLKDAT); 63743166Snsouch } 63843166Snsouch } 63943166Snsouch else{ 64043166Snsouch error=EIO; 64143166Snsouch } 64243166Snsouch } 64343166Snsouch } 64443166Snsouch return (error); 64543166Snsouch} 64643166Snsouch 64746651SpeterDRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 64843166Snsouch 64943166Snsouch 65043166Snsouchstatic void intpm_intr __P((void *arg)); 65146651Speterstatic int 65246651Speterintpm_attach(device_t dev) 65343166Snsouch{ 65443166Snsouch int value; 65546651Speter int unit=device_get_unit(dev); 65646651Speter void *ih; 65746651Speter int error; 65843166Snsouch char * str; 65943166Snsouch { 66043166Snsouch struct intpm_pci_softc *sciic; 66143166Snsouch device_t smbinterface; 66246651Speter int rid; 66346651Speter struct resource *res; 66446651Speter 66546651Speter sciic=device_get_softc(dev); 66643166Snsouch if(sciic==NULL){ 66746651Speter return ENOMEM; 66843166Snsouch } 66943166Snsouch 67046651Speter rid=PCI_BASE_ADDR_SMB; 67146651Speter#if 0 67246651Speter res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid, 67346651Speter 0,~0,1,RF_ACTIVE); 67446651Speter if(res==NULL){ 67546651Speter device_printf(dev,"IO FAILED Trying Memory\n"); 67646651Speter res=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0, 67746651Speter 1,RF_ACTIVE); 67846651Speter } 67946651Speter#else 68046651Speter /*Do as I tell!*/ 68146651Speter value=pci_read_config(dev,rid,4); 68246651Speter res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,value&(~1), 68346651Speter (value&(~1))+256,256,RF_ACTIVE); 68446651Speter#endif 68546651Speter if(res==NULL){ 68646651Speter device_printf(dev,"Could not allocate Bus space\n"); 68746651Speter return ENXIO; 68846651Speter } 68946651Speter sciic->smbst=rman_get_bustag(res); 69046651Speter sciic->smbsh=rman_get_bushandle(res); 69146651Speter 69246651Speter device_printf(dev,"%s %x\n", 69346651Speter (sciic->smbst==I386_BUS_SPACE_IO)? 69446651Speter "I/O mapped":"Memory", 69546651Speter sciic->smbsh); 69646651Speter 69743166Snsouch 69843166Snsouch#ifndef NO_CHANGE_PCICONF 69946651Speter pci_write_config(dev,PCIR_INTLINE,0x9,1); 70046651Speter pci_write_config(dev,PCI_HST_CFG_SMB, 70146651Speter PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 70243166Snsouch#endif 70346651Speter value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 70443166Snsouch switch(value&0xe){ 70543166Snsouch case PCI_INTR_SMB_SMI: 70646651Speter str="SMI"; 70743166Snsouch break; 70843166Snsouch case PCI_INTR_SMB_IRQ9: 70943166Snsouch str="IRQ 9"; 71043166Snsouch break; 71143166Snsouch default: 71243166Snsouch str="BOGUS"; 71343166Snsouch } 71446651Speter device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 71546651Speter value=pci_read_config(dev,PCI_REVID_SMB,1); 71643166Snsouch printf("revision %d\n",value); 71743166Snsouch /* 71843166Snsouch * Install intr HANDLER here 71943166Snsouch */ 72046651Speter rid=0; 72146651Speter res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 72246651Speter if(res==NULL){ 72346651Speter device_printf(dev,"could not allocate irq"); 72446651Speter return ENOMEM; 72546651Speter } 72646651Speter error=bus_setup_intr(dev,res,(driver_intr_t *) intpm_intr,sciic,&ih); 72746651Speter if(error){ 72846651Speter device_printf(dev,"Failed to map intr\n"); 72946651Speter return error; 73043166Snsouch } 73146651Speter smbinterface=device_add_child(dev,"intsmb",unit,NULL); 73246651Speter if(!smbinterface){ 73346651Speter printf("intsmb%d:could not add SMBus device\n",unit); 73446651Speter } 73543166Snsouch device_probe_and_attach(smbinterface); 73643166Snsouch } 73746651Speter 73846651Speter value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 73943166Snsouch printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 74046651Speter return 0; 74143166Snsouch} 74246651Speterstatic int 74346651Speterintpm_probe(device_t dev) 74446651Speter{ 74546651Speter struct _pcsid *ep =pci_ids; 74646651Speter u_int32_t device_id=pci_get_devid(dev); 74746651Speter while (ep->type && ep->type != device_id) 74846651Speter ++ep; 74946651Speter if(ep->desc!=NULL){ 75046651Speter device_set_desc(dev,ep->desc); 75146651Speter return 0; 75246651Speter }else{ 75346651Speter return ENXIO; 75446651Speter } 75546651Speter} 75646651SpeterDRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 75746651Speter 75843166Snsouchstatic void intpm_intr(void *arg) 75943166Snsouch{ 76043166Snsouch struct intpm_pci_softc *sc; 76143166Snsouch sc=(struct intpm_pci_softc *)arg; 76243166Snsouch intsmb_intr(sc->smbus); 76343166Snsouch intsmb_slvintr(sc->smbus); 76443166Snsouch} 76543166Snsouch#endif /* NPCI > 0 */ 76643166Snsouch#endif 767