intpm.c revision 74285
162587Sitojun/*- 295023Ssuz * Copyright (c) 1998, 1999 Takanori Watanabe 362587Sitojun * All rights reserved. 4139823Simp * 554263Sshin * Redistribution and use in source and binary forms, with or without 654263Sshin * modification, are permitted provided that the following conditions 754263Sshin * are met: 854263Sshin * 1. Redistributions of source code must retain the above copyright 954263Sshin * notice, this list of conditions and the following disclaimer. 1054263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1154263Sshin * notice, this list of conditions and the following disclaimer in the 1254263Sshin * documentation and/or other materials provided with the distribution. 1354263Sshin * 1454263Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1554263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1654263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1754263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1854263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1954263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2054263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2154263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2254263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2354263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2454263Sshin * SUCH DAMAGE. 2554263Sshin * 2654263Sshin * $FreeBSD: head/sys/pci/intpm.c 74285 2001-03-15 06:56:51Z peter $ 2754263Sshin */ 2854263Sshin 2954263Sshin#include <sys/param.h> 3054263Sshin#include <sys/systm.h> 3154263Sshin#include <sys/kernel.h> 3254263Sshin#include <machine/bus_pio.h> 3354263Sshin#include <machine/bus_memio.h> 3454263Sshin#include <machine/bus.h> 35101739Srwatson 3654263Sshin#include <sys/uio.h> 3754263Sshin#include <sys/module.h> 3854263Sshin#include <sys/bus.h> 3954263Sshin#include <sys/rman.h> 40101182Srwatson#include <machine/resource.h> 4154263Sshin#include <dev/smbus/smbconf.h> 4254263Sshin 43129880Sphk#include "smbus_if.h" 4454263Sshin 4554263Sshin/*This should be removed if force_pci_map_int supported*/ 4654263Sshin#include <sys/interrupt.h> 4754263Sshin 4891270Sbrooks#include <pci/pcireg.h> 4954263Sshin#include <pci/pcivar.h> 5062587Sitojun#include <pci/intpmreg.h> 5179106Sbrooks 5254263Sshin#include "opt_intpm.h" 5354263Sshin 5454263Sshinstatic struct _pcsid 55130933Sbrooks{ 5654263Sshin u_int32_t type; 5754263Sshin char *desc; 5854263Sshin} pci_ids[] = 5954263Sshin{ 6054263Sshin { 0x71138086,"Intel 82371AB Power management controller"}, 6154263Sshin#if 0 6254263Sshin /* Not a good idea yet, this stops isab0 functioning */ 6378064Sume { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"}, 6478064Sume#endif 6554263Sshin 6654263Sshin { 0x00000000, NULL } 6779106Sbrooks}; 6854263Sshinstatic int intsmb_probe(device_t); 6954263Sshinstatic int intsmb_attach(device_t); 7054263Sshin 7154263Sshinstatic int intsmb_intr(device_t dev); 7254263Sshinstatic int intsmb_slvintr(device_t dev); 7354263Sshinstatic void intsmb_alrintr(device_t dev); 7454263Sshinstatic int intsmb_callback(device_t dev, int index, caddr_t data); 7554263Sshinstatic int intsmb_quick(device_t dev, u_char slave, int how); 7654263Sshinstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 77148385Sumestatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 7854263Sshinstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 7962587Sitojunstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 8054263Sshinstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 8154263Sshinstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 8262587Sitojunstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 83153621Sthompsastatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 84153621Sthompsastatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8554263Sshinstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 8654263Sshinstatic int intsmb_stop(device_t dev); 8754263Sshinstatic int intsmb_stop_poll(device_t dev); 8854263Sshinstatic int intsmb_free(device_t dev); 8979106Sbrooksstatic int intpm_probe (device_t dev); 9062587Sitojunstatic int intpm_attach (device_t dev); 91127305Srwatsonstatic devclass_t intsmb_devclass; 92127898Sru 93127305Srwatsonstatic device_method_t intpm_methods[]={ 94127305Srwatson DEVMETHOD(device_probe,intsmb_probe), 9579106Sbrooks DEVMETHOD(device_attach,intsmb_attach), 9689065Smsmith 9779106Sbrooks DEVMETHOD(bus_print_child, bus_generic_print_child), 9883998Sbrooks 9983998Sbrooks DEVMETHOD(smbus_callback,intsmb_callback), 10083998Sbrooks DEVMETHOD(smbus_quick,intsmb_quick), 10183998Sbrooks DEVMETHOD(smbus_sendb,intsmb_sendb), 10283998Sbrooks DEVMETHOD(smbus_recvb,intsmb_recvb), 103153621Sthompsa DEVMETHOD(smbus_writeb,intsmb_writeb), 104128209Sbrooks DEVMETHOD(smbus_writew,intsmb_writew), 105128209Sbrooks DEVMETHOD(smbus_readb,intsmb_readb), 10679106Sbrooks DEVMETHOD(smbus_readw,intsmb_readw), 107130933Sbrooks DEVMETHOD(smbus_pcall,intsmb_pcall), 10879106Sbrooks DEVMETHOD(smbus_bwrite,intsmb_bwrite), 10992725Salfred DEVMETHOD(smbus_bread,intsmb_bread), 11079106Sbrooks {0,0} 11191270Sbrooks}; 11291270Sbrooks 11391270Sbrooksstruct intpm_pci_softc{ 11462587Sitojun bus_space_tag_t smbst; 11562587Sitojun bus_space_handle_t smbsh; 11691270Sbrooks bus_space_tag_t pmst; 11762587Sitojun bus_space_handle_t pmsh; 11862587Sitojun device_t smbus; 11962587Sitojun}; 12095023Ssuz 12162587Sitojun 12262587Sitojunstruct intsmb_softc{ 12362587Sitojun struct intpm_pci_softc *pci_sc; 12462587Sitojun bus_space_tag_t st; 12562587Sitojun bus_space_handle_t sh; 12691270Sbrooks device_t smbus; 12791270Sbrooks int isbusy; 12862587Sitojun}; 12991270Sbrooks 13091270Sbrooksstatic driver_t intpm_driver = { 13191270Sbrooks "intsmb", 13291270Sbrooks intpm_methods, 13391270Sbrooks sizeof(struct intsmb_softc), 13491270Sbrooks}; 13591270Sbrooks 13691270Sbrooksstatic devclass_t intpm_devclass; 13791270Sbrooksstatic device_method_t intpm_pci_methods[] = { 13891270Sbrooks DEVMETHOD(device_probe,intpm_probe), 13991270Sbrooks DEVMETHOD(device_attach,intpm_attach), 14091270Sbrooks {0,0} 14191270Sbrooks}; 142128209Sbrooksstatic driver_t intpm_pci_driver = { 14379106Sbrooks "intpm", 14479106Sbrooks intpm_pci_methods, 14592081Smux sizeof(struct intpm_pci_softc) 14654263Sshin}; 14778064Sume 14854263Sshinstatic int 149131672Sbmsintsmb_probe(device_t dev) 150147256Sbrooks{ 151147256Sbrooks struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 152147256Sbrooks sc->smbus=smbus_alloc_bus(dev); 153147256Sbrooks if (!sc->smbus) 154147256Sbrooks return (EINVAL); /* XXX don't know what to return else */ 15579106Sbrooks device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 156155037Sglebius 157155037Sglebius return (0); /* XXX don't know what to return else */ 158147256Sbrooks} 159147256Sbrooksstatic int 16079106Sbrooksintsmb_attach(device_t dev) 16179106Sbrooks{ 16262587Sitojun struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 163147256Sbrooks sc->pci_sc=device_get_softc(device_get_parent(dev)); 164147256Sbrooks sc->isbusy=0; 165147256Sbrooks sc->sh=sc->pci_sc->smbsh; 16678064Sume sc->st=sc->pci_sc->smbst; 16779106Sbrooks sc->pci_sc->smbus=dev; 168147256Sbrooks device_probe_and_attach(sc->smbus); 16978064Sume#ifdef ENABLE_ALART 170147256Sbrooks /*Enable Arart*/ 171153621Sthompsa bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 172147256Sbrooks PIIX4_SMBSLVCNT_ALTEN); 173147256Sbrooks#endif 174147256Sbrooks return (0); 175147611Sdwmalone} 17683998Sbrooks 177147256Sbrooksstatic int 178155037Sglebiusintsmb_callback(device_t dev, int index, caddr_t data) 179155037Sglebius{ 180155037Sglebius int error = 0; 181155037Sglebius intrmask_t s; 182155037Sglebius s=splnet(); 183155037Sglebius switch (index) { 18479106Sbrooks case SMB_REQUEST_BUS: 18579106Sbrooks break; 186127305Srwatson case SMB_RELEASE_BUS: 187151266Sthompsa break; 188151266Sthompsa default: 18979106Sbrooks error = EINVAL; 19079106Sbrooks } 191151266Sthompsa splx(s); 19279106Sbrooks return (error); 193151266Sthompsa} 194151266Sthompsa/*counterpart of smbtx_smb_free*/ 195151266Sthompsastatic int 196151266Sthompsaintsmb_free(device_t dev){ 197127305Srwatson intrmask_t s; 198105293Sume struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 199105293Sume if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 200105293Sume PIIX4_SMBHSTSTAT_BUSY) 201105293Sume#ifdef ENABLE_ALART 202105293Sume ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 203105293Sume PIIX4_SMBSLVSTS_BUSY) 204105293Sume#endif 20579106Sbrooks || sc->isbusy) 20679106Sbrooks return EBUSY; 20779106Sbrooks s=splhigh(); 20879106Sbrooks sc->isbusy=1; 209105293Sume /*Disable Intrrupt in slave part*/ 21079106Sbrooks#ifndef ENABLE_ALART 21183998Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 21283998Sbrooks#endif 21379106Sbrooks /*Reset INTR Flag to prepare INTR*/ 21479106Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 215147256Sbrooks (PIIX4_SMBHSTSTAT_INTR| 21679106Sbrooks PIIX4_SMBHSTSTAT_ERR| 217155037Sglebius PIIX4_SMBHSTSTAT_BUSC| 218155037Sglebius PIIX4_SMBHSTSTAT_FAIL) 21979106Sbrooks ); 22079106Sbrooks splx(s); 22179106Sbrooks return 0; 22279106Sbrooks} 22379106Sbrooks 22479106Sbrooksstatic int 22579106Sbrooksintsmb_intr(device_t dev) 22679106Sbrooks{ 22779106Sbrooks struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 22879106Sbrooks int status; 22979106Sbrooks status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 23079106Sbrooks if(status&PIIX4_SMBHSTSTAT_BUSY){ 231127305Srwatson return 1; 23283997Sbrooks 23379106Sbrooks } 23479106Sbrooks if(status&(PIIX4_SMBHSTSTAT_INTR| 23579106Sbrooks PIIX4_SMBHSTSTAT_ERR| 23679106Sbrooks PIIX4_SMBHSTSTAT_BUSC| 23762587Sitojun PIIX4_SMBHSTSTAT_FAIL)){ 23879106Sbrooks int tmp; 23979106Sbrooks tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 24079106Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 24179106Sbrooks tmp&~PIIX4_SMBHSTCNT_INTREN); 242127305Srwatson if(sc->isbusy){ 24379106Sbrooks sc->isbusy=0; 24479106Sbrooks wakeup(sc); 24562587Sitojun } 24679106Sbrooks return 0; 247132199Sphk } 248132199Sphk return 1;/* Not Completed*/ 24954263Sshin} 25079106Sbrooksstatic int 25154263Sshinintsmb_slvintr(device_t dev) 25254263Sshin{ 25379106Sbrooks struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 25479106Sbrooks int status,retval; 25579106Sbrooks retval=1; 25679106Sbrooks status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 25779106Sbrooks if(status&PIIX4_SMBSLVSTS_BUSY) 25854263Sshin return retval; 25979106Sbrooks if(status&PIIX4_SMBSLVSTS_ALART){ 26083997Sbrooks intsmb_alrintr(dev); 26179106Sbrooks retval=0; 262105293Sume }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 26362587Sitojun |PIIX4_SMBSLVSTS_SDW1)){ 26462587Sitojun retval=0; 26562587Sitojun } 26662587Sitojun /*Reset Status Register*/ 26762587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 26862587Sitojun PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 26962587Sitojun PIIX4_SMBSLVSTS_SLV); 27062587Sitojun return retval; 27162587Sitojun} 27262587Sitojun 27362587Sitojunstatic void intsmb_alrintr(device_t dev) 27462587Sitojun{ 27562587Sitojun struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 276147256Sbrooks int slvcnt; 27762587Sitojun#ifdef ENABLE_ALART 27862587Sitojun int error; 27962587Sitojun#endif 28062587Sitojun 28162587Sitojun /*stop generating INTR from ALART*/ 28262587Sitojun slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 28362587Sitojun#ifdef ENABLE_ALART 28462587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 28562587Sitojun slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 28662587Sitojun#endif 28762587Sitojun DELAY(5); 28862587Sitojun /*ask bus who assert it and then ask it what's the matter. */ 28962587Sitojun#ifdef ENABLE_ALART 29062587Sitojun error=intsmb_free(dev); 29162587Sitojun if(!error){ 292153621Sthompsa bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 293153621Sthompsa |LSB); 294153621Sthompsa intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 29562587Sitojun if(!(error=intsmb_stop_poll(dev))){ 29662587Sitojun volatile u_int8_t *addr; 29762587Sitojun addr=bus_space_read_1(sc->st,sc->sh, 29862587Sitojun PIIX4_SMBHSTDAT0); 299105339Sume printf("ALART_RESPONSE: %p\n", addr); 300105339Sume } 301105339Sume }else{ 302105339Sume printf("ERROR\n"); 30391327Sbrooks } 30462587Sitojun 30562587Sitojun /*Re-enable INTR from ALART*/ 30662587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 30762587Sitojun slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 30862587Sitojun DELAY(5); 30962587Sitojun#endif 31062587Sitojun 31162587Sitojun return; 31262587Sitojun} 31362587Sitojunstatic void 31462587Sitojunintsmb_start(device_t dev,unsigned char cmd,int nointr) 315105293Sume{ 316105293Sume struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 31762587Sitojun unsigned char tmp; 31862587Sitojun tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 31962587Sitojun tmp&= 0xe0; 32062587Sitojun tmp |= cmd; 32162587Sitojun tmp |=PIIX4_SMBHSTCNT_START; 32262587Sitojun /*While not in autoconfiguration Intrrupt Enabled*/ 32362587Sitojun if(!cold||!nointr) 32462587Sitojun tmp |=PIIX4_SMBHSTCNT_INTREN; 32562587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 32662587Sitojun} 327153621Sthompsa 328153621Sthompsa/*Polling Code. Polling is not encouraged 329153621Sthompsa * because It is required to wait for the device get busy. 330153621Sthompsa *(29063505.pdf from Intel) 331153621Sthompsa * But during boot,intrrupt cannot be used. 332153621Sthompsa * so use polling code while in autoconfiguration. 333153621Sthompsa */ 334153621Sthompsa 335153621Sthompsastatic int 336153621Sthompsaintsmb_stop_poll(device_t dev){ 337153621Sthompsa int error,i; 338153621Sthompsa struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 339153621Sthompsa 340153621Sthompsa /* 341153621Sthompsa * In smbtx driver ,Simply waiting. 342153621Sthompsa * This loops 100-200 times. 343153621Sthompsa */ 344153621Sthompsa for(i=0;i<0x7fff;i++){ 345153621Sthompsa if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 346153621Sthompsa &PIIX4_SMBHSTSTAT_BUSY)){ 347153621Sthompsa break; 348153621Sthompsa } 34954263Sshin } 35054263Sshin for(i=0;i<0x7fff;i++){ 35154263Sshin int status; 35254263Sshin status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 35354263Sshin if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 35454263Sshin sc->isbusy=0; 35554263Sshin error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 356147256Sbrooks (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 357127898Sru (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 35854263Sshin if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 359127898Sru printf("unknown cause why?"); 360147611Sdwmalone } 36154263Sshin return error; 362101182Srwatson } 363101182Srwatson } 364101739Srwatson { 365101739Srwatson int tmp; 366101739Srwatson sc->isbusy=0; 367101739Srwatson tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 368101182Srwatson bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 369101182Srwatson tmp&~PIIX4_SMBHSTCNT_INTREN); 37054263Sshin } 37154263Sshin return EIO; 372127898Sru} 373127898Sru/* 374127898Sru *wait for completion and return result. 37554263Sshin */ 37654263Sshinstatic int 377127898Sruintsmb_stop(device_t dev){ 378127898Sru int error; 379127898Sru intrmask_t s; 380127898Sru struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 381127898Sru if(cold){ 382127898Sru /*So that it can use device during probing device on SMBus.*/ 383127898Sru error=intsmb_stop_poll(dev); 384127898Sru return error; 385127898Sru }else{ 386127898Sru if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 387127898Sru int status; 388127898Sru status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 389127898Sru if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 390127898Sru error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 391127898Sru (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 39254263Sshin (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 39354263Sshin if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 394127303Srwatson printf("intsmb%d:unknown cause why?\n", 39554263Sshin device_get_unit(dev)); 39654263Sshin } 39754263Sshin#ifdef ENABLE_ALART 39854263Sshin bus_space_write_1(sc->st,sc->sh, 399127898Sru PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 400127898Sru#endif 401127898Sru return error; 402127898Sru } 403127898Sru } 404127898Sru } 405127898Sru /*Timeout Procedure*/ 406127898Sru s=splhigh(); 407127898Sru sc->isbusy=0; 40862587Sitojun /*Re-enable supressed intrrupt from slave part*/ 40954263Sshin bus_space_write_1(sc->st,sc->sh, 410155037Sglebius PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 411155037Sglebius splx(s); 412155037Sglebius return EIO; 41354263Sshin} 41454263Sshin 415159174Sglebiusstatic int 41654263Sshinintsmb_quick(device_t dev, u_char slave, int how) 41754263Sshin{ 41854263Sshin int error=0; 41954263Sshin u_char data; 42054263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 421147611Sdwmalone data=slave; 422147611Sdwmalone /*Quick command is part of Address, I think*/ 423147611Sdwmalone switch(how){ 424147611Sdwmalone case SMB_QWRITE: 425147611Sdwmalone data&=~LSB; 426147611Sdwmalone break; 427153621Sthompsa case SMB_QREAD: 428159180Scsjp data|=LSB; 42962587Sitojun break; 43054263Sshin default: 43154263Sshin error=EINVAL; 432153621Sthompsa } 433153621Sthompsa if(!error){ 434153621Sthompsa error=intsmb_free(dev); 435153621Sthompsa if(!error){ 43678064Sume bus_space_write_1(sc->st,sc->sh, 43778064Sume PIIX4_SMBHSTADD,data); 43862587Sitojun intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 43962587Sitojun error=intsmb_stop(dev); 44078064Sume } 44154263Sshin } 44254263Sshin 44354263Sshin return (error); 444153621Sthompsa} 44554263Sshin 44654263Sshinstatic int 44754263Sshinintsmb_sendb(device_t dev, u_char slave, char byte) 44854263Sshin{ 449153621Sthompsa int error; 45054263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 45154263Sshin error=intsmb_free(dev); 45254263Sshin if(!error){ 45362587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 45454263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 45554263Sshin intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 45654263Sshin error=intsmb_stop(dev); 457159174Sglebius } 45854263Sshin return (error); 45978064Sume} 46078064Sumestatic int 461155037Sglebiusintsmb_recvb(device_t dev, u_char slave, char *byte) 46254263Sshin{ 46354263Sshin int error; 46454263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 465105338Sume error=intsmb_free(dev); 46654263Sshin if(!error){ 46754263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 468105338Sume |LSB); 46954263Sshin intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 470153621Sthompsa if(!(error=intsmb_stop(dev))){ 471153621Sthompsa#ifdef RECV_IS_IN_CMD 47254263Sshin /*Linux SMBus stuff also troubles 473105338Sume Because Intel's datasheet will not make clear. 47454263Sshin */ 47554263Sshin *byte=bus_space_read_1(sc->st,sc->sh, 47654263Sshin PIIX4_SMBHSTCMD); 47754263Sshin#else 47854263Sshin *byte=bus_space_read_1(sc->st,sc->sh, 479105338Sume PIIX4_SMBHSTDAT0); 480101182Srwatson#endif 481101182Srwatson } 482105338Sume } 483101182Srwatson return (error); 484101182Srwatson} 485159180Scsjpstatic int 48678064Sumeintsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 487123922Ssam{ 48854263Sshin int error; 48954263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 49083998Sbrooks error=intsmb_free(dev); 491105338Sume if(!error){ 49283998Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 49383998Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 49483998Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 49583998Sbrooks intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 49654263Sshin error=intsmb_stop(dev); 49754263Sshin } 49854263Sshin return (error); 49954263Sshin} 50095023Ssuzstatic int 50154263Sshinintsmb_writew(device_t dev, u_char slave, char cmd, short word) 50295023Ssuz{ 50354263Sshin int error; 50495023Ssuz struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 50595023Ssuz error=intsmb_free(dev); 50654263Sshin if(!error){ 50754263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 50854263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 50954263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 51054263Sshin word&0xff); 51154263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 51254263Sshin (word>>8)&0xff); 51354263Sshin intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 51454263Sshin error=intsmb_stop(dev); 51554263Sshin } 51654263Sshin return (error); 51754263Sshin} 518153621Sthompsa 519153621Sthompsastatic int 520153621Sthompsaintsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 521153621Sthompsa{ 522153621Sthompsa int error; 523153621Sthompsa struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 524153621Sthompsa error=intsmb_free(dev); 525153621Sthompsa if(!error){ 526153621Sthompsa bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 527153621Sthompsa bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 528153621Sthompsa intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 529153621Sthompsa if(!(error=intsmb_stop(dev))){ 530153621Sthompsa *byte=bus_space_read_1(sc->st,sc->sh, 531153621Sthompsa PIIX4_SMBHSTDAT0); 532153621Sthompsa } 533153621Sthompsa } 534153621Sthompsa return (error); 535153621Sthompsa} 536153621Sthompsastatic int 537153621Sthompsaintsmb_readw(device_t dev, u_char slave, char cmd, short *word) 538153621Sthompsa{ 539153621Sthompsa int error; 540153621Sthompsa struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 541153621Sthompsa error=intsmb_free(dev); 542153621Sthompsa if(!error){ 543153621Sthompsa bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 544153621Sthompsa bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 545153621Sthompsa intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 546153621Sthompsa if(!(error=intsmb_stop(dev))){ 54754263Sshin *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 54883998Sbrooks *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 549105338Sume } 55083998Sbrooks } 55183998Sbrooks return (error); 55254263Sshin} 55354263Sshin/* 55454263Sshin * Data sheet claims that it implements all function, but also claims 555105338Sume * that it implements 7 function and not mention PCALL. So I don't know 556105338Sume * whether it will work. 557111888Sjlemon */ 55854263Sshinstatic int 55954263Sshinintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 56062587Sitojun{ 56154263Sshin#ifdef PROCCALL_TEST 56254263Sshin int error; 56354263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 56454263Sshin error=intsmb_free(dev); 56554263Sshin if(!error){ 56654263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 567147256Sbrooks bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 56854263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 56954263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 57062587Sitojun intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 571105339Sume } 572105339Sume if(!(error=intsmb_stop(dev))){ 573105339Sume *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 574105339Sume *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 57554263Sshin } 57654263Sshin return error; 577105293Sume#else 57854263Sshin return 0; 57962587Sitojun#endif 58054263Sshin} 58154263Sshinstatic int 58254263Sshinintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 58354263Sshin{ 58454263Sshin int error,i; 58554263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 58654263Sshin error=intsmb_free(dev); 58762587Sitojun if(count>SMBBLOCKTRANS_MAX||count==0) 58854263Sshin error=EINVAL; 58954263Sshin if(!error){ 59062587Sitojun /*Reset internal array index*/ 59154263Sshin bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 592105339Sume 593105339Sume bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 594105339Sume bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 595105339Sume for(i=0;i<count;i++){ 59654263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 59762587Sitojun } 59854263Sshin bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 599105339Sume intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 60054263Sshin error=intsmb_stop(dev); 601105339Sume } 60254263Sshin return (error); 60354263Sshin} 60454263Sshin 60578064Sumestatic int 60662587Sitojunintsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 60778064Sume{ 60862587Sitojun int error,i; 60954263Sshin struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 61054263Sshin error=intsmb_free(dev); 61154263Sshin if(count>SMBBLOCKTRANS_MAX||count==0) 61254263Sshin error=EINVAL; 61362587Sitojun if(!error){ 61478064Sume /*Reset internal array index*/ 61562587Sitojun bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 61662587Sitojun 61762587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 61862587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 61962587Sitojun bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 62062587Sitojun intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 62162587Sitojun error=intsmb_stop(dev); 62262587Sitojun if(!error){ 62378064Sume bzero(buf,count);/*Is it needed?*/ 62478064Sume count= bus_space_read_1(sc->st,sc->sh, 62578064Sume PIIX4_SMBHSTDAT0); 62678064Sume if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 62778064Sume for(i=0;i<count;i++){ 628105293Sume buf[i]=bus_space_read_1(sc->st, 62991327Sbrooks sc->sh, 630105293Sume PIIX4_SMBBLKDAT); 63162587Sitojun } 63254263Sshin } 63378064Sume else{ 63478064Sume error=EIO; 63578064Sume } 63678064Sume } 63778064Sume } 63878064Sume return (error); 63978064Sume} 64078064Sume 64178064SumeDRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 64278064Sume 64378064Sume 64478064Sumestatic void intpm_intr __P((void *arg)); 64578064Sumestatic int 64678064Sumeintpm_attach(device_t dev) 64778064Sume{ 64878064Sume int value; 64978064Sume int unit=device_get_unit(dev); 65078064Sume void *ih; 65178064Sume int error; 65278064Sume char * str; 65378064Sume { 65478064Sume struct intpm_pci_softc *sciic; 65578064Sume device_t smbinterface; 65678064Sume int rid; 65778064Sume struct resource *res; 65878064Sume 65978064Sume sciic=device_get_softc(dev); 66078064Sume if(sciic==NULL){ 66178064Sume return ENOMEM; 66278064Sume } 66378064Sume 66478064Sume rid=PCI_BASE_ADDR_SMB; 66578064Sume res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid, 66678064Sume 0,~0,1,RF_ACTIVE); 66778064Sume if(res==NULL){ 66878064Sume device_printf(dev,"Could not allocate Bus space\n"); 66978064Sume return ENXIO; 67078064Sume } 67178064Sume sciic->smbst=rman_get_bustag(res); 67278064Sume sciic->smbsh=rman_get_bushandle(res); 67378064Sume 67478064Sume device_printf(dev,"%s %x\n", 67578064Sume (sciic->smbst==I386_BUS_SPACE_IO)? 67678064Sume "I/O mapped":"Memory", 67778064Sume sciic->smbsh); 67878064Sume 67978064Sume 68078064Sume#ifndef NO_CHANGE_PCICONF 68178064Sume pci_write_config(dev,PCIR_INTLINE,0x9,1); 68278064Sume pci_write_config(dev,PCI_HST_CFG_SMB, 68378064Sume PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 68478064Sume#endif 68578064Sume value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 68678064Sume switch(value&0xe){ 68778064Sume case PCI_INTR_SMB_SMI: 688147256Sbrooks str="SMI"; 68962587Sitojun break; 69062587Sitojun case PCI_INTR_SMB_IRQ9: 69162587Sitojun str="IRQ 9"; 69262587Sitojun break; 693147256Sbrooks default: 69454263Sshin str="BOGUS"; 69562587Sitojun } 69662587Sitojun device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 69754263Sshin value=pci_read_config(dev,PCI_REVID_SMB,1); 69854263Sshin printf("revision %d\n",value); 69954263Sshin /* 70054263Sshin * Install intr HANDLER here 70154263Sshin */ 70254263Sshin rid=0; 70354263Sshin res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 70454263Sshin if(res==NULL){ 70554263Sshin device_printf(dev,"could not allocate irq"); 70678064Sume return ENOMEM; 70754263Sshin } 70878064Sume error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih); 70954263Sshin if(error){ 71078064Sume device_printf(dev,"Failed to map intr\n"); 71154263Sshin return error; 71254263Sshin } 71354263Sshin smbinterface=device_add_child(dev,"intsmb",unit); 71478064Sume if(!smbinterface){ 71554263Sshin printf("intsmb%d:could not add SMBus device\n",unit); 71654263Sshin } 71778064Sume device_probe_and_attach(smbinterface); 71854263Sshin } 71954263Sshin 72054263Sshin value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 72154263Sshin printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 72254263Sshin return 0; 72354263Sshin} 72478064Sumestatic int 72578064Sumeintpm_probe(device_t dev) 72678064Sume{ 727148385Sume struct _pcsid *ep =pci_ids; 728148385Sume u_int32_t device_id=pci_get_devid(dev); 729148385Sume 730148385Sume while (ep->type && ep->type != device_id) 731148385Sume ++ep; 732148385Sume if(ep->desc!=NULL){ 733148385Sume device_set_desc(dev,ep->desc); 73454263Sshin bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */ 73562587Sitojun return 0; 73654263Sshin }else{ 73754263Sshin return ENXIO; 73854263Sshin } 73954263Sshin} 74054263SshinDRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 74154263Sshin 74254263Sshinstatic void intpm_intr(void *arg) 74354263Sshin{ 74454263Sshin struct intpm_pci_softc *sc; 74578064Sume sc=(struct intpm_pci_softc *)arg; 74654263Sshin intsmb_intr(sc->smbus); 74778064Sume intsmb_slvintr(sc->smbus); 74854263Sshin 74978064Sume} 75054263Sshin