intpm.c revision 67164
1253572Sloos/*- 2253572Sloos * Copyright (c) 1998, 1999 Takanori Watanabe 3253572Sloos * All rights reserved. 4253572Sloos * 5253572Sloos * Redistribution and use in source and binary forms, with or without 6253572Sloos * modification, are permitted provided that the following conditions 7253572Sloos * are met: 8253572Sloos * 1. Redistributions of source code must retain the above copyright 9253572Sloos * notice, this list of conditions and the following disclaimer. 10253572Sloos * 2. Redistributions in binary form must reproduce the above copyright 11253572Sloos * notice, this list of conditions and the following disclaimer in the 12253572Sloos * documentation and/or other materials provided with the distribution. 13253572Sloos * 14253572Sloos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15253572Sloos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16253572Sloos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17253572Sloos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18253572Sloos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19253572Sloos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20253572Sloos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21253572Sloos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22253572Sloos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23253572Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24253572Sloos * SUCH DAMAGE. 25253572Sloos * 26253572Sloos * $FreeBSD: head/sys/pci/intpm.c 67164 2000-10-15 14:19:01Z phk $ 27253572Sloos */ 28253572Sloos 29253572Sloos#include <sys/param.h> 30253572Sloos#include <sys/systm.h> 31253572Sloos#include <sys/kernel.h> 32253572Sloos#include <machine/bus_pio.h> 33253572Sloos#include <machine/bus_memio.h> 34257284Sglebius#include <machine/bus.h> 35253572Sloos 36257284Sglebius#include <sys/uio.h> 37253572Sloos#include <sys/module.h> 38253572Sloos#include <sys/bus.h> 39253572Sloos#include <sys/rman.h> 40253572Sloos#include <machine/resource.h> 41253572Sloos#include <dev/smbus/smbconf.h> 42253572Sloos 43253572Sloos#include "smbus_if.h" 44253572Sloos 45253572Sloos/*This should be removed if force_pci_map_int supported*/ 46253572Sloos#include <sys/interrupt.h> 47253572Sloos 48253572Sloos#include <pci/pcireg.h> 49253572Sloos#include <pci/pcivar.h> 50253572Sloos#include <pci/intpmreg.h> 51253572Sloos 52253572Sloos#include "opt_intpm.h" 53256583Sadrian 54256583Sadrianstatic struct _pcsid 55256583Sadrian{ 56256583Sadrian u_int32_t type; 57253572Sloos char *desc; 58279797Sadrian} pci_ids[] = 59253572Sloos{ 60253572Sloos { 0x71138086,"Intel 82371AB Power management controller"}, 61253572Sloos 62253572Sloos { 0x00000000, NULL } 63253572Sloos}; 64253572Sloosstatic int intsmb_probe(device_t); 65253572Sloosstatic int intsmb_attach(device_t); 66253572Sloos 67253572Sloosstatic int intsmb_intr(device_t dev); 68253572Sloosstatic int intsmb_slvintr(device_t dev); 69253572Sloosstatic void intsmb_alrintr(device_t dev); 70253572Sloosstatic int intsmb_callback(device_t dev, int index, caddr_t data); 71253572Sloosstatic int intsmb_quick(device_t dev, u_char slave, int how); 72253572Sloosstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 73253572Sloosstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 74253572Sloosstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 75253572Sloosstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 76253572Sloosstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 77253572Sloosstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 78253572Sloosstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 79253572Sloosstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 80253572Sloosstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 81253572Sloosstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 82253572Sloosstatic int intsmb_stop(device_t dev); 83253572Sloosstatic int intsmb_stop_poll(device_t dev); 84253572Sloosstatic int intsmb_free(device_t dev); 85253572Sloosstatic int intpm_probe (device_t dev); 86253572Sloosstatic int intpm_attach (device_t dev); 87253572Sloosstatic devclass_t intsmb_devclass; 88279797Sadrian 89279797Sadrianstatic device_method_t intpm_methods[]={ 90253572Sloos DEVMETHOD(device_probe,intsmb_probe), 91253572Sloos DEVMETHOD(device_attach,intsmb_attach), 92253572Sloos 93279797Sadrian DEVMETHOD(bus_print_child, bus_generic_print_child), 94253572Sloos 95253572Sloos DEVMETHOD(smbus_callback,intsmb_callback), 96279797Sadrian DEVMETHOD(smbus_quick,intsmb_quick), 97279797Sadrian DEVMETHOD(smbus_sendb,intsmb_sendb), 98253572Sloos DEVMETHOD(smbus_recvb,intsmb_recvb), 99253572Sloos DEVMETHOD(smbus_writeb,intsmb_writeb), 100253572Sloos DEVMETHOD(smbus_writew,intsmb_writew), 101279797Sadrian DEVMETHOD(smbus_readb,intsmb_readb), 102253572Sloos DEVMETHOD(smbus_readw,intsmb_readw), 103253572Sloos DEVMETHOD(smbus_pcall,intsmb_pcall), 104279790Sadrian DEVMETHOD(smbus_bwrite,intsmb_bwrite), 105279943Sadrian DEVMETHOD(smbus_bread,intsmb_bread), 106279943Sadrian {0,0} 107253572Sloos}; 108253572Sloos 109253572Sloosstruct intpm_pci_softc{ 110253572Sloos bus_space_tag_t smbst; 111253572Sloos bus_space_handle_t smbsh; 112279797Sadrian bus_space_tag_t pmst; 113253572Sloos bus_space_handle_t pmsh; 114253572Sloos device_t smbus; 115253572Sloos}; 116253572Sloos 117253572Sloos 118253572Sloosstruct intsmb_softc{ 119253572Sloos struct intpm_pci_softc *pci_sc; 120253572Sloos bus_space_tag_t st; 121253572Sloos bus_space_handle_t sh; 122253572Sloos device_t smbus; 123279943Sadrian int isbusy; 124253572Sloos}; 125253572Sloos 126253572Sloosstatic driver_t intpm_driver = { 127279790Sadrian "intsmb", 128279943Sadrian intpm_methods, 129279943Sadrian sizeof(struct intsmb_softc), 130253572Sloos}; 131253572Sloos 132253572Sloosstatic devclass_t intpm_devclass; 133253572Sloosstatic device_method_t intpm_pci_methods[] = { 134279797Sadrian DEVMETHOD(device_probe,intpm_probe), 135253572Sloos DEVMETHOD(device_attach,intpm_attach), 136253572Sloos {0,0} 137253572Sloos}; 138253572Sloosstatic driver_t intpm_pci_driver = { 139253572Sloos "intpm", 140279790Sadrian intpm_pci_methods, 141279790Sadrian sizeof(struct intpm_pci_softc) 142253572Sloos}; 143253572Sloos 144253572Sloosstatic int 145253572Sloosintsmb_probe(device_t dev) 146253572Sloos{ 147253572Sloos struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 148253572Sloos sc->smbus=smbus_alloc_bus(dev); 149253572Sloos if (!sc->smbus) 150253572Sloos return (EINVAL); /* XXX don't know what to return else */ 151253572Sloos device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 152253572Sloos 153253572Sloos return (0); /* XXX don't know what to return else */ 154253572Sloos} 155279790Sadrianstatic int 156279790Sadrianintsmb_attach(device_t dev) 157253572Sloos{ 158253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 159253572Sloos sc->pci_sc=device_get_softc(device_get_parent(dev)); 160253572Sloos sc->isbusy=0; 161253572Sloos sc->sh=sc->pci_sc->smbsh; 162253572Sloos sc->st=sc->pci_sc->smbst; 163253572Sloos sc->pci_sc->smbus=dev; 164253572Sloos device_probe_and_attach(sc->smbus); 165253572Sloos#ifdef ENABLE_ALART 166253572Sloos /*Enable Arart*/ 167253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 168253572Sloos PIIX4_SMBSLVCNT_ALTEN); 169253572Sloos#endif 170253572Sloos return (0); 171253572Sloos} 172253572Sloos 173253572Sloosstatic int 174253572Sloosintsmb_callback(device_t dev, int index, caddr_t data) 175262429Sadrian{ 176253572Sloos int error = 0; 177253572Sloos intrmask_t s; 178253572Sloos s=splnet(); 179253572Sloos switch (index) { 180253572Sloos case SMB_REQUEST_BUS: 181253572Sloos break; 182253572Sloos case SMB_RELEASE_BUS: 183253572Sloos break; 184253572Sloos default: 185253572Sloos error = EINVAL; 186253572Sloos } 187253572Sloos splx(s); 188253572Sloos return (error); 189253572Sloos} 190253572Sloos/*counterpart of smbtx_smb_free*/ 191253572Sloosstatic int 192253572Sloosintsmb_free(device_t dev){ 193253572Sloos intrmask_t s; 194253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 195253572Sloos if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 196253572Sloos PIIX4_SMBHSTSTAT_BUSY) 197279797Sadrian#ifdef ENABLE_ALART 198253572Sloos ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 199253572Sloos PIIX4_SMBSLVSTS_BUSY) 200253572Sloos#endif 201253572Sloos || sc->isbusy) 202253572Sloos return EBUSY; 203253572Sloos s=splhigh(); 204253572Sloos sc->isbusy=1; 205253572Sloos /*Disable Intrrupt in slave part*/ 206253572Sloos#ifndef ENABLE_ALART 207253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 208253572Sloos#endif 209253572Sloos /*Reset INTR Flag to prepare INTR*/ 210253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 211253572Sloos (PIIX4_SMBHSTSTAT_INTR| 212253572Sloos PIIX4_SMBHSTSTAT_ERR| 213253572Sloos PIIX4_SMBHSTSTAT_BUSC| 214253572Sloos PIIX4_SMBHSTSTAT_FAIL) 215253572Sloos ); 216253572Sloos splx(s); 217253572Sloos return 0; 218253572Sloos} 219253572Sloos 220253572Sloosstatic int 221253572Sloosintsmb_intr(device_t dev) 222253572Sloos{ 223253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 224262429Sadrian int status; 225253572Sloos status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 226253572Sloos if(status&PIIX4_SMBHSTSTAT_BUSY){ 227253572Sloos return 1; 228279943Sadrian 229253572Sloos } 230253572Sloos if(status&(PIIX4_SMBHSTSTAT_INTR| 231253572Sloos PIIX4_SMBHSTSTAT_ERR| 232253572Sloos PIIX4_SMBHSTSTAT_BUSC| 233253572Sloos PIIX4_SMBHSTSTAT_FAIL)){ 234253572Sloos int tmp; 235253572Sloos tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 236253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 237253572Sloos tmp&~PIIX4_SMBHSTCNT_INTREN); 238253572Sloos if(sc->isbusy){ 239253572Sloos sc->isbusy=0; 240253572Sloos wakeup(sc); 241253572Sloos } 242253572Sloos return 0; 243253572Sloos } 244253572Sloos return 1;/* Not Completed*/ 245279943Sadrian} 246253572Sloosstatic int 247253572Sloosintsmb_slvintr(device_t dev) 248253572Sloos{ 249253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 250253572Sloos int status,retval; 251253572Sloos retval=1; 252253572Sloos status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 253253572Sloos if(status&PIIX4_SMBSLVSTS_BUSY) 254253572Sloos return retval; 255253572Sloos if(status&PIIX4_SMBSLVSTS_ALART){ 256253572Sloos intsmb_alrintr(dev); 257253572Sloos retval=0; 258253572Sloos }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 259253572Sloos |PIIX4_SMBSLVSTS_SDW1)){ 260253572Sloos retval=0; 261253572Sloos } 262253572Sloos /*Reset Status Register*/ 263253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 264262429Sadrian PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 265253572Sloos PIIX4_SMBSLVSTS_SLV); 266253572Sloos return retval; 267253572Sloos} 268253572Sloos 269253572Sloosstatic void intsmb_alrintr(device_t dev) 270253572Sloos{ 271253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 272253572Sloos int slvcnt; 273253572Sloos#ifdef ENABLE_ALART 274253572Sloos int error; 275253572Sloos#endif 276253572Sloos 277253572Sloos /*stop generating INTR from ALART*/ 278253572Sloos slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 279253572Sloos#ifdef ENABLE_ALART 280253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 281253572Sloos slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 282253572Sloos#endif 283253572Sloos DELAY(5); 284253572Sloos /*ask bus who assert it and then ask it what's the matter. */ 285253572Sloos#ifdef ENABLE_ALART 286253572Sloos error=intsmb_free(dev); 287253572Sloos if(!error){ 288253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 289253572Sloos |LSB); 290253572Sloos intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 291279790Sadrian if(!(error=intsmb_stop_poll(dev))){ 292279943Sadrian volatile u_int8_t *addr; 293253572Sloos addr=bus_space_read_1(sc->st,sc->sh, 294253572Sloos PIIX4_SMBHSTDAT0); 295253572Sloos printf("ALART_RESPONSE: %p\n", addr); 296279790Sadrian } 297253572Sloos }else{ 298279943Sadrian printf("ERROR\n"); 299253572Sloos } 300253572Sloos 301253572Sloos /*Re-enable INTR from ALART*/ 302279943Sadrian bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 303253572Sloos slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 304253572Sloos DELAY(5); 305253572Sloos#endif 306279943Sadrian 307253572Sloos return; 308253572Sloos} 309253572Sloosstatic void 310253572Sloosintsmb_start(device_t dev,unsigned char cmd,int nointr) 311262429Sadrian{ 312253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 313253572Sloos unsigned char tmp; 314253572Sloos tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 315253572Sloos tmp&= 0xe0; 316253572Sloos tmp |= cmd; 317253572Sloos tmp |=PIIX4_SMBHSTCNT_START; 318253572Sloos /*While not in autoconfiguration Intrrupt Enabled*/ 319253572Sloos if(!cold||!nointr) 320253572Sloos tmp |=PIIX4_SMBHSTCNT_INTREN; 321253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 322253572Sloos} 323253572Sloos 324253572Sloos/*Polling Code. Polling is not encouraged 325253572Sloos * because It is required to wait for the device get busy. 326253572Sloos *(29063505.pdf from Intel) 327253572Sloos * But during boot,intrrupt cannot be used. 328253572Sloos * so use polling code while in autoconfiguration. 329253572Sloos */ 330253572Sloos 331279797Sadrianstatic int 332253572Sloosintsmb_stop_poll(device_t dev){ 333253572Sloos int error,i; 334253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 335253572Sloos 336253572Sloos /* 337253572Sloos * In smbtx driver ,Simply waiting. 338253572Sloos * This loops 100-200 times. 339253572Sloos */ 340253572Sloos for(i=0;i<0x7fff;i++){ 341253572Sloos if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 342253572Sloos &PIIX4_SMBHSTSTAT_BUSY)){ 343253572Sloos break; 344253572Sloos } 345253572Sloos } 346253572Sloos for(i=0;i<0x7fff;i++){ 347253572Sloos int status; 348253572Sloos status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 349253572Sloos if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 350253572Sloos sc->isbusy=0; 351253572Sloos error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 352253572Sloos (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 353279943Sadrian (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 354279943Sadrian if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 355253572Sloos printf("unknown cause why?"); 356253572Sloos } 357279790Sadrian return error; 358253572Sloos } 359253572Sloos } 360253572Sloos { 361253572Sloos int tmp; 362253572Sloos sc->isbusy=0; 363253572Sloos tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 364253572Sloos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 365253572Sloos tmp&~PIIX4_SMBHSTCNT_INTREN); 366253572Sloos } 367262429Sadrian return EIO; 368253572Sloos} 369253572Sloos/* 370253572Sloos *wait for completion and return result. 371253572Sloos */ 372253572Sloosstatic int 373253572Sloosintsmb_stop(device_t dev){ 374253572Sloos int error; 375253572Sloos intrmask_t s; 376253572Sloos struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 377253572Sloos if(cold){ 378262429Sadrian /*So that it can use device during probing device on SMBus.*/ 379253572Sloos error=intsmb_stop_poll(dev); 380253572Sloos return error; 381253572Sloos }else{ 382253572Sloos if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 383253572Sloos int status; 384253572Sloos status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 385 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 386 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 387 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 388 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 389 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 390 printf("intsmb%d:unknown cause why?\n", 391 device_get_unit(dev)); 392 } 393#ifdef ENABLE_ALART 394 bus_space_write_1(sc->st,sc->sh, 395 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 396#endif 397 return error; 398 } 399 } 400 } 401 /*Timeout Procedure*/ 402 s=splhigh(); 403 sc->isbusy=0; 404 /*Re-enable supressed intrrupt from slave part*/ 405 bus_space_write_1(sc->st,sc->sh, 406 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 407 splx(s); 408 return EIO; 409} 410 411static int 412intsmb_quick(device_t dev, u_char slave, int how) 413{ 414 int error=0; 415 u_char data; 416 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 417 data=slave; 418 /*Quick command is part of Address, I think*/ 419 switch(how){ 420 case SMB_QWRITE: 421 data&=~LSB; 422 break; 423 case SMB_QREAD: 424 data|=LSB; 425 break; 426 default: 427 error=EINVAL; 428 } 429 if(!error){ 430 error=intsmb_free(dev); 431 if(!error){ 432 bus_space_write_1(sc->st,sc->sh, 433 PIIX4_SMBHSTADD,data); 434 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 435 error=intsmb_stop(dev); 436 } 437 } 438 439 return (error); 440} 441 442static int 443intsmb_sendb(device_t dev, u_char slave, char byte) 444{ 445 int error; 446 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 447 error=intsmb_free(dev); 448 if(!error){ 449 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 450 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 451 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 452 error=intsmb_stop(dev); 453 } 454 return (error); 455} 456static int 457intsmb_recvb(device_t dev, u_char slave, char *byte) 458{ 459 int error; 460 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 461 error=intsmb_free(dev); 462 if(!error){ 463 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 464 |LSB); 465 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 466 if(!(error=intsmb_stop(dev))){ 467#ifdef RECV_IS_IN_CMD 468 /*Linux SMBus stuff also troubles 469 Because Intel's datasheet will not make clear. 470 */ 471 *byte=bus_space_read_1(sc->st,sc->sh, 472 PIIX4_SMBHSTCMD); 473#else 474 *byte=bus_space_read_1(sc->st,sc->sh, 475 PIIX4_SMBHSTDAT0); 476#endif 477 } 478 } 479 return (error); 480} 481static int 482intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 483{ 484 int error; 485 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 486 error=intsmb_free(dev); 487 if(!error){ 488 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 489 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 490 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 491 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 492 error=intsmb_stop(dev); 493 } 494 return (error); 495} 496static int 497intsmb_writew(device_t dev, u_char slave, char cmd, short word) 498{ 499 int error; 500 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 501 error=intsmb_free(dev); 502 if(!error){ 503 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 504 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 505 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 506 word&0xff); 507 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 508 (word>>8)&0xff); 509 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 510 error=intsmb_stop(dev); 511 } 512 return (error); 513} 514 515static int 516intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 517{ 518 int error; 519 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 520 error=intsmb_free(dev); 521 if(!error){ 522 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 523 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 524 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 525 if(!(error=intsmb_stop(dev))){ 526 *byte=bus_space_read_1(sc->st,sc->sh, 527 PIIX4_SMBHSTDAT0); 528 } 529 } 530 return (error); 531} 532static int 533intsmb_readw(device_t dev, u_char slave, char cmd, short *word) 534{ 535 int error; 536 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 537 error=intsmb_free(dev); 538 if(!error){ 539 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 540 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 541 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 542 if(!(error=intsmb_stop(dev))){ 543 *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 544 *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 545 } 546 } 547 return (error); 548} 549/* 550 * Data sheet claims that it implements all function, but also claims 551 * that it implements 7 function and not mention PCALL. So I don't know 552 * whether it will work. 553 */ 554static int 555intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 556{ 557#ifdef PROCCALL_TEST 558 int error; 559 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 560 error=intsmb_free(dev); 561 if(!error){ 562 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 563 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 564 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 565 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 566 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 567 } 568 if(!(error=intsmb_stop(dev))){ 569 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 570 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 571 } 572 return error; 573#else 574 return 0; 575#endif 576} 577static int 578intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 579{ 580 int error,i; 581 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 582 error=intsmb_free(dev); 583 if(count>SMBBLOCKTRANS_MAX||count==0) 584 error=EINVAL; 585 if(!error){ 586 /*Reset internal array index*/ 587 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 588 589 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 590 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 591 for(i=0;i<count;i++){ 592 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 593 } 594 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 595 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 596 error=intsmb_stop(dev); 597 } 598 return (error); 599} 600 601static int 602intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 603{ 604 int error,i; 605 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 606 error=intsmb_free(dev); 607 if(count>SMBBLOCKTRANS_MAX||count==0) 608 error=EINVAL; 609 if(!error){ 610 /*Reset internal array index*/ 611 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 612 613 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 614 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 615 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 616 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 617 error=intsmb_stop(dev); 618 if(!error){ 619 bzero(buf,count);/*Is it needed?*/ 620 count= bus_space_read_1(sc->st,sc->sh, 621 PIIX4_SMBHSTDAT0); 622 if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 623 for(i=0;i<count;i++){ 624 buf[i]=bus_space_read_1(sc->st, 625 sc->sh, 626 PIIX4_SMBBLKDAT); 627 } 628 } 629 else{ 630 error=EIO; 631 } 632 } 633 } 634 return (error); 635} 636 637DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 638 639 640static void intpm_intr __P((void *arg)); 641static int 642intpm_attach(device_t dev) 643{ 644 int value; 645 int unit=device_get_unit(dev); 646 void *ih; 647 int error; 648 char * str; 649 { 650 struct intpm_pci_softc *sciic; 651 device_t smbinterface; 652 int rid; 653 struct resource *res; 654 655 sciic=device_get_softc(dev); 656 if(sciic==NULL){ 657 return ENOMEM; 658 } 659 660 rid=PCI_BASE_ADDR_SMB; 661 res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid, 662 0,~0,1,RF_ACTIVE); 663 if(res==NULL){ 664 device_printf(dev,"Could not allocate Bus space\n"); 665 return ENXIO; 666 } 667 sciic->smbst=rman_get_bustag(res); 668 sciic->smbsh=rman_get_bushandle(res); 669 670 device_printf(dev,"%s %x\n", 671 (sciic->smbst==I386_BUS_SPACE_IO)? 672 "I/O mapped":"Memory", 673 sciic->smbsh); 674 675 676#ifndef NO_CHANGE_PCICONF 677 pci_write_config(dev,PCIR_INTLINE,0x9,1); 678 pci_write_config(dev,PCI_HST_CFG_SMB, 679 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 680#endif 681 value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 682 switch(value&0xe){ 683 case PCI_INTR_SMB_SMI: 684 str="SMI"; 685 break; 686 case PCI_INTR_SMB_IRQ9: 687 str="IRQ 9"; 688 break; 689 default: 690 str="BOGUS"; 691 } 692 device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 693 value=pci_read_config(dev,PCI_REVID_SMB,1); 694 printf("revision %d\n",value); 695 /* 696 * Install intr HANDLER here 697 */ 698 rid=0; 699 res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 700 if(res==NULL){ 701 device_printf(dev,"could not allocate irq"); 702 return ENOMEM; 703 } 704 error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih); 705 if(error){ 706 device_printf(dev,"Failed to map intr\n"); 707 return error; 708 } 709 smbinterface=device_add_child(dev,"intsmb",unit); 710 if(!smbinterface){ 711 printf("intsmb%d:could not add SMBus device\n",unit); 712 } 713 device_probe_and_attach(smbinterface); 714 } 715 716 value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 717 printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 718 return 0; 719} 720static int 721intpm_probe(device_t dev) 722{ 723 struct _pcsid *ep =pci_ids; 724 u_int32_t device_id=pci_get_devid(dev); 725 726 while (ep->type && ep->type != device_id) 727 ++ep; 728 if(ep->desc!=NULL){ 729 device_set_desc(dev,ep->desc); 730 bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */ 731 return 0; 732 }else{ 733 return ENXIO; 734 } 735} 736DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 737 738static void intpm_intr(void *arg) 739{ 740 struct intpm_pci_softc *sc; 741 sc=(struct intpm_pci_softc *)arg; 742 intsmb_intr(sc->smbus); 743 intsmb_slvintr(sc->smbus); 744 745} 746