intpm.c revision 43311
1195534Sscottl/*- 2238805Smav * Copyright (c) 1998, 1999 Takanori Watanabe 3195534Sscottl * All rights reserved. 4195534Sscottl * 5195534Sscottl * Redistribution and use in source and binary forms, with or without 6195534Sscottl * modification, are permitted provided that the following conditions 7195534Sscottl * are met: 8195534Sscottl * 1. Redistributions of source code must retain the above copyright 9195534Sscottl * notice, this list of conditions and the following disclaimer. 10195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11195534Sscottl * notice, this list of conditions and the following disclaimer in the 12195534Sscottl * documentation and/or other materials provided with the distribution. 13195534Sscottl * 14195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15195534Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16195534Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17195534Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18195534Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19195534Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20195534Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21195534Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22195534Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23195534Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24195534Sscottl * SUCH DAMAGE. 25195534Sscottl * 26195534Sscottl * $Id: intpm.c,v 1.3 1999/01/27 23:45:43 dillon Exp $ 27195534Sscottl */ 28195534Sscottl 29195534Sscottl#include "pci.h" 30195534Sscottl#include "intpm.h" 31195534Sscottl 32195534Sscottl#if NPCI > 0 33195534Sscottl#if NINTPM >0 34195534Sscottl/* I don't think the chip is used in other architecture. :-)*/ 35220576Smav#include <sys/param.h> 36195534Sscottl#include <sys/systm.h> 37195534Sscottl#include <sys/kernel.h> 38195534Sscottl 39195534Sscottl#include <machine/bus_pio.h> 40195534Sscottl#include <machine/bus_memio.h> 41195534Sscottl#include <machine/bus.h> 42195534Sscottl 43195534Sscottl#include <machine/clock.h> 44195534Sscottl#include <sys/uio.h> 45195534Sscottl#include <sys/module.h> 46195534Sscottl#include <sys/bus.h> 47195534Sscottl#include <sys/conf.h> 48271146Simp#include <sys/malloc.h> 49271146Simp#include <sys/buf.h> 50195534Sscottl 51276344Smarius#include <dev/smbus/smbconf.h> 52199176Smav 53203030Smav#include "smbus_if.h" 54199176Smav 55199322Smav/*This should be removed if force_pci_map_int supported*/ 56199176Smav#include <sys/interrupt.h> 57271146Simp 58278034Ssmh#include <pci/pcireg.h> 59278034Ssmh#include <pci/pcivar.h> 60278034Ssmh#include <pci/intpmreg.h> 61278034Ssmh 62278034Ssmh#include "opt_intpm.h" 63278034Ssmh 64278034Ssmhstatic struct _pcsid 65278034Ssmh{ 66278034Ssmh pcidi_t type; 67278034Ssmh char *desc; 68278034Ssmh} pci_ids[] = 69271146Simp{ 70271146Simp { 0x71138086,"Intel 82371AB Power management controller"}, 71334453Smarius 72336522Smarkj { 0x00000000, NULL } 73336522Smarkj}; 74244146Smavstatic int intsmb_probe(device_t); 75244146Smavstatic int intsmb_attach(device_t); 76244146Smavstatic void intsmb_print_child(device_t, device_t); 77244146Smav 78244146Smavstatic int intsmb_intr(device_t dev); 79326120Smavstatic int intsmb_slvintr(device_t dev); 80326120Smavstatic void intsmb_alrintr(device_t dev); 81326120Smavstatic int intsmb_callback(device_t dev, int index, caddr_t data); 82326120Smavstatic int intsmb_quick(device_t dev, u_char slave, int how); 83326120Smavstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 84317673Smavstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 85317673Smavstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 86317673Smavstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 87317673Smavstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 88317673Smavstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 89317673Smavstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 90317673Smavstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 91317673Smavstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 92317673Smavstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 93358200Smavstatic int intsmb_stop(device_t dev); 94203030Smavstatic int intsmb_stop_poll(device_t dev); 95203030Smavstatic int intsmb_free(device_t dev); 96203030Smavstatic struct intpm_pci_softc *intpm_alloc(int unit); 97203030Smavstatic const char* intpm_probe __P((pcici_t tag, pcidi_t type)); 98203030Smavstatic void intpm_attach __P((pcici_t config_id, int unit)); 99203030Smavstatic devclass_t intsmb_devclass; 100203030Smav 101203030Smavstatic device_method_t intpm_methods[]={ 102203030Smav DEVMETHOD(device_probe,intsmb_probe), 103203030Smav DEVMETHOD(device_attach,intsmb_attach), 104322572Smav 105203030Smav DEVMETHOD(bus_print_child, intsmb_print_child), 106203030Smav 107322572Smav DEVMETHOD(smbus_callback,intsmb_callback), 108203030Smav DEVMETHOD(smbus_quick,intsmb_quick), 109203030Smav DEVMETHOD(smbus_sendb,intsmb_sendb), 110203030Smav DEVMETHOD(smbus_recvb,intsmb_recvb), 111203030Smav DEVMETHOD(smbus_writeb,intsmb_writeb), 112203030Smav DEVMETHOD(smbus_writew,intsmb_writew), 113203030Smav DEVMETHOD(smbus_readb,intsmb_readb), 114203030Smav DEVMETHOD(smbus_readw,intsmb_readw), 115203030Smav DEVMETHOD(smbus_pcall,intsmb_pcall), 116203030Smav DEVMETHOD(smbus_bwrite,intsmb_bwrite), 117203030Smav DEVMETHOD(smbus_bread,intsmb_bread), 118203030Smav {0,0} 119203030Smav}; 120322572Smav 121203030Smavstatic struct intpm_pci_softc{ 122322572Smav bus_space_tag_t smbst; 123322573Smav bus_space_handle_t smbsh; 124322573Smav bus_space_tag_t pmst; 125322573Smav bus_space_handle_t pmsh; 126322573Smav pcici_t cfg; 127322573Smav device_t smbus; 128322573Smav}intpm_pci[NINTPM]; 129331195Seadler 130331195Seadler 131331195Seadlerstruct intsmb_softc{ 132331195Seadler struct intpm_pci_softc *pci_sc; 133331195Seadler bus_space_tag_t st; 134331195Seadler bus_space_handle_t sh; 135331195Seadler device_t smbus; 136331195Seadler int isbusy; 137331195Seadler}; 138331195Seadlerstatic driver_t intpm_driver = { 139331195Seadler "intsmb", 140331195Seadler intpm_methods, 141331195Seadler DRIVER_TYPE_MISC, 142331195Seadler sizeof(struct intsmb_softc), 143331195Seadler}; 144331195Seadlerstatic u_long intpm_count ; 145331195Seadler 146331195Seadlerstatic struct pci_device intpm_device = { 147331195Seadler "intpm", 148331195Seadler intpm_probe, 149211922Smav intpm_attach, 150211922Smav &intpm_count 151322572Smav}; 152322572Smav 153322572SmavDATA_SET (pcidevice_set, intpm_device); 154218605Smav 155218605Smavstatic int 156218605Smavintsmb_probe(device_t dev) 157322572Smav{ 158221789Sjfv struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 159221789Sjfv sc->smbus=smbus_alloc_bus(dev); 160258162Smav if (!sc->smbus) 161258162Smav return (EINVAL); /* XXX don't know what to return else */ 162258162Smav device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 163258162Smav 164258162Smav return (0); /* XXX don't know what to return else */ 165258162Smav} 166258162Smavstatic int 167258162Smavintsmb_attach(device_t dev) 168258162Smav{ 169258162Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 170258162Smav sc->pci_sc=&intpm_pci[device_get_unit(dev)]; 171258162Smav sc->isbusy=0; 172258162Smav sc->sh=sc->pci_sc->smbsh; 173258162Smav sc->st=sc->pci_sc->smbst; 174258162Smav sc->pci_sc->smbus=dev; 175258162Smav device_probe_and_attach(sc->smbus); 176258162Smav#ifdef ENABLE_ALART 177258162Smav /*Enable Arart*/ 178258162Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 179258162Smav PIIX4_SMBSLVCNT_ALTEN); 180258162Smav#endif 181258162Smav return (0); 182278034Ssmh} 183244983Sjfv 184244983Sjfvstatic void 185258162Smavintsmb_print_child(device_t bus, device_t dev) 186258162Smav{ 187258162Smav printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 188258162Smav return; 189258162Smav} 190258162Smavstatic int 191275101Smavintsmb_callback(device_t dev, int index, caddr_t data) 192275101Smav{ 193275101Smav int error = 0; 194275101Smav intrmask_t s; 195275101Smav s=splnet(); 196275101Smav switch (index) { 197275101Smav case SMB_REQUEST_BUS: 198275101Smav break; 199258162Smav case SMB_RELEASE_BUS: 200258162Smav break; 201258162Smav default: 202258162Smav error = EINVAL; 203258162Smav } 204258162Smav splx(s); 205258162Smav return (error); 206322572Smav} 207322572Smav/*counterpart of smbtx_smb_free*/ 208258162Smavstatic int 209258162Smavintsmb_free(device_t dev){ 210258162Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 211258162Smav if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 212258162Smav PIIX4_SMBHSTSTAT_BUSY) 213258162Smav#ifdef ENABLE_ALART 214258162Smav ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 215258162Smav PIIX4_SMBSLVSTS_BUSY) 216355329Smav#endif 217355329Smav || sc->isbusy) 218355329Smav return EBUSY; 219355329Smav sc->isbusy=1; 220298983Smav /*Disable Intrrupt in slave part*/ 221298983Smav#ifndef ENABLE_ALART 222298983Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 223298983Smav#endif 224298983Smav /*Reset INTR Flag to prepare INTR*/ 225298983Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 226298983Smav (PIIX4_SMBHSTSTAT_INTR| 227298983Smav PIIX4_SMBHSTSTAT_ERR| 228298983Smav PIIX4_SMBHSTSTAT_BUSC| 229322572Smav PIIX4_SMBHSTSTAT_FAIL) 230322572Smav ); 231322572Smav return 0; 232322572Smav} 233322572Smav 234322572Smavstatic int 235322572Smavintsmb_intr(device_t dev) 236322572Smav{ 237322572Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 238322572Smav int status; 239322572Smav intrmask_t s; 240345820Smav status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 241345820Smav if(status&PIIX4_SMBHSTSTAT_BUSY){ 242221789Sjfv return 1; 243239907Smav 244304658Savg } 245239907Smav s=splhigh(); 246203030Smav if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR| 247203030Smav PIIX4_SMBHSTSTAT_ERR| 248203030Smav PIIX4_SMBHSTSTAT_BUSC| 249203030Smav PIIX4_SMBHSTSTAT_FAIL))){ 250359971Smav int tmp; 251285020Smav sc->isbusy=0; 252285020Smav tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 253285020Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 254285020Smav tmp&~PIIX4_SMBHSTCNT_INTREN); 255285020Smav splx(s); 256285020Smav wakeup(sc); 257285020Smav return 0; 258285020Smav } 259271163Smav splx(s); 260271163Smav return 1;/* Not Completed*/ 261271163Smav} 262271163Smavstatic int 263271163Smavintsmb_slvintr(device_t dev) 264271163Smav{ 265271163Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 266271163Smav int status,retval; 267271163Smav retval=1; 268271163Smav status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 269271163Smav if(status&PIIX4_SMBSLVSTS_BUSY) 270271163Smav return retval; 271271163Smav if(status&PIIX4_SMBSLVSTS_ALART){ 272271163Smav intsmb_alrintr(dev); 273271163Smav retval=0; 274271163Smav }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 275271163Smav |PIIX4_SMBSLVSTS_SDW1)){ 276271163Smav retval=0; 277271163Smav } 278271163Smav /*Reset Status Register*/ 279271163Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 280271163Smav PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 281271163Smav PIIX4_SMBSLVSTS_SLV); 282271163Smav return retval; 283271163Smav} 284207499Smav 285207499Smavstatic void intsmb_alrintr(device_t dev) 286207499Smav{ 287207499Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 288207499Smav int slvcnt; 289207499Smav#ifdef ENABLE_ALART 290207499Smav int error; 291207499Smav#endif 292207499Smav 293207499Smav /*stop generating INTR from ALART*/ 294207499Smav slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 295207499Smav#ifdef ENABLE_ALART 296207499Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 297207499Smav slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 298207499Smav#endif 299207499Smav DELAY(5); 300207499Smav /*ask bus who assert it and then ask it what's the matter. */ 301207499Smav#ifdef ENABLE_ALART 302207499Smav error=intsmb_free(dev); 303207499Smav if(!error){ 304207499Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 305207499Smav |LSB); 306207499Smav intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 307207499Smav if(!(error=intsmb_stop_poll(dev))){ 308207499Smav volatile u_int8_t *addr; 309207499Smav addr=bus_space_read_1(sc->st,sc->sh, 310207499Smav PIIX4_SMBHSTDAT0); 311207499Smav printf("ALART_RESPONSE: %p\n", addr); 312207499Smav } 313207499Smav }else{ 314207499Smav printf("ERROR\n"); 315207499Smav } 316207499Smav 317207499Smav /*Re-enable INTR from ALART*/ 318207499Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 319207499Smav slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 320207499Smav DELAY(5); 321207499Smav#endif 322207499Smav 323207499Smav return; 324207499Smav} 325207499Smavstatic void 326207499Smavintsmb_start(device_t dev,unsigned char cmd,int nointr) 327207499Smav{ 328207499Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 329207499Smav unsigned char tmp; 330207499Smav tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 331207499Smav tmp&= 0xe0; 332207499Smav tmp |= cmd; 333207499Smav tmp |=PIIX4_SMBHSTCNT_START; 334207499Smav /*While not in autoconfiguration Intrrupt Enabled*/ 335207499Smav if(!cold||!nointr) 336207499Smav tmp |=PIIX4_SMBHSTCNT_INTREN; 337207499Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 338207499Smav} 339207499Smav 340207499Smav/*Polling Code. Polling is not encouraged 341207499Smav * because It is required to wait for the device get busy. 342224603Smav *(29063505.pdf from Intel) 343207499Smav * But during boot,intrrupt cannot be used. 344207499Smav * so use polling code while in autoconfiguration. 345207499Smav */ 346207499Smav 347207499Smavstatic int 348207499Smavintsmb_stop_poll(device_t dev){ 349207499Smav int error,i; 350207499Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 351207499Smav /* 352207499Smav * In smbtx driver ,Simply waiting. 353271403Smav * This loops 100-200 times. 354208907Smav */ 355208907Smav for(i=0;i<0x7fff;i++){ 356203030Smav if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 357203030Smav &PIIX4_SMBHSTSTAT_BUSY)){ 358203030Smav break; 359279573Semaste } 360297447Szbb } 361203030Smav for(i=0;i<0x7fff;i++){ 362199176Smav int status; 363199176Smav status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 364271146Simp if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 365271146Simp sc->isbusy=0; 366271146Simp error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 367220565Smav (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 368271146Simp (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 369271146Simp if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 370271146Simp printf("unknown cause why?"); 371271146Simp } 372271146Simp return error; 373228200Smav } 374195534Sscottl } 375195534Sscottl sc->isbusy=0; 376195534Sscottl return EIO; 377199176Smav} 378199322Smav/* 379199322Smav *wait for completion and return result. 380203030Smav */ 381199322Smavstatic int 382260163Szbbintsmb_stop(device_t dev){ 383260163Szbb int error; 384260163Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 385260163Szbb if(cold){ 386260163Szbb /*So that it can use device during probing device on SMBus.*/ 387260163Szbb error=intsmb_stop_poll(dev); 388260163Szbb return error; 389199322Smav }else{ 390199322Smav if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 391199322Smav int status; 392199322Smav status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 393199322Smav if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 394288111Smav error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 395288111Smav (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 396288111Smav (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 397199322Smav if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 398199322Smav printf("intsmb%d:unknown cause why?\n", 399199322Smav device_get_unit(dev)); 400203030Smav } 401228200Smav#ifdef ENABLE_ALART 402228200Smav bus_space_write_1(sc->st,sc->sh, 403199717Smav PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 404199717Smav#endif 405359971Smav return error; 406199717Smav } 407199717Smav } 408199322Smav } 409199322Smav /*Timeout Procedure*/ 410199322Smav sc->isbusy=0; 411280393Smav /*Re-enable supressed intrrupt from slave part*/ 412199322Smav bus_space_write_1(sc->st,sc->sh, 413199322Smav PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 414288111Smav return EIO; 415199322Smav} 416199322Smav 417280393Smavstatic int 418199322Smavintsmb_quick(device_t dev, u_char slave, int how) 419199322Smav{ 420199322Smav int error=0; 421199322Smav u_char data; 422199322Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 423199322Smav data=slave; 424199176Smav /*Quick command is part of Address, I think*/ 425199176Smav switch(how){ 426203030Smav case SMB_QWRITE: 427195534Sscottl data&=~LSB; 428199322Smav break; 429199322Smav case SMB_QREAD: 430199176Smav data|=LSB; 431199176Smav break; 432203030Smav default: 433203030Smav error=EINVAL; 434199176Smav } 435199176Smav if(!error){ 436199176Smav error=intsmb_free(dev); 437280393Smav if(!error){ 438199176Smav bus_space_write_1(sc->st,sc->sh, 439199176Smav PIIX4_SMBHSTADD,data); 440199176Smav intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 441280393Smav error=intsmb_stop(dev); 442195534Sscottl } 443195534Sscottl } 444195534Sscottl 445285789Szbb return (error); 446285789Szbb} 447285789Szbb 448285789Szbbstatic int 449285789Szbbintsmb_sendb(device_t dev, u_char slave, char byte) 450285789Szbb{ 451285789Szbb int error; 452285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 453285789Szbb error=intsmb_free(dev); 454285789Szbb if(!error){ 455285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 456285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 457285789Szbb intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 458285789Szbb error=intsmb_stop(dev); 459285789Szbb } 460285789Szbb return (error); 461285789Szbb} 462285789Szbbstatic int 463285789Szbbintsmb_recvb(device_t dev, u_char slave, char *byte) 464285789Szbb{ 465285789Szbb int error; 466285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 467271146Simp error=intsmb_free(dev); 468195534Sscottl if(!error){ 469195534Sscottl bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 470271146Simp |LSB); 471199322Smav intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 472203030Smav if(!(error=intsmb_stop(dev))){ 473285789Szbb#ifdef RECV_IS_IN_CMD 474285789Szbb /*Linux SMBus stuff also troubles 475195534Sscottl Because Intel's datasheet will not make clear. 476285789Szbb */ 477285789Szbb *byte=bus_space_read_1(sc->st,sc->sh, 478285789Szbb PIIX4_SMBHSTCMD); 479199322Smav#else 480203030Smav *byte=bus_space_read_1(sc->st,sc->sh, 481203030Smav PIIX4_SMBHSTDAT0); 482203030Smav#endif 483199322Smav } 484199322Smav } 485271146Simp return (error); 486271146Simp} 487271146Simpstatic int 488271146Simpintsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 489271146Simp{ 490271146Simp int error; 491297921Smav struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 492297921Smav error=intsmb_free(dev); 493271146Simp if(!error){ 494271146Simp bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 495271146Simp bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 496271146Simp bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 497277100Skib intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 498277100Skib error=intsmb_stop(dev); 499277100Skib } 500277100Skib return (error); 501277100Skib} 502277100Skibstatic int 503195534Sscottlintsmb_writew(device_t dev, u_char slave, char cmd, short word) 504195534Sscottl{ 505195534Sscottl int error; 506285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 507297447Szbb error=intsmb_free(dev); 508297447Szbb if(!error){ 509297447Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 510285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 511285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 512285789Szbb word&0xff); 513285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 514285789Szbb (word>>8)&0xff); 515285789Szbb intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 516285789Szbb error=intsmb_stop(dev); 517285789Szbb } 518285789Szbb return (error); 519285789Szbb} 520285789Szbb 521285789Szbbstatic int 522285789Szbbintsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 523285789Szbb{ 524285789Szbb int error; 525285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 526285789Szbb error=intsmb_free(dev); 527285789Szbb if(!error){ 528285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 529285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 530285789Szbb intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 531285789Szbb if(!(error=intsmb_stop(dev))){ 532285789Szbb *byte=bus_space_read_1(sc->st,sc->sh, 533285789Szbb PIIX4_SMBHSTDAT0); 534285789Szbb } 535285789Szbb } 536285789Szbb return (error); 537285789Szbb} 538285789Szbbstatic int 539285789Szbbintsmb_readw(device_t dev, u_char slave, char cmd, short *word) 540285789Szbb{ 541285789Szbb int error; 542285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 543285789Szbb error=intsmb_free(dev); 544285789Szbb if(!error){ 545285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 546285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 547285789Szbb intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 548285789Szbb if(!(error=intsmb_stop(dev))){ 549285789Szbb *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 550285789Szbb *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 551285789Szbb } 552285789Szbb } 553285789Szbb return (error); 554285789Szbb} 555285789Szbb/* 556207511Smav * Data sheet claims that it implements all function, but also claims 557195534Sscottl * that it implements 7 function and not mention PCALL. So I don't know 558271146Simp * whether it will work. 559285789Szbb */ 560195534Sscottlstatic int 561297793Spfgintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 562222304Smav{ 563195534Sscottl#ifdef PROCCALL_TEST 564195534Sscottl int error; 565271146Simp struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 566195534Sscottl error=intsmb_free(dev); 567245875Smav if(!error){ 568256843Smav bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 569278034Ssmh bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 570278034Ssmh bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 571278034Ssmh bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 572278034Ssmh intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 573195534Sscottl } 574256843Smav if(!(error=intsmb_stop(dev))){ 575256843Smav *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 576285789Szbb *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 577285789Szbb } 578256843Smav return error; 579256843Smav#else 580285789Szbb return 0; 581285789Szbb#endif 582285789Szbb} 583285789Szbbstatic int 584256843Smavintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 585285789Szbb{ 586285789Szbb int error,i; 587285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 588285789Szbb error=intsmb_free(dev); 589285789Szbb if(count>SMBBLOCKTRANS_MAX||count==0) 590285789Szbb error=EINVAL; 591285789Szbb if(!error){ 592285789Szbb /*Reset internal array index*/ 593285789Szbb bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 594285789Szbb 595285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 596285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 597285789Szbb for(i=0;i<count;i++){ 598285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 599285789Szbb } 600285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 601285789Szbb intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 602285789Szbb error=intsmb_stop(dev); 603285789Szbb } 604285789Szbb return (error); 605285789Szbb} 606285789Szbb 607285789Szbbstatic int 608285789Szbbintsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 609285789Szbb{ 610285789Szbb int error,i; 611285789Szbb struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 612285789Szbb error=intsmb_free(dev); 613256843Smav if(count>SMBBLOCKTRANS_MAX||count==0) 614195534Sscottl error=EINVAL; 615271146Simp if(!error){ 616285789Szbb /*Reset internal array index*/ 617285789Szbb bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 618271146Simp 619285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 620285789Szbb bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 621271146Simp bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 622195534Sscottl intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 623195534Sscottl error=intsmb_stop(dev); 624195534Sscottl if(!error){ 625271146Simp bzero(buf,count);/*Is it needed?*/ 626195534Sscottl count= bus_space_read_1(sc->st,sc->sh, 627195534Sscottl PIIX4_SMBHSTDAT0); 628271146Simp if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 629271146Simp for(i=0;i<count;i++){ 630195534Sscottl buf[i]=bus_space_read_1(sc->st, 631195534Sscottl sc->sh, 632195534Sscottl PIIX4_SMBBLKDAT); 633195534Sscottl } 634271146Simp } 635195534Sscottl else{ 636195534Sscottl error=EIO; 637195534Sscottl } 638271146Simp } 639271146Simp } 640271146Simp return (error); 641271146Simp} 642271146Simp 643195534SscottlDRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0); 644195534Sscottl 645195534Sscottl 646271146Simpstatic void intpm_intr __P((void *arg)); 647195534Sscottl 648271146Simpstatic const char* 649195534Sscottlintpm_probe (pcici_t tag, pcidi_t type) 650271146Simp{ 651271146Simp struct _pcsid *ep =pci_ids; 652271146Simp while (ep->type && ep->type != type) 653271146Simp ++ep; 654195534Sscottl return (ep->desc); 655195534Sscottl} 656195534Sscottl 657195534Sscottlstatic struct intpm_pci_softc *intpm_alloc(int unit){ 658271146Simp if(unit<NINTPM) 659271146Simp return &intpm_pci[unit]; 660271146Simp else 661271146Simp return NULL; 662195534Sscottl} 663195534Sscottl 664195534Sscottl/*Same as pci_map_int but this ignores INTPIN*/ 665195534Sscottlstatic int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr) 666195534Sscottl{ 667208410Smav int error; 668249346Smav#ifdef APIC_IO 669276344Smarius int nextpin, muxcnt; 670195534Sscottl#endif 671195534Sscottl /* Spec sheet claims that it use IRQ 9*/ 672195534Sscottl int irq = 9; 673195534Sscottl void *dev_instance = (void *)-1; /* XXX use cfg->devdata */ 674195534Sscottl void *idesc; 675195534Sscottl 676276344Smarius idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); 677199322Smav error = intr_connect(idesc); 678199322Smav if (error != 0) 679271146Simp return 0; 680271146Simp#ifdef APIC_IO 681271146Simp nextpin = next_apic_irq(irq); 682271146Simp 683199322Smav if (nextpin < 0) 684199322Smav return 1; 685199322Smav 686199322Smav /* 687199322Smav * Attempt handling of some broken mp tables. 688208410Smav * 689276344Smarius * It's OK to yell (since the mp tables are broken). 690199322Smav * 691199322Smav * Hanging in the boot is not OK 692199322Smav */ 693199322Smav 694199322Smav muxcnt = 2; 695199322Smav nextpin = next_apic_irq(nextpin); 696276344Smarius while (muxcnt < 5 && nextpin >= 0) { 697 muxcnt++; 698 nextpin = next_apic_irq(nextpin); 699 } 700 if (muxcnt >= 5) { 701 printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); 702 return 0; 703 } 704 705 printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt); 706 707 nextpin = next_apic_irq(irq); 708 while (nextpin >= 0) { 709 idesc = intr_create(dev_instance, nextpin, func, arg, 710 maskptr, 0); 711 error = intr_connect(idesc); 712 if (error != 0) 713 return 0; 714 printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); 715 nextpin = next_apic_irq(nextpin); 716 } 717#endif 718 return 1; 719} 720static void 721intpm_attach(config_id, unit) 722 pcici_t config_id; 723 int unit; 724{ 725 int value; 726 727 char * str; 728 { 729 struct intpm_pci_softc *sciic; 730 device_t smbinterface; 731 value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4); 732 sciic=intpm_alloc(unit); 733 if(sciic==NULL){ 734 return; 735 } 736 737 sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM; 738 739 /*Calling pci_map_port is better.But bus_space_handle_t != 740 * pci_port_t, so I don't call support routine while 741 * bus_space_??? support routine will be appear. 742 */ 743 sciic->smbsh=value&(~1); 744 if(sciic->smbsh==I386_BUS_SPACE_MEM){ 745 /*According to the spec, this will not occur*/ 746 int dummy; 747 pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy); 748 } 749 printf("intpm%d: %s %x ",unit, 750 (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory", 751 sciic->smbsh); 752#ifndef NO_CHANGE_PCICONF 753 pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1); 754 pci_cfgwrite(config_id,PCI_HST_CFG_SMB, 755 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 756#endif 757 config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1); 758 printf("ALLOCED IRQ %d ",config_id->intline); 759 value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1); 760 switch(value&0xe){ 761 case PCI_INTR_SMB_SMI: 762 str="SMI"; 763 break; 764 case PCI_INTR_SMB_IRQ9: 765 str="IRQ 9"; 766 break; 767 default: 768 str="BOGUS"; 769 } 770 printf("intr %s %s ",str,((value&1)? "enabled":"disabled")); 771 value=pci_cfgread(config_id,PCI_REVID_SMB,1); 772 printf("revision %d\n",value); 773 /* 774 * Install intr HANDLER here 775 */ 776 if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){ 777 printf("intpm%d: Failed to map intr\n",unit); 778 } 779 smbinterface=device_add_child(root_bus,"intsmb",unit,NULL); 780 device_probe_and_attach(smbinterface); 781 } 782 value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4); 783 printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 784 return; 785} 786static void intpm_intr(void *arg) 787{ 788 struct intpm_pci_softc *sc; 789 sc=(struct intpm_pci_softc *)arg; 790 intsmb_intr(sc->smbus); 791 intsmb_slvintr(sc->smbus); 792} 793#endif /* NPCI > 0 */ 794#endif 795