intpm.c revision 43166
1238603Sjoerg/*-
2238603Sjoerg * Copyright (c) 1998, 1999 Takanori Watanabe
3238603Sjoerg * All rights reserved.
4238603Sjoerg *
5238603Sjoerg * Redistribution and use in source and binary forms, with or without
6238603Sjoerg * modification, are permitted provided that the following conditions
7238603Sjoerg * are met:
8238603Sjoerg * 1. Redistributions of source code must retain the above copyright
9238603Sjoerg *        notice, this list of conditions and the following disclaimer.
10238603Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
11238603Sjoerg *        notice, this list of conditions and the following disclaimer in the
12238603Sjoerg *        documentation and/or other materials provided with the distribution.
13238603Sjoerg *
14238603Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15238603Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16238603Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17238603Sjoerg * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18238603Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19238603Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20238603Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21238603Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22238603Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23238603Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24238603Sjoerg * SUCH DAMAGE.
25238603Sjoerg *
26238603Sjoerg *	$Id$
27238603Sjoerg */
28238603Sjoerg
29238603Sjoerg#include "pci.h"
30238603Sjoerg#include "intpm.h"
31238603Sjoerg
32238603Sjoerg#if NPCI > 0
33238603Sjoerg#if NINTPM >0
34238603Sjoerg/* I don't think the chip is used in other architecture. :-)*/
35238603Sjoerg#include <sys/param.h>
36238603Sjoerg#include <sys/systm.h>
37238603Sjoerg#include <sys/kernel.h>
38238603Sjoerg
39257779Shselasky#include <machine/bus_pio.h>
40238603Sjoerg#include <machine/bus_memio.h>
41238603Sjoerg#include <machine/bus.h>
42238603Sjoerg
43238603Sjoerg#include <machine/clock.h>
44238603Sjoerg#include <sys/uio.h>
45238603Sjoerg#include <sys/module.h>
46257779Shselasky#include <sys/bus.h>
47257779Shselasky#include <sys/conf.h>
48238603Sjoerg#include <sys/malloc.h>
49238603Sjoerg#include <sys/buf.h>
50238603Sjoerg
51238603Sjoerg#include <dev/smbus/smbconf.h>
52238603Sjoerg
53238603Sjoerg#include "smbus_if.h"
54238603Sjoerg
55238603Sjoerg/*This should be removed if force_pci_map_int supported*/
56238603Sjoerg#include <sys/interrupt.h>
57238603Sjoerg
58238603Sjoerg#include <pci/pcireg.h>
59238603Sjoerg#include <pci/pcivar.h>
60238603Sjoerg#include <pci/intpmreg.h>
61238603Sjoerg
62238603Sjoerg#include "opt_intpm.h"
63238603Sjoerg
64238603Sjoergstatic struct _pcsid
65238603Sjoerg{
66238603Sjoerg        pcidi_t type;
67238603Sjoerg	char	*desc;
68238603Sjoerg} pci_ids[] =
69238603Sjoerg{
70238603Sjoerg	{ 0x71138086,"Intel 82371AB Power management controller"},
71238603Sjoerg
72238603Sjoerg	{ 0x00000000,	NULL					}
73238603Sjoerg};
74238603Sjoergstatic int intsmb_probe(device_t);
75238603Sjoergstatic int intsmb_attach(device_t);
76238603Sjoergstatic void intsmb_print_child(device_t, device_t);
77238603Sjoerg
78238603Sjoergstatic int intsmb_intr(device_t dev);
79238603Sjoergstatic int intsmb_slvintr(device_t dev);
80238603Sjoergstatic void  intsmb_alrintr(device_t dev);
81238603Sjoergstatic int intsmb_callback(device_t dev, int index, caddr_t data);
82238603Sjoergstatic int intsmb_quick(device_t dev, u_char slave, int how);
83238603Sjoergstatic int intsmb_sendb(device_t dev, u_char slave, char byte);
84238603Sjoergstatic int intsmb_recvb(device_t dev, u_char slave, char *byte);
85238603Sjoergstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
86238603Sjoergstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
87238603Sjoergstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
88238603Sjoergstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
89238603Sjoergstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
90257779Shselaskystatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
91238603Sjoergstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
92238603Sjoergstatic void intsmb_start(device_t dev,u_char cmd,int nointr);
93238603Sjoergstatic int intsmb_stop(device_t dev);
94238603Sjoergstatic int intsmb_stop_poll(device_t dev);
95238603Sjoergstatic int intsmb_free(device_t dev);
96238603Sjoergstatic struct intpm_pci_softc *intpm_alloc(int unit);
97238603Sjoergstatic const char* intpm_probe __P((pcici_t tag, pcidi_t type));
98238603Sjoergstatic void intpm_attach __P((pcici_t config_id, int unit));
99238603Sjoergstatic devclass_t intsmb_devclass;
100257779Shselasky
101238603Sjoergstatic device_method_t intpm_methods[]={
102238603Sjoerg        DEVMETHOD(device_probe,intsmb_probe),
103238603Sjoerg        DEVMETHOD(device_attach,intsmb_attach),
104238603Sjoerg
105238603Sjoerg        DEVMETHOD(bus_print_child, intsmb_print_child),
106238603Sjoerg
107238603Sjoerg        DEVMETHOD(smbus_callback,intsmb_callback),
108238603Sjoerg        DEVMETHOD(smbus_quick,intsmb_quick),
109238603Sjoerg        DEVMETHOD(smbus_sendb,intsmb_sendb),
110238603Sjoerg        DEVMETHOD(smbus_recvb,intsmb_recvb),
111238603Sjoerg        DEVMETHOD(smbus_writeb,intsmb_writeb),
112238603Sjoerg        DEVMETHOD(smbus_writew,intsmb_writew),
113238603Sjoerg        DEVMETHOD(smbus_readb,intsmb_readb),
114238603Sjoerg        DEVMETHOD(smbus_readw,intsmb_readw),
115238603Sjoerg        DEVMETHOD(smbus_pcall,intsmb_pcall),
116238603Sjoerg        DEVMETHOD(smbus_bwrite,intsmb_bwrite),
117238603Sjoerg        DEVMETHOD(smbus_bread,intsmb_bread),
118238603Sjoerg        {0,0}
119238603Sjoerg};
120238603Sjoerg
121238603Sjoergstatic struct intpm_pci_softc{
122238603Sjoerg        bus_space_tag_t smbst;
123238603Sjoerg        bus_space_handle_t smbsh;
124238603Sjoerg	bus_space_tag_t pmst;
125238603Sjoerg	bus_space_handle_t pmsh;
126238603Sjoerg        pcici_t cfg;
127238603Sjoerg	device_t  smbus;
128238603Sjoerg}intpm_pci[NINTPM];
129238603Sjoerg
130257779Shselasky
131238603Sjoergstruct intsmb_softc{
132238603Sjoerg        struct intpm_pci_softc *pci_sc;
133238603Sjoerg        bus_space_tag_t st;
134238603Sjoerg        bus_space_handle_t sh;
135238603Sjoerg        device_t smbus;
136238603Sjoerg        int isbusy;
137238603Sjoerg};
138238603Sjoergstatic driver_t intpm_driver = {
139238603Sjoerg        "intsmb",
140238603Sjoerg        intpm_methods,
141238603Sjoerg        DRIVER_TYPE_MISC,
142238603Sjoerg        sizeof(struct intsmb_softc),
143238603Sjoerg};
144238603Sjoergstatic u_long intpm_count ;
145238603Sjoerg
146238603Sjoergstatic struct	pci_device intpm_device = {
147238603Sjoerg	"intpm",
148238603Sjoerg 	intpm_probe,
149238603Sjoerg	intpm_attach,
150257779Shselasky	&intpm_count
151238603Sjoerg};
152238603Sjoerg
153238603SjoergDATA_SET (pcidevice_set, intpm_device);
154238603Sjoerg
155238603Sjoergstatic int
156238603Sjoergintsmb_probe(device_t dev)
157238603Sjoerg{
158238603Sjoerg        struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
159257779Shselasky        sc->smbus=smbus_alloc_bus(dev);
160238603Sjoerg        if (!sc->smbus)
161238603Sjoerg                return (EINVAL);    /* XXX don't know what to return else */
162238603Sjoerg        device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
163238603Sjoerg
164238603Sjoerg        return (0);          /* XXX don't know what to return else */
165238603Sjoerg}
166238603Sjoergstatic int
167238603Sjoergintsmb_attach(device_t dev)
168238603Sjoerg{
169257779Shselasky        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
170238603Sjoerg        sc->pci_sc=&intpm_pci[device_get_unit(dev)];
171238603Sjoerg        sc->isbusy=0;
172238603Sjoerg	sc->sh=sc->pci_sc->smbsh;
173238603Sjoerg	sc->st=sc->pci_sc->smbst;
174238603Sjoerg	sc->pci_sc->smbus=dev;
175238603Sjoerg        device_probe_and_attach(sc->smbus);
176238603Sjoerg#ifdef ENABLE_ALART
177238603Sjoerg	/*Enable Arart*/
178238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
179238603Sjoerg			  PIIX4_SMBSLVCNT_ALTEN);
180238603Sjoerg#endif
181238603Sjoerg        return (0);
182238603Sjoerg}
183238603Sjoerg
184238603Sjoergstatic void
185238603Sjoergintsmb_print_child(device_t bus, device_t dev)
186238603Sjoerg{
187238603Sjoerg	printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
188238603Sjoerg	return;
189238603Sjoerg}
190238603Sjoergstatic int
191238603Sjoergintsmb_callback(device_t dev, int index, caddr_t data)
192238603Sjoerg{
193238603Sjoerg	int error = 0;
194238603Sjoerg	intrmask_t s;
195238603Sjoerg	s=splnet();
196238603Sjoerg	switch (index) {
197238603Sjoerg	case SMB_REQUEST_BUS:
198238603Sjoerg		break;
199238603Sjoerg	case SMB_RELEASE_BUS:
200238603Sjoerg		break;
201238603Sjoerg	default:
202238603Sjoerg		error = EINVAL;
203238603Sjoerg	}
204238603Sjoerg	splx(s);
205238603Sjoerg	return (error);
206238603Sjoerg}
207238603Sjoerg/*counterpart of smbtx_smb_free*/
208238603Sjoergstatic        int
209238603Sjoergintsmb_free(device_t dev){
210238603Sjoerg        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
211238603Sjoerg        if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
212238603Sjoerg	    PIIX4_SMBHSTSTAT_BUSY)
213238603Sjoerg#ifdef ENABLE_ALART
214238603Sjoerg	   ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
215238603Sjoerg	      PIIX4_SMBSLVSTS_BUSY)
216238603Sjoerg#endif
217238603Sjoerg	   || sc->isbusy)
218238603Sjoerg                return EBUSY;
219238603Sjoerg        sc->isbusy=1;
220238603Sjoerg	/*Disable Intrrupt in slave part*/
221238603Sjoerg#ifndef ENABLE_ALART
222238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
223238603Sjoerg#endif
224238603Sjoerg        /*Reset INTR Flag to prepare INTR*/
225238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
226238603Sjoerg			  (PIIX4_SMBHSTSTAT_INTR|
227238603Sjoerg			   PIIX4_SMBHSTSTAT_ERR|
228238603Sjoerg			   PIIX4_SMBHSTSTAT_BUSC|
229238603Sjoerg			   PIIX4_SMBHSTSTAT_FAIL)
230238603Sjoerg		);
231238603Sjoerg        return 0;
232238603Sjoerg}
233238603Sjoerg
234238603Sjoergstatic int
235238603Sjoergintsmb_intr(device_t dev)
236238603Sjoerg{
237238603Sjoerg	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
238238603Sjoerg	int status;
239238603Sjoerg	intrmask_t s;
240238603Sjoerg	status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
241238603Sjoerg	if(status&PIIX4_SMBHSTSTAT_BUSY){
242238603Sjoerg		return 1;
243238603Sjoerg
244238603Sjoerg	}
245238603Sjoerg	s=splhigh();
246238603Sjoerg	if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR|
247238603Sjoerg				PIIX4_SMBHSTSTAT_ERR|
248238603Sjoerg				PIIX4_SMBHSTSTAT_BUSC|
249238603Sjoerg				PIIX4_SMBHSTSTAT_FAIL))){
250238603Sjoerg		int tmp;
251238603Sjoerg		sc->isbusy=0;
252238603Sjoerg		tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
253238603Sjoerg		bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
254238603Sjoerg				  tmp&~PIIX4_SMBHSTCNT_INTREN);
255238603Sjoerg		splx(s);
256238603Sjoerg		wakeup(sc);
257238603Sjoerg		return 0;
258238603Sjoerg	}
259238603Sjoerg	splx(s);
260238603Sjoerg	return 1;/* Not Completed*/
261238603Sjoerg}
262238603Sjoergstatic int
263238603Sjoergintsmb_slvintr(device_t dev)
264238603Sjoerg{
265238603Sjoerg	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
266238603Sjoerg        int status,retval;
267238603Sjoerg	retval=1;
268238603Sjoerg        status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
269238603Sjoerg	if(status&PIIX4_SMBSLVSTS_BUSY)
270238603Sjoerg		return retval;
271238603Sjoerg	if(status&PIIX4_SMBSLVSTS_ALART){
272238603Sjoerg		intsmb_alrintr(dev);
273238603Sjoerg		retval=0;
274238603Sjoerg	}else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
275238603Sjoerg			  |PIIX4_SMBSLVSTS_SDW1)){
276238603Sjoerg		retval=0;
277238603Sjoerg	}
278238603Sjoerg	/*Reset Status Register*/
279238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
280238603Sjoerg			  PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
281238603Sjoerg			  PIIX4_SMBSLVSTS_SLV);
282238603Sjoerg	return retval;
283238603Sjoerg}
284238603Sjoerg
285238603Sjoergstatic void intsmb_alrintr(device_t dev)
286238603Sjoerg{
287238603Sjoerg	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
288238603Sjoerg	int slvcnt;
289238603Sjoerg	/*stop generating INTR from ALART*/
290238603Sjoerg	slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
291238603Sjoerg#ifdef ENABLE_ALART
292238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
293238603Sjoerg			  slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
294238603Sjoerg#endif
295238603Sjoerg	DELAY(5);
296238603Sjoerg	/*ask bus who assert it and then ask it what's the matter. */
297238603Sjoerg#ifdef ENABLE_ALART
298238603Sjoerg	error=intsmb_free(dev);
299238603Sjoerg	if(!error){
300238603Sjoerg                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
301238603Sjoerg                                  |LSB);
302238603Sjoerg		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
303238603Sjoerg		if(!(error=intsmb_stop_poll(dev))){
304238603Sjoerg			addr=bus_space_read_1(sc->st,sc->sh,
305238603Sjoerg					      PIIX4_SMBHSTDAT0);
306238603Sjoerg			printf("ALART_RESPONSE: %x\n",(int) addr);
307238603Sjoerg		}
308238603Sjoerg	}else{
309238603Sjoerg	        printf("ERROR\n");
310238603Sjoerg	}
311238603Sjoerg
312238603Sjoerg	/*Re-enable INTR from ALART*/
313238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
314238603Sjoerg			  slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
315238603Sjoerg	DELAY(5);
316238603Sjoerg#endif
317238603Sjoerg
318238603Sjoerg	return;
319238603Sjoerg}
320238603Sjoergstatic void
321238603Sjoergintsmb_start(device_t dev,unsigned char cmd,int nointr)
322238603Sjoerg{
323238603Sjoerg	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
324238603Sjoerg	unsigned char tmp;
325238603Sjoerg	tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
326238603Sjoerg	tmp&= 0xe0;
327238603Sjoerg	tmp |= cmd;
328238603Sjoerg	tmp |=PIIX4_SMBHSTCNT_START;
329238603Sjoerg	/*While not in autoconfiguration Intrrupt Enabled*/
330238603Sjoerg	if(!cold||!nointr)
331238603Sjoerg		tmp |=PIIX4_SMBHSTCNT_INTREN;
332238603Sjoerg	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
333238603Sjoerg}
334238603Sjoerg
335238603Sjoerg/*Polling Code. Polling is not encouraged
336238603Sjoerg * because It is required to wait for the device get busy.
337238603Sjoerg *(29063505.pdf from Intel)
338238603Sjoerg * But during boot,intrrupt cannot be used.
339238603Sjoerg * so use polling code while in autoconfiguration.
340238603Sjoerg */
341238603Sjoerg
342238603Sjoergstatic        int
343238603Sjoergintsmb_stop_poll(device_t dev){
344238603Sjoerg        int error,i;
345238603Sjoerg        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
346238603Sjoerg	/*
347238603Sjoerg	 *  In smbtx driver ,Simply waiting.
348238603Sjoerg	 *  This loops 100-200 times.
349238603Sjoerg	 */
350238603Sjoerg	for(i=0;i<0x7fff;i++){
351238603Sjoerg                if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
352238603Sjoerg		    &PIIX4_SMBHSTSTAT_BUSY)){
353238603Sjoerg                        break;
354238603Sjoerg                }
355238603Sjoerg	}
356238603Sjoerg	for(i=0;i<0x7fff;i++){
357238603Sjoerg		int status;
358238603Sjoerg		status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
359238603Sjoerg		if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
360238603Sjoerg			sc->isbusy=0;
361238603Sjoerg			error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
362238603Sjoerg				(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
363238603Sjoerg				(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
364238603Sjoerg			if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
365238603Sjoerg				printf("unknown cause why?");
366238603Sjoerg			}
367238603Sjoerg			return error;
368238603Sjoerg		}
369238603Sjoerg	}
370238603Sjoerg	sc->isbusy=0;
371238603Sjoerg	return EIO;
372238603Sjoerg}
373238603Sjoerg/*
374238603Sjoerg *wait for completion and return result.
375238603Sjoerg */
376238603Sjoergstatic        int
377238603Sjoergintsmb_stop(device_t dev){
378238603Sjoerg        int error;
379238603Sjoerg        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
380238603Sjoerg	if(cold){
381238603Sjoerg		/*So that it can use device during probing device on SMBus.*/
382238603Sjoerg		error=intsmb_stop_poll(dev);
383238603Sjoerg		return error;
384238603Sjoerg	}else{
385238603Sjoerg		if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
386238603Sjoerg			int status;
387238603Sjoerg			status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
388238603Sjoerg			if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
389238603Sjoerg				error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
390238603Sjoerg					(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
391238603Sjoerg					(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
392238603Sjoerg				if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
393238603Sjoerg					printf("intsmb%d:unknown cause why?\n",
394238603Sjoerg					       device_get_unit(dev));
395238603Sjoerg				}
396238603Sjoerg#ifdef ENABLE_ALART
397238603Sjoerg				bus_space_write_1(sc->st,sc->sh,
398238603Sjoerg						  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
399238603Sjoerg#endif
400238603Sjoerg				return error;
401238603Sjoerg			}
402238603Sjoerg		}
403238603Sjoerg	}
404238603Sjoerg	/*Timeout Procedure*/
405238603Sjoerg	sc->isbusy=0;
406238603Sjoerg	/*Re-enable supressed intrrupt from slave part*/
407238603Sjoerg	bus_space_write_1(sc->st,sc->sh,
408238603Sjoerg			  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
409238603Sjoerg        return EIO;
410238603Sjoerg}
411238603Sjoerg
412238603Sjoergstatic int
413238603Sjoergintsmb_quick(device_t dev, u_char slave, int how)
414238603Sjoerg{
415238603Sjoerg        int error=0;
416        u_char data;
417        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
418        data=slave;
419	/*Quick command is part of Address, I think*/
420        switch(how){
421        case SMB_QWRITE:
422                data&=~LSB;
423		break;
424        case SMB_QREAD:
425                data|=LSB;
426                break;
427        default:
428                error=EINVAL;
429        }
430        if(!error){
431	        error=intsmb_free(dev);
432                if(!error){
433                        bus_space_write_1(sc->st,sc->sh,
434					  PIIX4_SMBHSTADD,data);
435			intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
436                        error=intsmb_stop(dev);
437                }
438        }
439
440        return (error);
441}
442
443static int
444intsmb_sendb(device_t dev, u_char slave, char byte)
445{
446        int error;
447        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
448        error=intsmb_free(dev);
449        if(!error){
450                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
451                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
452		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
453                error=intsmb_stop(dev);
454        }
455        return (error);
456}
457static int
458intsmb_recvb(device_t dev, u_char slave, char *byte)
459{
460        int error;
461        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
462        error=intsmb_free(dev);
463        if(!error){
464                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
465				  |LSB);
466                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
467                if(!(error=intsmb_stop(dev))){
468#ifdef RECV_IS_IN_CMD
469		        /*Linux SMBus stuff also troubles
470			  Because Intel's datasheet will not make clear.
471			 */
472                        *byte=bus_space_read_1(sc->st,sc->sh,
473					       PIIX4_SMBHSTCMD);
474#else
475                        *byte=bus_space_read_1(sc->st,sc->sh,
476					       PIIX4_SMBHSTDAT0);
477#endif
478                }
479        }
480        return (error);
481}
482static int
483intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
484{
485        int error;
486        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
487        error=intsmb_free(dev);
488        if(!error){
489                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
490                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
491                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
492		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
493                error=intsmb_stop(dev);
494        }
495        return (error);
496}
497static int
498intsmb_writew(device_t dev, u_char slave, char cmd, short word)
499{
500        int error;
501        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
502        error=intsmb_free(dev);
503        if(!error){
504                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
505                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
506                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
507				  word&0xff);
508                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
509				  (word>>8)&0xff);
510		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
511                error=intsmb_stop(dev);
512        }
513        return (error);
514}
515
516static int
517intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
518{
519        int error;
520        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
521        error=intsmb_free(dev);
522        if(!error){
523                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
524                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
525		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
526                if(!(error=intsmb_stop(dev))){
527		        *byte=bus_space_read_1(sc->st,sc->sh,
528					       PIIX4_SMBHSTDAT0);
529                }
530        }
531        return (error);
532}
533static int
534intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
535{
536        int error;
537        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
538        error=intsmb_free(dev);
539        if(!error){
540                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
541                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
542		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
543                if(!(error=intsmb_stop(dev))){
544                        *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
545                        *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
546                }
547        }
548        return (error);
549}
550/*
551 * Data sheet claims that it implements all function, but also claims
552 * that it implements 7 function and not mention PCALL. So I don't know
553 * whether it will work.
554 */
555static int
556intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
557{
558#ifdef PROCCALL_TEST
559        int error;
560        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
561        error=intsmb_free(dev);
562        if(!error){
563                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
564                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
565                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
566                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
567                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
568        }
569        if(!(error=intsmb_stop(dev))){
570                *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
571                *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
572        }
573        return error;
574#else
575	return 0;
576#endif
577}
578static int
579intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
580{
581        int error,i;
582        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
583        error=intsmb_free(dev);
584        if(count>SMBBLOCKTRANS_MAX||count==0)
585                error=EINVAL;
586        if(!error){
587                /*Reset internal array index*/
588                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
589
590                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
591                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
592                for(i=0;i<count;i++){
593                        bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
594                }
595                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
596                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
597                error=intsmb_stop(dev);
598        }
599        return (error);
600}
601
602static int
603intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
604{
605        int error,i;
606        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
607        error=intsmb_free(dev);
608        if(count>SMBBLOCKTRANS_MAX||count==0)
609                error=EINVAL;
610        if(!error){
611                /*Reset internal array index*/
612                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
613
614                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
615                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
616                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
617                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
618                error=intsmb_stop(dev);
619                if(!error){
620                        bzero(buf,count);/*Is it needed?*/
621                        count= bus_space_read_1(sc->st,sc->sh,
622						PIIX4_SMBHSTDAT0);
623                        if(count!=0&&count<=SMBBLOCKTRANS_MAX){
624			        for(i=0;i<count;i++){
625				        buf[i]=bus_space_read_1(sc->st,
626								sc->sh,
627								PIIX4_SMBBLKDAT);
628				}
629			}
630                        else{
631				error=EIO;
632                        }
633		}
634	}
635        return (error);
636}
637
638DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0);
639
640
641static void intpm_intr __P((void *arg));
642
643static const char*
644intpm_probe (pcici_t tag, pcidi_t type)
645{
646        struct _pcsid	*ep =pci_ids;
647        while (ep->type && ep->type != type)
648                ++ep;
649        return (ep->desc);
650}
651
652static struct intpm_pci_softc *intpm_alloc(int unit){
653        if(unit<NINTPM)
654                return &intpm_pci[unit];
655        else
656                return NULL;
657}
658
659/*Same as pci_map_int but this ignores INTPIN*/
660static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr)
661{
662        int error;
663#ifdef APIC_IO
664        int nextpin, muxcnt;
665#endif
666	/* Spec sheet claims that it use IRQ 9*/
667        int irq = 9;
668        void *dev_instance = (void *)-1; /* XXX use cfg->devdata        */
669        void *idesc;
670
671        idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0);
672        error = intr_connect(idesc);
673        if (error != 0)
674                return 0;
675#ifdef APIC_IO
676        nextpin = next_apic_irq(irq);
677
678        if (nextpin < 0)
679                return 1;
680
681        /*
682         * Attempt handling of some broken mp tables.
683         *
684         * It's OK to yell (since the mp tables are broken).
685         *
686         * Hanging in the boot is not OK
687         */
688
689        muxcnt = 2;
690        nextpin = next_apic_irq(nextpin);
691        while (muxcnt < 5 && nextpin >= 0) {
692                muxcnt++;
693                nextpin = next_apic_irq(nextpin);
694        }
695        if (muxcnt >= 5) {
696                printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
697                return 0;
698        }
699
700        printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt);
701
702        nextpin = next_apic_irq(irq);
703        while (nextpin >= 0) {
704                idesc = intr_create(dev_instance, nextpin, func, arg,
705				    maskptr, 0);
706                error = intr_connect(idesc);
707                if (error != 0)
708                        return 0;
709                printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq);
710                nextpin = next_apic_irq(nextpin);
711        }
712#endif
713        return 1;
714}
715static void
716intpm_attach(config_id, unit)
717     pcici_t config_id;
718     int	unit;
719{
720        int value;
721
722        char * str;
723        {
724                struct intpm_pci_softc *sciic;
725                device_t smbinterface;
726                value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4);
727                sciic=intpm_alloc(unit);
728                if(sciic==NULL){
729                        return;
730                }
731
732		sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM;
733
734		/*Calling pci_map_port is better.But bus_space_handle_t !=
735		 * pci_port_t, so I don't call support routine while
736		 * bus_space_??? support routine will be appear.
737		 */
738                sciic->smbsh=value&(~1);
739		if(sciic->smbsh==I386_BUS_SPACE_MEM){
740		       /*According to the spec, this will not occur*/
741                       int dummy;
742		       pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy);
743		}
744                printf("intpm%d: %s %x ",unit,
745		       (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory",
746		       sciic->smbsh);
747#ifndef NO_CHANGE_PCICONF
748		pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1);
749                pci_cfgwrite(config_id,PCI_HST_CFG_SMB,
750			     PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
751#endif
752		config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1);
753		printf("ALLOCED IRQ %d ",config_id->intline);
754                value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1);
755                switch(value&0xe){
756                case PCI_INTR_SMB_SMI:
757                        str="SMI";
758                        break;
759                case PCI_INTR_SMB_IRQ9:
760                        str="IRQ 9";
761                        break;
762                default:
763                        str="BOGUS";
764                }
765                printf("intr %s %s ",str,((value&1)? "enabled":"disabled"));
766                value=pci_cfgread(config_id,PCI_REVID_SMB,1);
767                printf("revision %d\n",value);
768                /*
769                 * Install intr HANDLER here
770                 */
771                if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){
772                        printf("intpm%d: Failed to map intr\n",unit);
773                }
774                smbinterface=device_add_child(root_bus,"intsmb",unit,NULL);
775                device_probe_and_attach(smbinterface);
776        }
777        value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4);
778        printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
779        return;
780}
781static void intpm_intr(void *arg)
782{
783        struct intpm_pci_softc *sc;
784        sc=(struct intpm_pci_softc *)arg;
785	intsmb_intr(sc->smbus);
786	intsmb_slvintr(sc->smbus);
787}
788#endif /* NPCI > 0 */
789#endif
790