xref: /freebsd/sys/dev/pci/isa_pci.c (revision 41ee9f1c6918a36d2feca1640bde21b420618948)
1bb0d0a8eSMike Smith /*-
2bb0d0a8eSMike Smith  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
3bb0d0a8eSMike Smith  * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
4bb0d0a8eSMike Smith  * Copyright (c) 2000 BSDi
5bb0d0a8eSMike Smith  * All rights reserved.
6bb0d0a8eSMike Smith  *
7bb0d0a8eSMike Smith  * Redistribution and use in source and binary forms, with or without
8bb0d0a8eSMike Smith  * modification, are permitted provided that the following conditions
9bb0d0a8eSMike Smith  * are met:
10bb0d0a8eSMike Smith  * 1. Redistributions of source code must retain the above copyright
11bb0d0a8eSMike Smith  *    notice, this list of conditions and the following disclaimer.
12bb0d0a8eSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
13bb0d0a8eSMike Smith  *    notice, this list of conditions and the following disclaimer in the
14bb0d0a8eSMike Smith  *    documentation and/or other materials provided with the distribution.
15bb0d0a8eSMike Smith  * 3. The name of the author may not be used to endorse or promote products
16bb0d0a8eSMike Smith  *    derived from this software without specific prior written permission.
17bb0d0a8eSMike Smith  *
18bb0d0a8eSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19bb0d0a8eSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20bb0d0a8eSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21bb0d0a8eSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22bb0d0a8eSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23bb0d0a8eSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24bb0d0a8eSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25bb0d0a8eSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26bb0d0a8eSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27bb0d0a8eSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28bb0d0a8eSMike Smith  * SUCH DAMAGE.
29bb0d0a8eSMike Smith  */
30bb0d0a8eSMike Smith 
31aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
33aad970f1SDavid E. O'Brien 
34bb0d0a8eSMike Smith /*
35bb0d0a8eSMike Smith  * PCI:ISA bridge support
36bb0d0a8eSMike Smith  */
37bb0d0a8eSMike Smith 
38bb0d0a8eSMike Smith #include <sys/param.h>
39bb0d0a8eSMike Smith #include <sys/systm.h>
40bb0d0a8eSMike Smith #include <sys/kernel.h>
4141ee9f1cSPoul-Henning Kamp #include <sys/module.h>
4258164331SIan Dowse #include <machine/bus.h>
4358164331SIan Dowse #include <machine/resource.h>
44bb0d0a8eSMike Smith #include <sys/bus.h>
4558164331SIan Dowse #include <sys/rman.h>
46bb0d0a8eSMike Smith 
47c37faf26SJohn Baldwin #include <isa/isavar.h>
4838d8c994SWarner Losh #include <dev/pci/pcivar.h>
4938d8c994SWarner Losh #include <dev/pci/pcireg.h>
50bb0d0a8eSMike Smith 
5158164331SIan Dowse #define	ELCR_IOADDR	0x4d0	/* Interrupt Edge/Level Control Registers */
5258164331SIan Dowse #define	ELCR_IOLEN	2
5358164331SIan Dowse 
5458164331SIan Dowse struct isab_softc {
5558164331SIan Dowse     struct resource *elcr_res;
5658164331SIan Dowse     u_char saved_elcr[ELCR_IOLEN];
5758164331SIan Dowse };
5858164331SIan Dowse 
59bb0d0a8eSMike Smith static int	isab_probe(device_t dev);
60c37faf26SJohn Baldwin static int	pci_isab_attach(device_t dev);
6158164331SIan Dowse static int	isab_detach(device_t dev);
6258164331SIan Dowse static int	isab_resume(device_t dev);
6358164331SIan Dowse static int	isab_suspend(device_t dev);
64bb0d0a8eSMike Smith 
65bb0d0a8eSMike Smith static device_method_t isab_methods[] = {
66bb0d0a8eSMike Smith     /* Device interface */
67bb0d0a8eSMike Smith     DEVMETHOD(device_probe,		isab_probe),
68c37faf26SJohn Baldwin     DEVMETHOD(device_attach,		pci_isab_attach),
6958164331SIan Dowse     DEVMETHOD(device_detach,		isab_detach),
70bb0d0a8eSMike Smith     DEVMETHOD(device_shutdown,		bus_generic_shutdown),
7158164331SIan Dowse     DEVMETHOD(device_suspend,		isab_suspend),
7258164331SIan Dowse     DEVMETHOD(device_resume,		isab_resume),
73bb0d0a8eSMike Smith 
74bb0d0a8eSMike Smith     /* Bus interface */
75bb0d0a8eSMike Smith     DEVMETHOD(bus_print_child,		bus_generic_print_child),
76bb0d0a8eSMike Smith     DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
77bb0d0a8eSMike Smith     DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
78bb0d0a8eSMike Smith     DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
79bb0d0a8eSMike Smith     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
80bb0d0a8eSMike Smith     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
81bb0d0a8eSMike Smith     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
82bb0d0a8eSMike Smith 
83bb0d0a8eSMike Smith     { 0, 0 }
84bb0d0a8eSMike Smith };
85bb0d0a8eSMike Smith 
86bb0d0a8eSMike Smith static driver_t isab_driver = {
87bb0d0a8eSMike Smith     "isab",
88bb0d0a8eSMike Smith     isab_methods,
8958164331SIan Dowse     sizeof(struct isab_softc),
90bb0d0a8eSMike Smith };
91bb0d0a8eSMike Smith 
92bb0d0a8eSMike Smith DRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0);
93bb0d0a8eSMike Smith 
94bb0d0a8eSMike Smith /*
95bb0d0a8eSMike Smith  * XXX we need to add a quirk list here for bridges that don't correctly
96bb0d0a8eSMike Smith  *     report themselves.
97bb0d0a8eSMike Smith  */
98bb0d0a8eSMike Smith static int
99bb0d0a8eSMike Smith isab_probe(device_t dev)
100bb0d0a8eSMike Smith {
101bb0d0a8eSMike Smith     int		matched = 0;
102bb0d0a8eSMike Smith 
103bb0d0a8eSMike Smith     /*
104bb0d0a8eSMike Smith      * Try for a generic match based on class/subclass.
105bb0d0a8eSMike Smith      */
106fed8edf5SMike Smith     if ((pci_get_class(dev) == PCIC_BRIDGE) &&
107fed8edf5SMike Smith 	(pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) {
108bb0d0a8eSMike Smith 	matched = 1;
109e620c314SMike Smith     } else {
110bb0d0a8eSMike Smith 	/*
111e620c314SMike Smith 	 * These are devices that we *know* are PCI:ISA bridges.
112e620c314SMike Smith 	 * Sometimes, however, they don't report themselves as
113e620c314SMike Smith 	 * such.  Check in case one of them is pretending to be
114e620c314SMike Smith 	 * something else.
115bb0d0a8eSMike Smith 	 */
116bb0d0a8eSMike Smith 	switch (pci_get_devid(dev)) {
117bb0d0a8eSMike Smith 	case 0x04848086:	/* Intel 82378ZB/82378IB */
118bb0d0a8eSMike Smith 	case 0x122e8086:	/* Intel 82371FB */
119bb0d0a8eSMike Smith 	case 0x70008086:	/* Intel 82371SB */
120e620c314SMike Smith 	case 0x71108086:	/* Intel 82371AB */
121417c87d1SJim Pirzyk 	case 0x71988086:	/* Intel 82443MX */
122bb0d0a8eSMike Smith 	case 0x24108086:	/* Intel 82801AA (ICH) */
123bb0d0a8eSMike Smith 	case 0x24208086:	/* Intel 82801AB (ICH0) */
124e620c314SMike Smith 	case 0x24408086:	/* Intel 82801AB (ICH2) */
125bb0d0a8eSMike Smith 	case 0x00061004:	/* VLSI 82C593 */
126bb0d0a8eSMike Smith 	case 0x05861106:	/* VIA 82C586 */
127e620c314SMike Smith 	case 0x05961106:	/* VIA 82C596 */
128e620c314SMike Smith 	case 0x06861106:	/* VIA 82C686 */
129bb0d0a8eSMike Smith 	case 0x153310b9:	/* AcerLabs M1533 */
130bb0d0a8eSMike Smith 	case 0x154310b9:	/* AcerLabs M1543 */
131bb0d0a8eSMike Smith 	case 0x00081039:	/* SiS 85c503 */
132bb0d0a8eSMike Smith 	case 0x00001078:	/* Cyrix Cx5510 */
133bb0d0a8eSMike Smith 	case 0x01001078:	/* Cyrix Cx5530 */
134bb0d0a8eSMike Smith 	case 0xc7001045:	/* OPTi 82C700 (FireStar) */
135bb0d0a8eSMike Smith 	case 0x00011033:	/* NEC 0001 (C-bus) */
136bb0d0a8eSMike Smith 	case 0x002c1033:	/* NEC 002C (C-bus) */
137bb0d0a8eSMike Smith 	case 0x003b1033:	/* NEC 003B (C-bus) */
138bb0d0a8eSMike Smith 	case 0x886a1060:	/* UMC UM8886 ISA */
139bb0d0a8eSMike Smith 	case 0x02001166:	/* ServerWorks IB6566 PCI */
140e620c314SMike Smith 	    if (bootverbose)
141e620c314SMike Smith 		printf("PCI-ISA bridge with incorrect subclass 0x%x\n",
142e620c314SMike Smith 		       pci_get_subclass(dev));
143bb0d0a8eSMike Smith 	    matched = 1;
144bb0d0a8eSMike Smith 	    break;
145bb0d0a8eSMike Smith 
146bb0d0a8eSMike Smith 	default:
147bb0d0a8eSMike Smith 	    break;
148bb0d0a8eSMike Smith 	}
149e620c314SMike Smith     }
150bb0d0a8eSMike Smith 
151bb0d0a8eSMike Smith     if (matched) {
152bb0d0a8eSMike Smith 	device_set_desc(dev, "PCI-ISA bridge");
153bb0d0a8eSMike Smith 	return(-10000);
154bb0d0a8eSMike Smith     }
155bb0d0a8eSMike Smith     return(ENXIO);
156bb0d0a8eSMike Smith }
157bb0d0a8eSMike Smith 
158bb0d0a8eSMike Smith static int
159c37faf26SJohn Baldwin pci_isab_attach(device_t dev)
160bb0d0a8eSMike Smith {
16158164331SIan Dowse     struct isab_softc *sc = device_get_softc(dev);
16258164331SIan Dowse     int error, rid;
163bb0d0a8eSMike Smith 
164bb0d0a8eSMike Smith     /*
165bb0d0a8eSMike Smith      * Attach an ISA bus.  Note that we can only have one ISA bus.
166bb0d0a8eSMike Smith      */
167c37faf26SJohn Baldwin     error = isab_attach(dev);
16858164331SIan Dowse     if (error)
16958164331SIan Dowse 	    return (error);
17058164331SIan Dowse 
17158164331SIan Dowse     switch (pci_get_devid(dev)) {
17258164331SIan Dowse     case 0x71108086: /* Intel 82371AB */
17358164331SIan Dowse 	/*
17458164331SIan Dowse 	 * Sometimes the ELCR (Edge/Level Control Register) is not restored
17558164331SIan Dowse 	 * correctly on resume by the BIOS, so we handle it ourselves.
17658164331SIan Dowse 	 */
17758164331SIan Dowse 	rid = 0;
17858164331SIan Dowse 	bus_set_resource(dev, SYS_RES_IOPORT, rid, ELCR_IOADDR, ELCR_IOLEN);
1795f96beb9SNate Lawson 	sc->elcr_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
18058164331SIan Dowse 	    RF_ACTIVE);
18158164331SIan Dowse 	if (sc->elcr_res == NULL)
18258164331SIan Dowse 	    device_printf(dev, "failed to allocate ELCR resource\n");
18358164331SIan Dowse         break;
18458164331SIan Dowse     }
185bb0d0a8eSMike Smith 
186bb0d0a8eSMike Smith     return(0);
187bb0d0a8eSMike Smith }
188bb0d0a8eSMike Smith 
18958164331SIan Dowse static int
19058164331SIan Dowse isab_detach(device_t dev)
19158164331SIan Dowse {
19258164331SIan Dowse     struct isab_softc *sc = device_get_softc(dev);
19358164331SIan Dowse 
19458164331SIan Dowse     if (sc->elcr_res != NULL)
19558164331SIan Dowse 	bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->elcr_res);
19658164331SIan Dowse 
19758164331SIan Dowse     return (bus_generic_detach(dev));
19858164331SIan Dowse }
19958164331SIan Dowse 
20058164331SIan Dowse static int
20158164331SIan Dowse isab_suspend(device_t dev)
20258164331SIan Dowse {
20358164331SIan Dowse     struct isab_softc *sc = device_get_softc(dev);
20458164331SIan Dowse     bus_space_tag_t bst;
20558164331SIan Dowse     bus_space_handle_t bsh;
20658164331SIan Dowse     int i;
20758164331SIan Dowse 
20858164331SIan Dowse     /* Save the ELCR if required. */
20958164331SIan Dowse     if (sc->elcr_res != NULL) {
21058164331SIan Dowse 	bst = rman_get_bustag(sc->elcr_res);
21158164331SIan Dowse 	bsh = rman_get_bushandle(sc->elcr_res);
21258164331SIan Dowse 	for (i = 0; i < ELCR_IOLEN; i++)
21358164331SIan Dowse 	    sc->saved_elcr[i] = bus_space_read_1(bst, bsh, i);
21458164331SIan Dowse     }
21558164331SIan Dowse 
21658164331SIan Dowse     return (bus_generic_suspend(dev));
21758164331SIan Dowse }
21858164331SIan Dowse 
21958164331SIan Dowse static int
22058164331SIan Dowse isab_resume(device_t dev)
22158164331SIan Dowse {
22258164331SIan Dowse     struct isab_softc *sc = device_get_softc(dev);
22358164331SIan Dowse     bus_space_tag_t bst;
22458164331SIan Dowse     bus_space_handle_t bsh;
22558164331SIan Dowse     int i;
22658164331SIan Dowse 
22758164331SIan Dowse     /* Restore the ELCR if required. */
22858164331SIan Dowse     if (sc->elcr_res != NULL) {
22958164331SIan Dowse 	bst = rman_get_bustag(sc->elcr_res);
23058164331SIan Dowse 	bsh = rman_get_bushandle(sc->elcr_res);
23158164331SIan Dowse 	for (i = 0; i < ELCR_IOLEN; i++)
23258164331SIan Dowse 	    bus_space_write_1(bst, bsh, i, sc->saved_elcr[i]);
23358164331SIan Dowse     }
23458164331SIan Dowse 
23558164331SIan Dowse     return (bus_generic_resume(dev));
23658164331SIan Dowse }
237