vga_pci.c revision 249476
178189Sbrian/*-
278189Sbrian * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
378189Sbrian * All rights reserved.
478189Sbrian *
578189Sbrian * Redistribution and use in source and binary forms, with or without
613389Sphk * modification, are permitted provided that the following conditions
778189Sbrian * are met:
878189Sbrian * 1. Redistributions of source code must retain the above copyright
978189Sbrian *    notice, this list of conditions and the following disclaimer.
1078189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer in the
1278189Sbrian *    documentation and/or other materials provided with the distribution.
1378189Sbrian * 3. Neither the name of the author nor the names of any co-contributors
1478189Sbrian *    may be used to endorse or promote products derived from this software
1513389Sphk *    without specific prior written permission.
1678189Sbrian *
1778189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1878189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1978189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2078189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2178189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2278189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2378189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2478189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2578189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2678189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713389Sphk * SUCH DAMAGE.
2850479Speter */
2913389Sphk
3013389Sphk#include <sys/cdefs.h>
3136285Sbrian__FBSDID("$FreeBSD: head/sys/dev/pci/vga_pci.c 249476 2013-04-14 14:02:34Z kib $");
3236285Sbrian
3336285Sbrian/*
34134789Sbrian * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
35134789Sbrian * drm(4) should attach as children of this device.
36134789Sbrian *
37 * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
38 * in or rename it.
39 */
40
41#include <sys/param.h>
42#include <sys/bus.h>
43#include <sys/kernel.h>
44#include <sys/module.h>
45#include <sys/rman.h>
46#include <sys/sysctl.h>
47#include <sys/systm.h>
48
49#include <dev/pci/pcireg.h>
50#include <dev/pci/pcivar.h>
51
52struct vga_resource {
53	struct resource	*vr_res;
54	int	vr_refs;
55};
56
57struct vga_pci_softc {
58	device_t	vga_msi_child;	/* Child driver using MSI. */
59	struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1];
60	struct vga_resource vga_bios;
61};
62
63SYSCTL_DECL(_hw_pci);
64
65int vga_pci_default_unit = -1;
66TUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit);
67SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
68    &vga_pci_default_unit, -1, "Default VGA-compatible display");
69
70static int
71vga_pci_probe(device_t dev)
72{
73	device_t bdev;
74	int unit;
75	uint16_t bctl;
76
77	switch (pci_get_class(dev)) {
78	case PCIC_DISPLAY:
79		break;
80	case PCIC_OLD:
81		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
82			return (ENXIO);
83		break;
84	default:
85		return (ENXIO);
86	}
87
88	/* Probe default display. */
89	unit = device_get_unit(dev);
90	bdev = device_get_parent(device_get_parent(dev));
91	bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2);
92	if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0)
93		vga_pci_default_unit = unit;
94	if (vga_pci_default_unit == unit)
95		device_set_flags(dev, 1);
96
97	device_set_desc(dev, "VGA-compatible display");
98	return (BUS_PROBE_GENERIC);
99}
100
101static int
102vga_pci_attach(device_t dev)
103{
104
105	bus_generic_probe(dev);
106
107	/* Always create a drm child for now to make it easier on drm. */
108	device_add_child(dev, "drm", -1);
109	device_add_child(dev, "drmn", -1);
110	bus_generic_attach(dev);
111	return (0);
112}
113
114static int
115vga_pci_suspend(device_t dev)
116{
117
118	return (bus_generic_suspend(dev));
119}
120
121static int
122vga_pci_resume(device_t dev)
123{
124
125	return (bus_generic_resume(dev));
126}
127
128/* Bus interface. */
129
130static int
131vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
132{
133
134	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
135}
136
137static int
138vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
139{
140
141	return (EINVAL);
142}
143
144static int
145vga_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
146    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
147    void **cookiep)
148{
149	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
150	    filter, intr, arg, cookiep));
151}
152
153static int
154vga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
155    void *cookie)
156{
157	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
158}
159
160static struct vga_resource *
161lookup_res(struct vga_pci_softc *sc, int rid)
162{
163	int bar;
164
165	if (rid == PCIR_BIOS)
166		return (&sc->vga_bios);
167	bar = PCI_RID2BAR(rid);
168	if (bar >= 0 && bar <= PCIR_MAX_BAR_0)
169		return (&sc->vga_bars[bar]);
170	return (NULL);
171}
172
173static struct resource *
174vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
175    u_long start, u_long end, u_long count, u_int flags)
176{
177	struct vga_resource *vr;
178
179	switch (type) {
180	case SYS_RES_MEMORY:
181	case SYS_RES_IOPORT:
182		/*
183		 * For BARs, we cache the resource so that we only allocate it
184		 * from the PCI bus once.
185		 */
186		vr = lookup_res(device_get_softc(dev), *rid);
187		if (vr == NULL)
188			return (NULL);
189		if (vr->vr_res == NULL)
190			vr->vr_res = bus_alloc_resource(dev, type, rid, start,
191			    end, count, flags);
192		if (vr->vr_res != NULL)
193			vr->vr_refs++;
194		return (vr->vr_res);
195	}
196	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
197}
198
199static int
200vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
201    struct resource *r)
202{
203	struct vga_resource *vr;
204	int error;
205
206	switch (type) {
207	case SYS_RES_MEMORY:
208	case SYS_RES_IOPORT:
209		/*
210		 * For BARs, we release the resource from the PCI bus
211		 * when the last child reference goes away.
212		 */
213		vr = lookup_res(device_get_softc(dev), rid);
214		if (vr == NULL)
215			return (EINVAL);
216		if (vr->vr_res == NULL)
217			return (EINVAL);
218		KASSERT(vr->vr_res == r, ("vga_pci resource mismatch"));
219		if (vr->vr_refs > 1) {
220			vr->vr_refs--;
221			return (0);
222		}
223		KASSERT(vr->vr_refs > 0,
224		    ("vga_pci resource reference count underflow"));
225		error = bus_release_resource(dev, type, rid, r);
226		if (error == 0) {
227			vr->vr_res = NULL;
228			vr->vr_refs = 0;
229		}
230		return (error);
231	}
232
233	return (bus_release_resource(dev, type, rid, r));
234}
235
236/* PCI interface. */
237
238static uint32_t
239vga_pci_read_config(device_t dev, device_t child, int reg, int width)
240{
241
242	return (pci_read_config(dev, reg, width));
243}
244
245static void
246vga_pci_write_config(device_t dev, device_t child, int reg,
247    uint32_t val, int width)
248{
249
250	pci_write_config(dev, reg, val, width);
251}
252
253static int
254vga_pci_enable_busmaster(device_t dev, device_t child)
255{
256
257	return (pci_enable_busmaster(dev));
258}
259
260static int
261vga_pci_disable_busmaster(device_t dev, device_t child)
262{
263
264	return (pci_disable_busmaster(dev));
265}
266
267static int
268vga_pci_enable_io(device_t dev, device_t child, int space)
269{
270
271	device_printf(dev, "child %s requested pci_enable_io\n",
272	    device_get_nameunit(child));
273	return (pci_enable_io(dev, space));
274}
275
276static int
277vga_pci_disable_io(device_t dev, device_t child, int space)
278{
279
280	device_printf(dev, "child %s requested pci_disable_io\n",
281	    device_get_nameunit(child));
282	return (pci_disable_io(dev, space));
283}
284
285static int
286vga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
287{
288
289	return (pci_get_vpd_ident(dev, identptr));
290}
291
292static int
293vga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
294    const char **vptr)
295{
296
297	return (pci_get_vpd_readonly(dev, kw, vptr));
298}
299
300static int
301vga_pci_set_powerstate(device_t dev, device_t child, int state)
302{
303
304	device_printf(dev, "child %s requested pci_set_powerstate\n",
305	    device_get_nameunit(child));
306	return (pci_set_powerstate(dev, state));
307}
308
309static int
310vga_pci_get_powerstate(device_t dev, device_t child)
311{
312
313	device_printf(dev, "child %s requested pci_get_powerstate\n",
314	    device_get_nameunit(child));
315	return (pci_get_powerstate(dev));
316}
317
318static int
319vga_pci_assign_interrupt(device_t dev, device_t child)
320{
321
322	device_printf(dev, "child %s requested pci_assign_interrupt\n",
323	    device_get_nameunit(child));
324	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
325}
326
327static int
328vga_pci_find_cap(device_t dev, device_t child, int capability,
329    int *capreg)
330{
331
332	return (pci_find_cap(dev, capability, capreg));
333}
334
335static int
336vga_pci_find_extcap(device_t dev, device_t child, int capability,
337    int *capreg)
338{
339
340	return (pci_find_extcap(dev, capability, capreg));
341}
342
343static int
344vga_pci_find_htcap(device_t dev, device_t child, int capability,
345    int *capreg)
346{
347
348	return (pci_find_htcap(dev, capability, capreg));
349}
350
351static int
352vga_pci_alloc_msi(device_t dev, device_t child, int *count)
353{
354	struct vga_pci_softc *sc;
355	int error;
356
357	sc = device_get_softc(dev);
358	if (sc->vga_msi_child != NULL)
359		return (EBUSY);
360	error = pci_alloc_msi(dev, count);
361	if (error == 0)
362		sc->vga_msi_child = child;
363	return (error);
364}
365
366static int
367vga_pci_alloc_msix(device_t dev, device_t child, int *count)
368{
369	struct vga_pci_softc *sc;
370	int error;
371
372	sc = device_get_softc(dev);
373	if (sc->vga_msi_child != NULL)
374		return (EBUSY);
375	error = pci_alloc_msix(dev, count);
376	if (error == 0)
377		sc->vga_msi_child = child;
378	return (error);
379}
380
381static int
382vga_pci_remap_msix(device_t dev, device_t child, int count,
383    const u_int *vectors)
384{
385	struct vga_pci_softc *sc;
386
387	sc = device_get_softc(dev);
388	if (sc->vga_msi_child != child)
389		return (ENXIO);
390	return (pci_remap_msix(dev, count, vectors));
391}
392
393static int
394vga_pci_release_msi(device_t dev, device_t child)
395{
396	struct vga_pci_softc *sc;
397	int error;
398
399	sc = device_get_softc(dev);
400	if (sc->vga_msi_child != child)
401		return (ENXIO);
402	error = pci_release_msi(dev);
403	if (error == 0)
404		sc->vga_msi_child = NULL;
405	return (error);
406}
407
408static int
409vga_pci_msi_count(device_t dev, device_t child)
410{
411
412	return (pci_msi_count(dev));
413}
414
415static int
416vga_pci_msix_count(device_t dev, device_t child)
417{
418
419	return (pci_msix_count(dev));
420}
421
422static bus_dma_tag_t
423vga_pci_get_dma_tag(device_t bus, device_t child)
424{
425
426	return (bus_get_dma_tag(bus));
427}
428
429static device_method_t vga_pci_methods[] = {
430	/* Device interface */
431	DEVMETHOD(device_probe,		vga_pci_probe),
432	DEVMETHOD(device_attach,	vga_pci_attach),
433	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
434	DEVMETHOD(device_suspend,	vga_pci_suspend),
435	DEVMETHOD(device_resume,	vga_pci_resume),
436
437	/* Bus interface */
438	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
439	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
440	DEVMETHOD(bus_setup_intr,	vga_pci_setup_intr),
441	DEVMETHOD(bus_teardown_intr,	vga_pci_teardown_intr),
442	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
443	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
444	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
445	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
446	DEVMETHOD(bus_get_dma_tag,	vga_pci_get_dma_tag),
447
448	/* PCI interface */
449	DEVMETHOD(pci_read_config,	vga_pci_read_config),
450	DEVMETHOD(pci_write_config,	vga_pci_write_config),
451	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
452	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
453	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
454	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
455	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
456	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
457	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
458	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
459	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
460	DEVMETHOD(pci_find_cap,		vga_pci_find_cap),
461	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
462	DEVMETHOD(pci_find_htcap,	vga_pci_find_htcap),
463	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
464	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
465	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),
466	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
467	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
468	DEVMETHOD(pci_msix_count,	vga_pci_msix_count),
469
470	{ 0, 0 }
471};
472
473static driver_t vga_pci_driver = {
474	"vgapci",
475	vga_pci_methods,
476	sizeof(struct vga_pci_softc),
477};
478
479static devclass_t vga_devclass;
480
481DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
482