intpm.c revision 49064
126238Swpaul/*- 226238Swpaul * Copyright (c) 1998, 1999 Takanori Watanabe 326238Swpaul * All rights reserved. 426238Swpaul * 526238Swpaul * Redistribution and use in source and binary forms, with or without 626238Swpaul * modification, are permitted provided that the following conditions 726238Swpaul * are met: 826238Swpaul * 1. Redistributions of source code must retain the above copyright 926238Swpaul * notice, this list of conditions and the following disclaimer. 1026238Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1126238Swpaul * notice, this list of conditions and the following disclaimer in the 1226238Swpaul * documentation and/or other materials provided with the distribution. 1326238Swpaul * 1426238Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1526238Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1626238Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1726238Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1826238Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1926238Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026238Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2126238Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2226238Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2326238Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2426238Swpaul * SUCH DAMAGE. 2526238Swpaul * 2626238Swpaul * $Id: intpm.c,v 1.11 1999/07/03 20:17:06 peter Exp $ 2726238Swpaul */ 2826238Swpaul 2926238Swpaul#include <sys/param.h> 3095633Smarkm#include <sys/systm.h> 3126238Swpaul#include <sys/kernel.h> 3227754Scharnier#include <machine/bus_pio.h> 3326238Swpaul#include <machine/bus_memio.h> 3426238Swpaul#include <machine/bus.h> 3527754Scharnier 3626238Swpaul#include <machine/clock.h> 3726238Swpaul#include <sys/uio.h> 3826238Swpaul#include <sys/module.h> 3926238Swpaul#include <sys/bus.h> 4026238Swpaul#include <sys/conf.h> 4126238Swpaul#include <sys/malloc.h> 4226238Swpaul#include <sys/buf.h> 4326238Swpaul#include <sys/rman.h> 4495633Smarkm#include <machine/resource.h> 4595633Smarkm#include <dev/smbus/smbconf.h> 4695633Smarkm 4787204Smarkm#include "smbus_if.h" 4887204Smarkm 4987204Smarkm/*This should be removed if force_pci_map_int supported*/ 5095633Smarkm#include <sys/interrupt.h> 5126238Swpaul 5226238Swpaul#include <pci/pcireg.h> 5395633Smarkm#include <pci/pcivar.h> 5426238Swpaul#include <pci/intpmreg.h> 5587204Smarkm 5626238Swpaul#include "opt_intpm.h" 5726238Swpaul 5826238Swpaulstatic struct _pcsid 5926238Swpaul{ 6095633Smarkm pcidi_t type; 61200462Sdelphij char *desc; 6287204Smarkm} pci_ids[] = 6387204Smarkm{ 6426238Swpaul { 0x71138086,"Intel 82371AB Power management controller"}, 6527754Scharnier 6626238Swpaul { 0x00000000, NULL } 6787204Smarkm}; 6826238Swpaulstatic int intsmb_probe(device_t); 6926238Swpaulstatic int intsmb_attach(device_t); 7026238Swpaulstatic void intsmb_print_child(device_t, device_t); 7126238Swpaul 7226238Swpaulstatic int intsmb_intr(device_t dev); 7326238Swpaulstatic int intsmb_slvintr(device_t dev); 7492921Simpstatic void intsmb_alrintr(device_t dev); 7592921Simpstatic int intsmb_callback(device_t dev, int index, caddr_t data); 7626238Swpaulstatic int intsmb_quick(device_t dev, u_char slave, int how); 7726238Swpaulstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 7826238Swpaulstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 7926238Swpaulstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 8026238Swpaulstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 8126238Swpaulstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 8287204Smarkmstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 8395633Smarkmstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 8495633Smarkmstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8526238Swpaulstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 8626238Swpaulstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 8726238Swpaulstatic int intsmb_stop(device_t dev); 8826238Swpaulstatic int intsmb_stop_poll(device_t dev); 8926238Swpaulstatic int intsmb_free(device_t dev); 9026238Swpaulstatic int intpm_probe (device_t dev); 9126238Swpaulstatic int intpm_attach (device_t dev); 9226238Swpaulstatic devclass_t intsmb_devclass; 9326238Swpaul 9426238Swpaulstatic device_method_t intpm_methods[]={ 9526238Swpaul DEVMETHOD(device_probe,intsmb_probe), 9626238Swpaul DEVMETHOD(device_attach,intsmb_attach), 9726238Swpaul 9826238Swpaul DEVMETHOD(bus_print_child, intsmb_print_child), 9926238Swpaul 10026238Swpaul DEVMETHOD(smbus_callback,intsmb_callback), 10126238Swpaul DEVMETHOD(smbus_quick,intsmb_quick), 10226238Swpaul DEVMETHOD(smbus_sendb,intsmb_sendb), 10326238Swpaul DEVMETHOD(smbus_recvb,intsmb_recvb), 10426238Swpaul DEVMETHOD(smbus_writeb,intsmb_writeb), 10526238Swpaul DEVMETHOD(smbus_writew,intsmb_writew), 10626238Swpaul DEVMETHOD(smbus_readb,intsmb_readb), 10726238Swpaul DEVMETHOD(smbus_readw,intsmb_readw), 10826238Swpaul DEVMETHOD(smbus_pcall,intsmb_pcall), 10926238Swpaul DEVMETHOD(smbus_bwrite,intsmb_bwrite), 11026238Swpaul DEVMETHOD(smbus_bread,intsmb_bread), 11126238Swpaul {0,0} 11226238Swpaul}; 11326238Swpaul 11426238Swpaulstruct intpm_pci_softc{ 11526238Swpaul bus_space_tag_t smbst; 11626238Swpaul bus_space_handle_t smbsh; 11726238Swpaul bus_space_tag_t pmst; 11826238Swpaul bus_space_handle_t pmsh; 11926238Swpaul pcici_t cfg; 12026238Swpaul device_t smbus; 12126238Swpaul}; 12226238Swpaul 12326238Swpaul 12426238Swpaulstruct intsmb_softc{ 12526238Swpaul struct intpm_pci_softc *pci_sc; 12626238Swpaul bus_space_tag_t st; 12726238Swpaul bus_space_handle_t sh; 12826238Swpaul device_t smbus; 12926238Swpaul int isbusy; 13026238Swpaul}; 13126238Swpaul 13226238Swpaulstatic driver_t intpm_driver = { 13326238Swpaul "intsmb", 13426238Swpaul intpm_methods, 13526238Swpaul sizeof(struct intsmb_softc), 13626238Swpaul}; 13726238Swpaul 13826238Swpaulstatic devclass_t intpm_devclass; 13926238Swpaulstatic device_method_t intpm_pci_methods[] = { 14026238Swpaul DEVMETHOD(device_probe,intpm_probe), 14187204Smarkm DEVMETHOD(device_attach,intpm_attach), 14295633Smarkm {0,0} 14326238Swpaul}; 14426238Swpaulstatic driver_t intpm_pci_driver = { 14526238Swpaul "intpm", 14626238Swpaul intpm_pci_methods, 14726238Swpaul sizeof(struct intpm_pci_softc) 14826238Swpaul}; 14926238Swpaul 15026238Swpaulstatic int 15126238Swpaulintsmb_probe(device_t dev) 15226238Swpaul{ 15326238Swpaul struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 15426238Swpaul sc->smbus=smbus_alloc_bus(dev); 15526238Swpaul if (!sc->smbus) 15626238Swpaul return (EINVAL); /* XXX don't know what to return else */ 15726238Swpaul device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 15826238Swpaul 15926238Swpaul return (0); /* XXX don't know what to return else */ 16026238Swpaul} 16126238Swpaulstatic int 16226238Swpaulintsmb_attach(device_t dev) 16326238Swpaul{ 16426238Swpaul struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 16526238Swpaul sc->pci_sc=device_get_softc(device_get_parent(dev)); 16626238Swpaul sc->isbusy=0; 16726238Swpaul sc->sh=sc->pci_sc->smbsh; 16826238Swpaul sc->st=sc->pci_sc->smbst; 16926238Swpaul sc->pci_sc->smbus=dev; 17026238Swpaul device_probe_and_attach(sc->smbus); 17126238Swpaul#ifdef ENABLE_ALART 17226238Swpaul /*Enable Arart*/ 17326238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 17426238Swpaul PIIX4_SMBSLVCNT_ALTEN); 17526238Swpaul#endif 17626238Swpaul return (0); 17726238Swpaul} 17879452Sbrian 17926238Swpaulstatic void 18026238Swpaulintsmb_print_child(device_t bus, device_t dev) 18126238Swpaul{ 18226238Swpaul printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 18326238Swpaul return; 18426238Swpaul} 18526238Swpaulstatic int 18626238Swpaulintsmb_callback(device_t dev, int index, caddr_t data) 18726238Swpaul{ 18826238Swpaul int error = 0; 18926238Swpaul intrmask_t s; 19026238Swpaul s=splnet(); 19126238Swpaul switch (index) { 19226238Swpaul case SMB_REQUEST_BUS: 19326238Swpaul break; 19426238Swpaul case SMB_RELEASE_BUS: 19526238Swpaul break; 19626238Swpaul default: 19726238Swpaul error = EINVAL; 19826238Swpaul } 19926238Swpaul splx(s); 20026238Swpaul return (error); 20126238Swpaul} 20226238Swpaul/*counterpart of smbtx_smb_free*/ 20326238Swpaulstatic int 20426238Swpaulintsmb_free(device_t dev){ 20526238Swpaul intrmask_t s; 20626238Swpaul struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 20795633Smarkm if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 20826238Swpaul PIIX4_SMBHSTSTAT_BUSY) 20926238Swpaul#ifdef ENABLE_ALART 21026238Swpaul ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 21126238Swpaul PIIX4_SMBSLVSTS_BUSY) 21226238Swpaul#endif 21326238Swpaul || sc->isbusy) 21426238Swpaul return EBUSY; 21526238Swpaul s=splhigh(); 21626238Swpaul sc->isbusy=1; 21726238Swpaul /*Disable Intrrupt in slave part*/ 21826238Swpaul#ifndef ENABLE_ALART 21926238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 22026238Swpaul#endif 22126238Swpaul /*Reset INTR Flag to prepare INTR*/ 22226238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 22326238Swpaul (PIIX4_SMBHSTSTAT_INTR| 22426238Swpaul PIIX4_SMBHSTSTAT_ERR| 22526238Swpaul PIIX4_SMBHSTSTAT_BUSC| 22626238Swpaul PIIX4_SMBHSTSTAT_FAIL) 22726238Swpaul ); 22895633Smarkm splx(s); 22926238Swpaul return 0; 23026238Swpaul} 23126238Swpaul 23226238Swpaulstatic int 23326238Swpaulintsmb_intr(device_t dev) 23426238Swpaul{ 23526238Swpaul struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 236141482Sstefanf int status; 237189169Sed status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 238189169Sed if(status&PIIX4_SMBHSTSTAT_BUSY){ 23926238Swpaul return 1; 24026238Swpaul 24126238Swpaul } 24226238Swpaul if(status&(PIIX4_SMBHSTSTAT_INTR| 24326238Swpaul PIIX4_SMBHSTSTAT_ERR| 24426238Swpaul PIIX4_SMBHSTSTAT_BUSC| 24526238Swpaul PIIX4_SMBHSTSTAT_FAIL)){ 24626238Swpaul int tmp; 24726238Swpaul tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 24826238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 24926238Swpaul tmp&~PIIX4_SMBHSTCNT_INTREN); 25026238Swpaul if(sc->isbusy){ 25126238Swpaul sc->isbusy=0; 25226238Swpaul wakeup(sc); 25326238Swpaul } 25426238Swpaul return 0; 25526238Swpaul } 25626238Swpaul return 1;/* Not Completed*/ 25726238Swpaul} 25826238Swpaulstatic int 25926238Swpaulintsmb_slvintr(device_t dev) 26026238Swpaul{ 26126238Swpaul struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 26226238Swpaul int status,retval; 26326238Swpaul retval=1; 26426238Swpaul status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 26526238Swpaul if(status&PIIX4_SMBSLVSTS_BUSY) 26626238Swpaul return retval; 26726238Swpaul if(status&PIIX4_SMBSLVSTS_ALART){ 26826238Swpaul intsmb_alrintr(dev); 269344193Savos retval=0; 270344193Savos }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 27126238Swpaul |PIIX4_SMBSLVSTS_SDW1)){ 27226238Swpaul retval=0; 27326238Swpaul } 274344193Savos /*Reset Status Register*/ 275344193Savos bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 276344193Savos PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 27726238Swpaul PIIX4_SMBSLVSTS_SLV); 27826238Swpaul return retval; 27926238Swpaul} 28026238Swpaul 28126238Swpaulstatic void intsmb_alrintr(device_t dev) 28226238Swpaul{ 28326238Swpaul struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 28426238Swpaul int slvcnt; 28526238Swpaul#ifdef ENABLE_ALART 28626238Swpaul int error; 28726238Swpaul#endif 28826238Swpaul 28926238Swpaul /*stop generating INTR from ALART*/ 29026238Swpaul slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 29126238Swpaul#ifdef ENABLE_ALART 29226238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 29326238Swpaul slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 29426238Swpaul#endif 29526238Swpaul DELAY(5); 29626238Swpaul /*ask bus who assert it and then ask it what's the matter. */ 29726238Swpaul#ifdef ENABLE_ALART 29826238Swpaul error=intsmb_free(dev); 29926238Swpaul if(!error){ 30026238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 30126238Swpaul |LSB); 30226238Swpaul intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 30326238Swpaul if(!(error=intsmb_stop_poll(dev))){ 30426238Swpaul volatile u_int8_t *addr; 30526238Swpaul addr=bus_space_read_1(sc->st,sc->sh, 30626238Swpaul PIIX4_SMBHSTDAT0); 30726238Swpaul printf("ALART_RESPONSE: %p\n", addr); 30826238Swpaul } 30926238Swpaul }else{ 31026238Swpaul printf("ERROR\n"); 31126238Swpaul } 31226238Swpaul 31326238Swpaul /*Re-enable INTR from ALART*/ 31426238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 31526238Swpaul slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 316344193Savos DELAY(5); 317344193Savos#endif 31826238Swpaul 31926238Swpaul return; 32026238Swpaul} 321344193Savosstatic void 322344193Savosintsmb_start(device_t dev,unsigned char cmd,int nointr) 32326238Swpaul{ 32426238Swpaul struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 325344193Savos unsigned char tmp; 326344193Savos tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 327344193Savos tmp&= 0xe0; 32826238Swpaul tmp |= cmd; 32926238Swpaul tmp |=PIIX4_SMBHSTCNT_START; 33026238Swpaul /*While not in autoconfiguration Intrrupt Enabled*/ 331141482Sstefanf if(!cold||!nointr) 33295633Smarkm tmp |=PIIX4_SMBHSTCNT_INTREN; 33326238Swpaul bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 33426238Swpaul} 33526238Swpaul 33626238Swpaul/*Polling Code. Polling is not encouraged 33726238Swpaul * because It is required to wait for the device get busy. 33826238Swpaul *(29063505.pdf from Intel) 33926238Swpaul * But during boot,intrrupt cannot be used. 34026238Swpaul * so use polling code while in autoconfiguration. 341 */ 342 343static int 344intsmb_stop_poll(device_t dev){ 345 int error,i; 346 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 347 348 /* 349 * In smbtx driver ,Simply waiting. 350 * This loops 100-200 times. 351 */ 352 for(i=0;i<0x7fff;i++){ 353 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 354 &PIIX4_SMBHSTSTAT_BUSY)){ 355 break; 356 } 357 } 358 for(i=0;i<0x7fff;i++){ 359 int status; 360 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 361 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 362 sc->isbusy=0; 363 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 364 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 365 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 366 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 367 printf("unknown cause why?"); 368 } 369 return error; 370 } 371 } 372 { 373 int tmp; 374 sc->isbusy=0; 375 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 376 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 377 tmp&~PIIX4_SMBHSTCNT_INTREN); 378 } 379 return EIO; 380} 381/* 382 *wait for completion and return result. 383 */ 384static int 385intsmb_stop(device_t dev){ 386 int error; 387 intrmask_t s; 388 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 389 if(cold){ 390 /*So that it can use device during probing device on SMBus.*/ 391 error=intsmb_stop_poll(dev); 392 return error; 393 }else{ 394 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 395 int status; 396 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 397 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 398 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 399 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 400 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 401 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 402 printf("intsmb%d:unknown cause why?\n", 403 device_get_unit(dev)); 404 } 405#ifdef ENABLE_ALART 406 bus_space_write_1(sc->st,sc->sh, 407 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 408#endif 409 return error; 410 } 411 } 412 } 413 /*Timeout Procedure*/ 414 s=splhigh(); 415 sc->isbusy=0; 416 /*Re-enable supressed intrrupt from slave part*/ 417 bus_space_write_1(sc->st,sc->sh, 418 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 419 splx(s); 420 return EIO; 421} 422 423static int 424intsmb_quick(device_t dev, u_char slave, int how) 425{ 426 int error=0; 427 u_char data; 428 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 429 data=slave; 430 /*Quick command is part of Address, I think*/ 431 switch(how){ 432 case SMB_QWRITE: 433 data&=~LSB; 434 break; 435 case SMB_QREAD: 436 data|=LSB; 437 break; 438 default: 439 error=EINVAL; 440 } 441 if(!error){ 442 error=intsmb_free(dev); 443 if(!error){ 444 bus_space_write_1(sc->st,sc->sh, 445 PIIX4_SMBHSTADD,data); 446 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 447 error=intsmb_stop(dev); 448 } 449 } 450 451 return (error); 452} 453 454static int 455intsmb_sendb(device_t dev, u_char slave, char byte) 456{ 457 int error; 458 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 459 error=intsmb_free(dev); 460 if(!error){ 461 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 462 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 463 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 464 error=intsmb_stop(dev); 465 } 466 return (error); 467} 468static int 469intsmb_recvb(device_t dev, u_char slave, char *byte) 470{ 471 int error; 472 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 473 error=intsmb_free(dev); 474 if(!error){ 475 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 476 |LSB); 477 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 478 if(!(error=intsmb_stop(dev))){ 479#ifdef RECV_IS_IN_CMD 480 /*Linux SMBus stuff also troubles 481 Because Intel's datasheet will not make clear. 482 */ 483 *byte=bus_space_read_1(sc->st,sc->sh, 484 PIIX4_SMBHSTCMD); 485#else 486 *byte=bus_space_read_1(sc->st,sc->sh, 487 PIIX4_SMBHSTDAT0); 488#endif 489 } 490 } 491 return (error); 492} 493static int 494intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 495{ 496 int error; 497 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 498 error=intsmb_free(dev); 499 if(!error){ 500 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 501 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 502 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 503 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 504 error=intsmb_stop(dev); 505 } 506 return (error); 507} 508static int 509intsmb_writew(device_t dev, u_char slave, char cmd, short word) 510{ 511 int error; 512 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 513 error=intsmb_free(dev); 514 if(!error){ 515 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 516 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 517 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 518 word&0xff); 519 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 520 (word>>8)&0xff); 521 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 522 error=intsmb_stop(dev); 523 } 524 return (error); 525} 526 527static int 528intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 529{ 530 int error; 531 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 532 error=intsmb_free(dev); 533 if(!error){ 534 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 535 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 536 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 537 if(!(error=intsmb_stop(dev))){ 538 *byte=bus_space_read_1(sc->st,sc->sh, 539 PIIX4_SMBHSTDAT0); 540 } 541 } 542 return (error); 543} 544static int 545intsmb_readw(device_t dev, u_char slave, char cmd, short *word) 546{ 547 int error; 548 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 549 error=intsmb_free(dev); 550 if(!error){ 551 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 552 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 553 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 554 if(!(error=intsmb_stop(dev))){ 555 *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 556 *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 557 } 558 } 559 return (error); 560} 561/* 562 * Data sheet claims that it implements all function, but also claims 563 * that it implements 7 function and not mention PCALL. So I don't know 564 * whether it will work. 565 */ 566static int 567intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 568{ 569#ifdef PROCCALL_TEST 570 int error; 571 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 572 error=intsmb_free(dev); 573 if(!error){ 574 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 575 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 576 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 577 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 578 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 579 } 580 if(!(error=intsmb_stop(dev))){ 581 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 582 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 583 } 584 return error; 585#else 586 return 0; 587#endif 588} 589static int 590intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 591{ 592 int error,i; 593 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 594 error=intsmb_free(dev); 595 if(count>SMBBLOCKTRANS_MAX||count==0) 596 error=EINVAL; 597 if(!error){ 598 /*Reset internal array index*/ 599 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 600 601 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 602 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 603 for(i=0;i<count;i++){ 604 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 605 } 606 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 607 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 608 error=intsmb_stop(dev); 609 } 610 return (error); 611} 612 613static int 614intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 615{ 616 int error,i; 617 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 618 error=intsmb_free(dev); 619 if(count>SMBBLOCKTRANS_MAX||count==0) 620 error=EINVAL; 621 if(!error){ 622 /*Reset internal array index*/ 623 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 624 625 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 626 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 627 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 628 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 629 error=intsmb_stop(dev); 630 if(!error){ 631 bzero(buf,count);/*Is it needed?*/ 632 count= bus_space_read_1(sc->st,sc->sh, 633 PIIX4_SMBHSTDAT0); 634 if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 635 for(i=0;i<count;i++){ 636 buf[i]=bus_space_read_1(sc->st, 637 sc->sh, 638 PIIX4_SMBBLKDAT); 639 } 640 } 641 else{ 642 error=EIO; 643 } 644 } 645 } 646 return (error); 647} 648 649DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 650 651 652static void intpm_intr __P((void *arg)); 653static int 654intpm_attach(device_t dev) 655{ 656 int value; 657 int unit=device_get_unit(dev); 658 void *ih; 659 int error; 660 char * str; 661 { 662 struct intpm_pci_softc *sciic; 663 device_t smbinterface; 664 int rid; 665 struct resource *res; 666 667 sciic=device_get_softc(dev); 668 if(sciic==NULL){ 669 return ENOMEM; 670 } 671 672 rid=PCI_BASE_ADDR_SMB; 673#if 0 674 res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid, 675 0,~0,1,RF_ACTIVE); 676 if(res==NULL){ 677 device_printf(dev,"IO FAILED Trying Memory\n"); 678 res=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0, 679 1,RF_ACTIVE); 680 } 681#else 682 /*Do as I tell!*/ 683 value=pci_read_config(dev,rid,4); 684 res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,value&(~1), 685 (value&(~1))+256,256,RF_ACTIVE); 686#endif 687 if(res==NULL){ 688 device_printf(dev,"Could not allocate Bus space\n"); 689 return ENXIO; 690 } 691 sciic->smbst=rman_get_bustag(res); 692 sciic->smbsh=rman_get_bushandle(res); 693 694 device_printf(dev,"%s %x\n", 695 (sciic->smbst==I386_BUS_SPACE_IO)? 696 "I/O mapped":"Memory", 697 sciic->smbsh); 698 699 700#ifndef NO_CHANGE_PCICONF 701 pci_write_config(dev,PCIR_INTLINE,0x9,1); 702 pci_write_config(dev,PCI_HST_CFG_SMB, 703 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 704#endif 705 value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 706 switch(value&0xe){ 707 case PCI_INTR_SMB_SMI: 708 str="SMI"; 709 break; 710 case PCI_INTR_SMB_IRQ9: 711 str="IRQ 9"; 712 break; 713 default: 714 str="BOGUS"; 715 } 716 device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 717 value=pci_read_config(dev,PCI_REVID_SMB,1); 718 printf("revision %d\n",value); 719 /* 720 * Install intr HANDLER here 721 */ 722 rid=0; 723 res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 724 if(res==NULL){ 725 device_printf(dev,"could not allocate irq"); 726 return ENOMEM; 727 } 728 error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih); 729 if(error){ 730 device_printf(dev,"Failed to map intr\n"); 731 return error; 732 } 733 smbinterface=device_add_child(dev,"intsmb",unit,NULL); 734 if(!smbinterface){ 735 printf("intsmb%d:could not add SMBus device\n",unit); 736 } 737 device_probe_and_attach(smbinterface); 738 } 739 740 value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 741 printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 742 return 0; 743} 744static int 745intpm_probe(device_t dev) 746{ 747 struct _pcsid *ep =pci_ids; 748 u_int32_t device_id=pci_get_devid(dev); 749 750 while (ep->type && ep->type != device_id) 751 ++ep; 752 if(ep->desc!=NULL){ 753 device_set_desc(dev,ep->desc); 754 return 0; 755 }else{ 756 return ENXIO; 757 } 758} 759DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 760 761static void intpm_intr(void *arg) 762{ 763 struct intpm_pci_softc *sc; 764 sc=(struct intpm_pci_softc *)arg; 765 intsmb_intr(sc->smbus); 766 intsmb_slvintr(sc->smbus); 767 768} 769