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