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