xref: /dflybsd-src/sys/bus/pci/vga_pci.c (revision 9a4126c771f815b44016361958c8fb6490712157)
14d28e78fSSepherosa Ziehau /*-
24d28e78fSSepherosa Ziehau  * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
34d28e78fSSepherosa Ziehau  * All rights reserved.
44d28e78fSSepherosa Ziehau  *
54d28e78fSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
64d28e78fSSepherosa Ziehau  * modification, are permitted provided that the following conditions
74d28e78fSSepherosa Ziehau  * are met:
84d28e78fSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
94d28e78fSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
104d28e78fSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
114d28e78fSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
124d28e78fSSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
134d28e78fSSepherosa Ziehau  * 3. Neither the name of the author nor the names of any co-contributors
144d28e78fSSepherosa Ziehau  *    may be used to endorse or promote products derived from this software
154d28e78fSSepherosa Ziehau  *    without specific prior written permission.
164d28e78fSSepherosa Ziehau  *
174d28e78fSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
184d28e78fSSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194d28e78fSSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204d28e78fSSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
214d28e78fSSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224d28e78fSSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234d28e78fSSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244d28e78fSSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254d28e78fSSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264d28e78fSSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274d28e78fSSepherosa Ziehau  * SUCH DAMAGE.
2883c1faaaSSascha Wildner  *
2983c1faaaSSascha Wildner  * $FreeBSD: src/sys/dev/pci/vga_pci.c,v 1.5.8.1 2009/04/15 03:14:26 kensmith Exp $
304d28e78fSSepherosa Ziehau  */
314d28e78fSSepherosa Ziehau 
324d28e78fSSepherosa Ziehau /*
334d28e78fSSepherosa Ziehau  * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
344d28e78fSSepherosa Ziehau  * drm(4) should attach as children of this device.
354d28e78fSSepherosa Ziehau  *
364d28e78fSSepherosa Ziehau  * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
374d28e78fSSepherosa Ziehau  * in or rename it.
384d28e78fSSepherosa Ziehau  */
394d28e78fSSepherosa Ziehau 
404d28e78fSSepherosa Ziehau #include <sys/param.h>
414d28e78fSSepherosa Ziehau #include <sys/bus.h>
424d28e78fSSepherosa Ziehau #include <sys/kernel.h>
434d28e78fSSepherosa Ziehau #include <sys/module.h>
44a02ece1fSFrançois Tigeot #include <sys/rman.h>
45a02ece1fSFrançois Tigeot #include <sys/sysctl.h>
46a02ece1fSFrançois Tigeot #include <sys/systm.h>
47a02ece1fSFrançois Tigeot 
48a02ece1fSFrançois Tigeot #include <machine/pmap.h>
494d28e78fSSepherosa Ziehau 
504d28e78fSSepherosa Ziehau #include <bus/pci/pcireg.h>
514d28e78fSSepherosa Ziehau #include <bus/pci/pcivar.h>
524d28e78fSSepherosa Ziehau 
53072d6095SFrançois Tigeot struct vga_resource {
54072d6095SFrançois Tigeot 	struct resource	*vr_res;
55072d6095SFrançois Tigeot 	int	vr_refs;
56072d6095SFrançois Tigeot };
57072d6095SFrançois Tigeot 
58072d6095SFrançois Tigeot struct vga_pci_softc {
59072d6095SFrançois Tigeot 	device_t	vga_msi_child;	/* Child driver using MSI. */
60072d6095SFrançois Tigeot 	struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1];
61072d6095SFrançois Tigeot 	struct vga_resource vga_bios;
62072d6095SFrançois Tigeot };
63072d6095SFrançois Tigeot 
64a02ece1fSFrançois Tigeot SYSCTL_DECL(_hw_pci);
65a02ece1fSFrançois Tigeot 
66072d6095SFrançois Tigeot static struct vga_resource *lookup_res(struct vga_pci_softc *sc, int rid);
67072d6095SFrançois Tigeot static struct resource *vga_pci_alloc_resource(device_t dev, device_t child,
68384438e3SSepherosa Ziehau     int type, int *rid, u_long start, u_long end, u_long count, u_int flags,
69384438e3SSepherosa Ziehau     int cpuid);
70072d6095SFrançois Tigeot static int	vga_pci_release_resource(device_t dev, device_t child, int type,
71072d6095SFrançois Tigeot     int rid, struct resource *r);
72072d6095SFrançois Tigeot 
73a02ece1fSFrançois Tigeot int vga_pci_default_unit = -1;
74a02ece1fSFrançois Tigeot TUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit);
75a02ece1fSFrançois Tigeot SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RD,
76a02ece1fSFrançois Tigeot     &vga_pci_default_unit, -1, "Default VGA-compatible display");
77a02ece1fSFrançois Tigeot 
78a02ece1fSFrançois Tigeot int
vga_pci_is_boot_display(device_t dev)79a02ece1fSFrançois Tigeot vga_pci_is_boot_display(device_t dev)
80a02ece1fSFrançois Tigeot {
812a979d81SImre Vadasz 	int unit;
822a979d81SImre Vadasz 	device_t pcib;
832a979d81SImre Vadasz 	uint16_t config;
842a979d81SImre Vadasz 
852a979d81SImre Vadasz 	/* Check that the given device is a video card */
862a979d81SImre Vadasz 	if ((pci_get_class(dev) != PCIC_DISPLAY &&
872a979d81SImre Vadasz 	    (pci_get_class(dev) != PCIC_OLD ||
882a979d81SImre Vadasz 	     pci_get_subclass(dev) != PCIS_OLD_VGA)))
892a979d81SImre Vadasz 		return (0);
902a979d81SImre Vadasz 
912a979d81SImre Vadasz 	unit = device_get_unit(dev);
922a979d81SImre Vadasz 
932a979d81SImre Vadasz 	if (vga_pci_default_unit >= 0) {
942a979d81SImre Vadasz 		/*
952a979d81SImre Vadasz 		 * The boot display device was determined by a previous
962a979d81SImre Vadasz 		 * call to this function, or the user forced it using
972a979d81SImre Vadasz 		 * the hw.pci.default_vgapci_unit tunable.
982a979d81SImre Vadasz 		 */
992a979d81SImre Vadasz 		return (vga_pci_default_unit == unit);
1002a979d81SImre Vadasz 	}
101a02ece1fSFrançois Tigeot 
102a02ece1fSFrançois Tigeot 	/*
1032a979d81SImre Vadasz 	 * The primary video card used as a boot display must have the
1042a979d81SImre Vadasz 	 * "I/O" and "Memory Address Space Decoding" bits set in its
1052a979d81SImre Vadasz 	 * Command register.
1062a979d81SImre Vadasz 	 *
1072a979d81SImre Vadasz 	 * Furthermore, if the card is attached to a bridge, instead of
1082a979d81SImre Vadasz 	 * the root PCI bus, the bridge must have the "VGA Enable" bit
1092a979d81SImre Vadasz 	 * set in its Control register.
110a02ece1fSFrançois Tigeot 	 */
1112a979d81SImre Vadasz 
1122a979d81SImre Vadasz 	pcib = device_get_parent(device_get_parent(dev));
1132a979d81SImre Vadasz 	if (device_get_devclass(device_get_parent(pcib)) ==
1142a979d81SImre Vadasz 	    devclass_find("pci")) {
1152a979d81SImre Vadasz 		/*
1162a979d81SImre Vadasz 		 * The parent bridge is a PCI-to-PCI bridge: check the
1172a979d81SImre Vadasz 		 * value of the "VGA Enable" bit.
1182a979d81SImre Vadasz 		 */
1192a979d81SImre Vadasz 		config = pci_read_config(pcib, PCIR_BRIDGECTL_1, 2);
1202a979d81SImre Vadasz 		if ((config & PCIB_BCR_VGA_ENABLE) == 0)
1212a979d81SImre Vadasz 			return (0);
1222a979d81SImre Vadasz 	}
1232a979d81SImre Vadasz 
1242a979d81SImre Vadasz 	config = pci_read_config(dev, PCIR_COMMAND, 2);
1252a979d81SImre Vadasz 	if ((config & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) == 0)
1262a979d81SImre Vadasz 		return (0);
1272a979d81SImre Vadasz 
1282a979d81SImre Vadasz 	/* This video card is the boot display: record its unit number. */
1292a979d81SImre Vadasz 	vga_pci_default_unit = unit;
1302a979d81SImre Vadasz 	device_set_flags(dev, 1);
1312a979d81SImre Vadasz 
1322a979d81SImre Vadasz 	return (1);
133a02ece1fSFrançois Tigeot }
134a02ece1fSFrançois Tigeot 
135a02ece1fSFrançois Tigeot void *
vga_pci_map_bios(device_t dev,size_t * size)136a02ece1fSFrançois Tigeot vga_pci_map_bios(device_t dev, size_t *size)
137a02ece1fSFrançois Tigeot {
138a02ece1fSFrançois Tigeot 	int rid;
139a02ece1fSFrançois Tigeot 	struct resource *res;
140a02ece1fSFrançois Tigeot 
141a02ece1fSFrançois Tigeot 	if (vga_pci_is_boot_display(dev)) {
142a02ece1fSFrançois Tigeot 		/*
143a02ece1fSFrançois Tigeot 		 * On x86, the System BIOS copy the default display
144a02ece1fSFrançois Tigeot 		 * device's Video BIOS at a fixed location in system
145a02ece1fSFrançois Tigeot 		 * memory (0xC0000, 128 kBytes long) at boot time.
146a02ece1fSFrançois Tigeot 		 *
147a02ece1fSFrançois Tigeot 		 * We use this copy for the default boot device, because
148a02ece1fSFrançois Tigeot 		 * the original ROM may not be valid after boot.
149a02ece1fSFrançois Tigeot 		 */
150a02ece1fSFrançois Tigeot 
151a02ece1fSFrançois Tigeot 		*size = VGA_PCI_BIOS_SHADOW_SIZE;
152a02ece1fSFrançois Tigeot 		return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size));
153a02ece1fSFrançois Tigeot 	}
154a02ece1fSFrançois Tigeot 
155a02ece1fSFrançois Tigeot 	rid = PCIR_BIOS;
156072d6095SFrançois Tigeot 	res = vga_pci_alloc_resource(dev, NULL, SYS_RES_MEMORY, &rid, 0ul,
157384438e3SSepherosa Ziehau 	    ~0ul, 1, RF_ACTIVE, -1);
158a02ece1fSFrançois Tigeot 	if (res == NULL) {
159a02ece1fSFrançois Tigeot 		return (NULL);
160a02ece1fSFrançois Tigeot 	}
161a02ece1fSFrançois Tigeot 
162a02ece1fSFrançois Tigeot 	*size = rman_get_size(res);
163a02ece1fSFrançois Tigeot 	return (rman_get_virtual(res));
164a02ece1fSFrançois Tigeot }
165a02ece1fSFrançois Tigeot 
166a02ece1fSFrançois Tigeot void
vga_pci_unmap_bios(device_t dev,void * bios)167a02ece1fSFrançois Tigeot vga_pci_unmap_bios(device_t dev, void *bios)
168a02ece1fSFrançois Tigeot {
169072d6095SFrançois Tigeot 	struct vga_resource *vr;
170a02ece1fSFrançois Tigeot 
171a02ece1fSFrançois Tigeot 	if (bios == NULL) {
172a02ece1fSFrançois Tigeot 		return;
173a02ece1fSFrançois Tigeot 	}
174a02ece1fSFrançois Tigeot 
175a02ece1fSFrançois Tigeot 	if (vga_pci_is_boot_display(dev)) {
176a02ece1fSFrançois Tigeot 		/* We mapped the BIOS shadow copy located at 0xC0000. */
177a02ece1fSFrançois Tigeot 		pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE);
178a02ece1fSFrançois Tigeot 
179a02ece1fSFrançois Tigeot 		return;
180a02ece1fSFrançois Tigeot 	}
181a02ece1fSFrançois Tigeot 
182a02ece1fSFrançois Tigeot 	/*
183072d6095SFrançois Tigeot 	 * Look up the PCIR_BIOS resource in our softc.  It should match
184072d6095SFrançois Tigeot 	 * the address we returned previously.
185a02ece1fSFrançois Tigeot 	 */
186072d6095SFrançois Tigeot 	vr = lookup_res(device_get_softc(dev), PCIR_BIOS);
187072d6095SFrançois Tigeot 	KASSERT(vr->vr_res != NULL, ("vga_pci_unmap_bios: bios not mapped"));
188072d6095SFrançois Tigeot 	KASSERT(rman_get_virtual(vr->vr_res) == bios,
189072d6095SFrançois Tigeot 	    ("vga_pci_unmap_bios: mismatch"));
190072d6095SFrançois Tigeot 	vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, PCIR_BIOS,
191072d6095SFrançois Tigeot 	    vr->vr_res);
192a02ece1fSFrançois Tigeot }
193a02ece1fSFrançois Tigeot 
1944d28e78fSSepherosa Ziehau static int
vga_pci_probe(device_t dev)1954d28e78fSSepherosa Ziehau vga_pci_probe(device_t dev)
1964d28e78fSSepherosa Ziehau {
1974d28e78fSSepherosa Ziehau 
1984d28e78fSSepherosa Ziehau 	switch (pci_get_class(dev)) {
1994d28e78fSSepherosa Ziehau 	case PCIC_DISPLAY:
2004d28e78fSSepherosa Ziehau 		break;
2014d28e78fSSepherosa Ziehau 	case PCIC_OLD:
2024d28e78fSSepherosa Ziehau 		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
2034d28e78fSSepherosa Ziehau 			return (ENXIO);
2044d28e78fSSepherosa Ziehau 		break;
2054d28e78fSSepherosa Ziehau 	default:
2064d28e78fSSepherosa Ziehau 		return (ENXIO);
2074d28e78fSSepherosa Ziehau 	}
208a02ece1fSFrançois Tigeot 
209a02ece1fSFrançois Tigeot 	/* Probe default display. */
2102a979d81SImre Vadasz 	vga_pci_is_boot_display(dev);
211a02ece1fSFrançois Tigeot 
2124d28e78fSSepherosa Ziehau 	device_set_desc(dev, "VGA-compatible display");
2134d28e78fSSepherosa Ziehau 	return (BUS_PROBE_GENERIC);
2144d28e78fSSepherosa Ziehau }
2154d28e78fSSepherosa Ziehau 
2164d28e78fSSepherosa Ziehau static int
vga_pci_attach(device_t dev)2174d28e78fSSepherosa Ziehau vga_pci_attach(device_t dev)
2184d28e78fSSepherosa Ziehau {
2194d28e78fSSepherosa Ziehau 
2204d28e78fSSepherosa Ziehau 	bus_generic_probe(dev);
2214d28e78fSSepherosa Ziehau 
2224d28e78fSSepherosa Ziehau 	/* Always create a drm child for now to make it easier on drm. */
2234d28e78fSSepherosa Ziehau 	device_add_child(dev, "drm", -1);
2244d28e78fSSepherosa Ziehau 	bus_generic_attach(dev);
2252a979d81SImre Vadasz 
2262a979d81SImre Vadasz 	if (vga_pci_is_boot_display(dev))
2272a979d81SImre Vadasz 		device_printf(dev, "Boot video device\n");
2282a979d81SImre Vadasz 
2294d28e78fSSepherosa Ziehau 	return (0);
2304d28e78fSSepherosa Ziehau }
2314d28e78fSSepherosa Ziehau 
2324d28e78fSSepherosa Ziehau static int
vga_pci_suspend(device_t dev)2334d28e78fSSepherosa Ziehau vga_pci_suspend(device_t dev)
2344d28e78fSSepherosa Ziehau {
2354d28e78fSSepherosa Ziehau 
2364d28e78fSSepherosa Ziehau 	return (bus_generic_suspend(dev));
2374d28e78fSSepherosa Ziehau }
2384d28e78fSSepherosa Ziehau 
2394d28e78fSSepherosa Ziehau static int
vga_pci_resume(device_t dev)2404d28e78fSSepherosa Ziehau vga_pci_resume(device_t dev)
2414d28e78fSSepherosa Ziehau {
2424d28e78fSSepherosa Ziehau 
2434d28e78fSSepherosa Ziehau 	return (bus_generic_resume(dev));
2444d28e78fSSepherosa Ziehau }
2454d28e78fSSepherosa Ziehau 
2464d28e78fSSepherosa Ziehau /* Bus interface. */
2474d28e78fSSepherosa Ziehau 
2484d28e78fSSepherosa Ziehau static int
vga_pci_read_ivar(device_t dev,device_t child,int which,uintptr_t * result)2494d28e78fSSepherosa Ziehau vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
2504d28e78fSSepherosa Ziehau {
2514d28e78fSSepherosa Ziehau 
2524d28e78fSSepherosa Ziehau 	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
2534d28e78fSSepherosa Ziehau }
2544d28e78fSSepherosa Ziehau 
2554d28e78fSSepherosa Ziehau static int
vga_pci_write_ivar(device_t dev,device_t child,int which,uintptr_t value)2564d28e78fSSepherosa Ziehau vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
2574d28e78fSSepherosa Ziehau {
2584d28e78fSSepherosa Ziehau 
2594d28e78fSSepherosa Ziehau 	return (EINVAL);
2604d28e78fSSepherosa Ziehau }
2614d28e78fSSepherosa Ziehau 
262*0855c8c0SImre Vadász static int
vga_pci_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_intr_t * intr,void * arg,void ** cookiep,lwkt_serialize_t serializer,const char * desc)263*0855c8c0SImre Vadász vga_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
264*0855c8c0SImre Vadász     int flags, driver_intr_t *intr, void *arg, void **cookiep,
265*0855c8c0SImre Vadász     lwkt_serialize_t serializer, const char *desc)
266*0855c8c0SImre Vadász {
267*0855c8c0SImre Vadász 
268*0855c8c0SImre Vadász 	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
269*0855c8c0SImre Vadász 	    intr, arg, cookiep, serializer, desc));
270*0855c8c0SImre Vadász }
271*0855c8c0SImre Vadász 
272*0855c8c0SImre Vadász static int
vga_pci_teardown_intr(device_t dev,device_t child,struct resource * irq,void * cookie)273*0855c8c0SImre Vadász vga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
274*0855c8c0SImre Vadász     void *cookie)
275*0855c8c0SImre Vadász {
276*0855c8c0SImre Vadász 
277*0855c8c0SImre Vadász 	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
278*0855c8c0SImre Vadász }
279*0855c8c0SImre Vadász 
280072d6095SFrançois Tigeot static struct vga_resource *
lookup_res(struct vga_pci_softc * sc,int rid)281072d6095SFrançois Tigeot lookup_res(struct vga_pci_softc *sc, int rid)
282072d6095SFrançois Tigeot {
283072d6095SFrançois Tigeot 	int bar;
284072d6095SFrançois Tigeot 
285072d6095SFrançois Tigeot 	if (rid == PCIR_BIOS)
286072d6095SFrançois Tigeot 		return (&sc->vga_bios);
287072d6095SFrançois Tigeot 	bar = PCI_RID2BAR(rid);
288072d6095SFrançois Tigeot 	if (bar >= 0 && bar <= PCIR_MAX_BAR_0)
289072d6095SFrançois Tigeot 		return (&sc->vga_bars[bar]);
290072d6095SFrançois Tigeot 	return (NULL);
291072d6095SFrançois Tigeot }
292072d6095SFrançois Tigeot 
2934d28e78fSSepherosa Ziehau static struct resource *
vga_pci_alloc_resource(device_t dev,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags,int cpuid __unused)2944d28e78fSSepherosa Ziehau vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
295384438e3SSepherosa Ziehau     u_long start, u_long end, u_long count, u_int flags, int cpuid __unused)
2964d28e78fSSepherosa Ziehau {
297072d6095SFrançois Tigeot 	struct vga_resource *vr;
2984d28e78fSSepherosa Ziehau 
299072d6095SFrançois Tigeot 	switch (type) {
300072d6095SFrançois Tigeot 	case SYS_RES_MEMORY:
301072d6095SFrançois Tigeot 	case SYS_RES_IOPORT:
302072d6095SFrançois Tigeot 		/*
303072d6095SFrançois Tigeot 		 * For BARs, we cache the resource so that we only allocate it
304072d6095SFrançois Tigeot 		 * from the PCI bus once.
305072d6095SFrançois Tigeot 		 */
306072d6095SFrançois Tigeot 		vr = lookup_res(device_get_softc(dev), *rid);
307072d6095SFrançois Tigeot 		if (vr == NULL)
308072d6095SFrançois Tigeot 			return (NULL);
309072d6095SFrançois Tigeot 		if (vr->vr_res == NULL)
310072d6095SFrançois Tigeot 			vr->vr_res = bus_alloc_resource(dev, type, rid, start,
311072d6095SFrançois Tigeot 			    end, count, flags);
312072d6095SFrançois Tigeot 		if (vr->vr_res != NULL)
313072d6095SFrançois Tigeot 			vr->vr_refs++;
314072d6095SFrançois Tigeot 		return (vr->vr_res);
315072d6095SFrançois Tigeot 	}
3164d28e78fSSepherosa Ziehau 	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
3174d28e78fSSepherosa Ziehau }
3184d28e78fSSepherosa Ziehau 
3194d28e78fSSepherosa Ziehau static int
vga_pci_release_resource(device_t dev,device_t child,int type,int rid,struct resource * r)3204d28e78fSSepherosa Ziehau vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
3214d28e78fSSepherosa Ziehau     struct resource *r)
3224d28e78fSSepherosa Ziehau {
323e8be1190SSepherosa Ziehau 	struct vga_resource *vr;
3244d28e78fSSepherosa Ziehau 
325e8be1190SSepherosa Ziehau 	switch (type) {
326e8be1190SSepherosa Ziehau 	case SYS_RES_MEMORY:
327e8be1190SSepherosa Ziehau 	case SYS_RES_IOPORT:
328e8be1190SSepherosa Ziehau 		/*
329e8be1190SSepherosa Ziehau 		 * Stop caching the resource when refs drops to 0
330e8be1190SSepherosa Ziehau 		 */
331e8be1190SSepherosa Ziehau 		vr = lookup_res(device_get_softc(dev), rid);
332e8be1190SSepherosa Ziehau 		if (vr && vr->vr_refs > 0) {
333e8be1190SSepherosa Ziehau 			if (--vr->vr_refs > 0)
334e8be1190SSepherosa Ziehau 				return(0);
335e8be1190SSepherosa Ziehau 			vr->vr_res = NULL;
336e8be1190SSepherosa Ziehau 			/* fall through */
337e8be1190SSepherosa Ziehau 		}
338e8be1190SSepherosa Ziehau 		/* fall through */
339e8be1190SSepherosa Ziehau 		break;
340e8be1190SSepherosa Ziehau 	}
3414d28e78fSSepherosa Ziehau 	return (bus_release_resource(dev, type, rid, r));
3424d28e78fSSepherosa Ziehau }
3434d28e78fSSepherosa Ziehau 
3444d28e78fSSepherosa Ziehau /* PCI interface. */
3454d28e78fSSepherosa Ziehau 
3464d28e78fSSepherosa Ziehau static uint32_t
vga_pci_read_config(device_t dev,device_t child,int reg,int width)3474d28e78fSSepherosa Ziehau vga_pci_read_config(device_t dev, device_t child, int reg, int width)
3484d28e78fSSepherosa Ziehau {
3494d28e78fSSepherosa Ziehau 
3504d28e78fSSepherosa Ziehau 	return (pci_read_config(dev, reg, width));
3514d28e78fSSepherosa Ziehau }
3524d28e78fSSepherosa Ziehau 
3534d28e78fSSepherosa Ziehau static void
vga_pci_write_config(device_t dev,device_t child,int reg,uint32_t val,int width)3544d28e78fSSepherosa Ziehau vga_pci_write_config(device_t dev, device_t child, int reg,
3554d28e78fSSepherosa Ziehau     uint32_t val, int width)
3564d28e78fSSepherosa Ziehau {
3574d28e78fSSepherosa Ziehau 
3584d28e78fSSepherosa Ziehau 	pci_write_config(dev, reg, val, width);
3594d28e78fSSepherosa Ziehau }
3604d28e78fSSepherosa Ziehau 
3614d28e78fSSepherosa Ziehau static int
vga_pci_enable_busmaster(device_t dev,device_t child)3624d28e78fSSepherosa Ziehau vga_pci_enable_busmaster(device_t dev, device_t child)
3634d28e78fSSepherosa Ziehau {
3644d28e78fSSepherosa Ziehau 
3654d28e78fSSepherosa Ziehau 	return (pci_enable_busmaster(dev));
3664d28e78fSSepherosa Ziehau }
3674d28e78fSSepherosa Ziehau 
3684d28e78fSSepherosa Ziehau static int
vga_pci_disable_busmaster(device_t dev,device_t child)3694d28e78fSSepherosa Ziehau vga_pci_disable_busmaster(device_t dev, device_t child)
3704d28e78fSSepherosa Ziehau {
3714d28e78fSSepherosa Ziehau 
3724d28e78fSSepherosa Ziehau 	return (pci_disable_busmaster(dev));
3734d28e78fSSepherosa Ziehau }
3744d28e78fSSepherosa Ziehau 
3754d28e78fSSepherosa Ziehau static int
vga_pci_enable_io(device_t dev,device_t child,int space)3764d28e78fSSepherosa Ziehau vga_pci_enable_io(device_t dev, device_t child, int space)
3774d28e78fSSepherosa Ziehau {
3784d28e78fSSepherosa Ziehau 
3794d28e78fSSepherosa Ziehau 	device_printf(dev, "child %s requested pci_enable_io\n",
3804d28e78fSSepherosa Ziehau 	    device_get_nameunit(child));
3814d28e78fSSepherosa Ziehau 	return (pci_enable_io(dev, space));
3824d28e78fSSepherosa Ziehau }
3834d28e78fSSepherosa Ziehau 
3844d28e78fSSepherosa Ziehau static int
vga_pci_disable_io(device_t dev,device_t child,int space)3854d28e78fSSepherosa Ziehau vga_pci_disable_io(device_t dev, device_t child, int space)
3864d28e78fSSepherosa Ziehau {
3874d28e78fSSepherosa Ziehau 
3884d28e78fSSepherosa Ziehau 	device_printf(dev, "child %s requested pci_disable_io\n",
3894d28e78fSSepherosa Ziehau 	    device_get_nameunit(child));
3904d28e78fSSepherosa Ziehau 	return (pci_disable_io(dev, space));
3914d28e78fSSepherosa Ziehau }
3924d28e78fSSepherosa Ziehau 
3934d28e78fSSepherosa Ziehau static int
vga_pci_get_vpd_ident(device_t dev,device_t child,const char ** identptr)394*0855c8c0SImre Vadász vga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
395*0855c8c0SImre Vadász {
396*0855c8c0SImre Vadász 
397*0855c8c0SImre Vadász 	return (pci_get_vpd_ident(dev, identptr));
398*0855c8c0SImre Vadász }
399*0855c8c0SImre Vadász 
400*0855c8c0SImre Vadász static int
vga_pci_get_vpd_readonly(device_t dev,device_t child,const char * kw,const char ** vptr)401*0855c8c0SImre Vadász vga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
402*0855c8c0SImre Vadász     const char **vptr)
403*0855c8c0SImre Vadász {
404*0855c8c0SImre Vadász 
405*0855c8c0SImre Vadász 	return (pci_get_vpd_readonly(dev, kw, vptr));
406*0855c8c0SImre Vadász }
407*0855c8c0SImre Vadász 
408*0855c8c0SImre Vadász static int
vga_pci_set_powerstate(device_t dev,device_t child,int state)4094d28e78fSSepherosa Ziehau vga_pci_set_powerstate(device_t dev, device_t child, int state)
4104d28e78fSSepherosa Ziehau {
4114d28e78fSSepherosa Ziehau 
4124d28e78fSSepherosa Ziehau 	return (pci_set_powerstate(dev, state));
4134d28e78fSSepherosa Ziehau }
4144d28e78fSSepherosa Ziehau 
4154d28e78fSSepherosa Ziehau static int
vga_pci_get_powerstate(device_t dev,device_t child)4164d28e78fSSepherosa Ziehau vga_pci_get_powerstate(device_t dev, device_t child)
4174d28e78fSSepherosa Ziehau {
4184d28e78fSSepherosa Ziehau 
4194d28e78fSSepherosa Ziehau 	return (pci_get_powerstate(dev));
4204d28e78fSSepherosa Ziehau }
4214d28e78fSSepherosa Ziehau 
4224d28e78fSSepherosa Ziehau static int
vga_pci_assign_interrupt(device_t dev,device_t child)4234d28e78fSSepherosa Ziehau vga_pci_assign_interrupt(device_t dev, device_t child)
4244d28e78fSSepherosa Ziehau {
4254d28e78fSSepherosa Ziehau 
4264d28e78fSSepherosa Ziehau 	device_printf(dev, "child %s requested pci_assign_interrupt\n",
4274d28e78fSSepherosa Ziehau 	    device_get_nameunit(child));
4284d28e78fSSepherosa Ziehau 	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
4294d28e78fSSepherosa Ziehau }
4304d28e78fSSepherosa Ziehau 
4314d28e78fSSepherosa Ziehau static int
vga_pci_find_extcap(device_t dev,device_t child,int capability,int * capreg)4324d28e78fSSepherosa Ziehau vga_pci_find_extcap(device_t dev, device_t child, int capability,
4334d28e78fSSepherosa Ziehau     int *capreg)
4344d28e78fSSepherosa Ziehau {
4354d28e78fSSepherosa Ziehau 
4364d28e78fSSepherosa Ziehau 	return (pci_find_extcap(dev, capability, capreg));
4374d28e78fSSepherosa Ziehau }
4384d28e78fSSepherosa Ziehau 
439*0855c8c0SImre Vadász static int
vga_pci_alloc_msi(device_t dev,device_t child,int * rid,int count,int cpuid)440*0855c8c0SImre Vadász vga_pci_alloc_msi(device_t dev, device_t child, int *rid, int count,
441*0855c8c0SImre Vadász     int cpuid)
442*0855c8c0SImre Vadász {
443*0855c8c0SImre Vadász 	struct vga_pci_softc *sc;
444*0855c8c0SImre Vadász 	int error;
445*0855c8c0SImre Vadász 
446*0855c8c0SImre Vadász 	sc = device_get_softc(dev);
447*0855c8c0SImre Vadász 	if (sc->vga_msi_child != NULL)
448*0855c8c0SImre Vadász 		return (EBUSY);
449*0855c8c0SImre Vadász 	error = pci_alloc_msi(dev, rid, count, cpuid);
450*0855c8c0SImre Vadász 	if (error == 0)
451*0855c8c0SImre Vadász 		sc->vga_msi_child = child;
452*0855c8c0SImre Vadász 	return (error);
453*0855c8c0SImre Vadász }
454*0855c8c0SImre Vadász 
455*0855c8c0SImre Vadász static int
vga_pci_release_msi(device_t dev,device_t child)456*0855c8c0SImre Vadász vga_pci_release_msi(device_t dev, device_t child)
457*0855c8c0SImre Vadász {
458*0855c8c0SImre Vadász 	struct vga_pci_softc *sc;
459*0855c8c0SImre Vadász 	int error;
460*0855c8c0SImre Vadász 
461*0855c8c0SImre Vadász 	sc = device_get_softc(dev);
462*0855c8c0SImre Vadász 	if (sc->vga_msi_child != child)
463*0855c8c0SImre Vadász 		return (ENXIO);
464*0855c8c0SImre Vadász 	error = pci_release_msi(dev);
465*0855c8c0SImre Vadász 	if (error == 0)
466*0855c8c0SImre Vadász 		sc->vga_msi_child = NULL;
467*0855c8c0SImre Vadász 	return (error);
468*0855c8c0SImre Vadász }
469*0855c8c0SImre Vadász 
470*0855c8c0SImre Vadász static int
vga_pci_msi_count(device_t dev,device_t child)471*0855c8c0SImre Vadász vga_pci_msi_count(device_t dev, device_t child)
472*0855c8c0SImre Vadász {
473*0855c8c0SImre Vadász 
474*0855c8c0SImre Vadász 	return (pci_msi_count(dev));
475*0855c8c0SImre Vadász }
476*0855c8c0SImre Vadász 
4774d28e78fSSepherosa Ziehau static device_method_t vga_pci_methods[] = {
4784d28e78fSSepherosa Ziehau 	/* Device interface */
4794d28e78fSSepherosa Ziehau 	DEVMETHOD(device_probe,		vga_pci_probe),
4804d28e78fSSepherosa Ziehau 	DEVMETHOD(device_attach,	vga_pci_attach),
4814d28e78fSSepherosa Ziehau 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
4824d28e78fSSepherosa Ziehau 	DEVMETHOD(device_suspend,	vga_pci_suspend),
4834d28e78fSSepherosa Ziehau 	DEVMETHOD(device_resume,	vga_pci_resume),
4844d28e78fSSepherosa Ziehau 
4854d28e78fSSepherosa Ziehau 	/* Bus interface */
4864d28e78fSSepherosa Ziehau 	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
4874d28e78fSSepherosa Ziehau 	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
488*0855c8c0SImre Vadász 	DEVMETHOD(bus_setup_intr,	vga_pci_setup_intr),
489*0855c8c0SImre Vadász 	DEVMETHOD(bus_teardown_intr,	vga_pci_teardown_intr),
4904d28e78fSSepherosa Ziehau 
4914d28e78fSSepherosa Ziehau 	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
4924d28e78fSSepherosa Ziehau 	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
4934d28e78fSSepherosa Ziehau 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
4944d28e78fSSepherosa Ziehau 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
4954d28e78fSSepherosa Ziehau 
4964d28e78fSSepherosa Ziehau 	/* PCI interface */
4974d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_read_config,	vga_pci_read_config),
4984d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_write_config,	vga_pci_write_config),
4994d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
5004d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
5014d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
5024d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
503*0855c8c0SImre Vadász 	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
504*0855c8c0SImre Vadász 	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
5054d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
5064d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
5074d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
5084d28e78fSSepherosa Ziehau 	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
509*0855c8c0SImre Vadász 	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
510*0855c8c0SImre Vadász 	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
511*0855c8c0SImre Vadász 	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
5124d28e78fSSepherosa Ziehau 
513d3c9c58eSSascha Wildner 	DEVMETHOD_END
5144d28e78fSSepherosa Ziehau };
5154d28e78fSSepherosa Ziehau 
5164d28e78fSSepherosa Ziehau static driver_t vga_pci_driver = {
5174d28e78fSSepherosa Ziehau 	"vgapci",
5184d28e78fSSepherosa Ziehau 	vga_pci_methods,
519e8be1190SSepherosa Ziehau 	sizeof(struct vga_pci_softc),
5204d28e78fSSepherosa Ziehau };
5214d28e78fSSepherosa Ziehau 
5224d28e78fSSepherosa Ziehau static devclass_t vga_devclass;
5234d28e78fSSepherosa Ziehau 
524aa2b9d05SSascha Wildner DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, NULL, NULL);
525