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