vga_pci.c revision 249476
119304Speter/*- 219304Speter * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org> 319304Speter * All rights reserved. 419304Speter * 519304Speter * Redistribution and use in source and binary forms, with or without 619304Speter * modification, are permitted provided that the following conditions 719304Speter * are met: 819304Speter * 1. Redistributions of source code must retain the above copyright 919304Speter * notice, this list of conditions and the following disclaimer. 1019304Speter * 2. Redistributions in binary form must reproduce the above copyright 1119304Speter * notice, this list of conditions and the following disclaimer in the 1219304Speter * documentation and/or other materials provided with the distribution. 13254225Speter * 3. Neither the name of the author nor the names of any co-contributors 1419304Speter * may be used to endorse or promote products derived from this software 1519304Speter * without specific prior written permission. 1619304Speter * 1719304Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1819304Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1919304Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2019304Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2119304Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2219304Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2319304Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2419304Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2519304Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2619304Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2719304Speter * SUCH DAMAGE. 2819304Speter */ 2919304Speter 3019304Speter#include <sys/cdefs.h> 3119304Speter__FBSDID("$FreeBSD: head/sys/dev/pci/vga_pci.c 249476 2013-04-14 14:02:34Z kib $"); 3219304Speter 3319304Speter/* 3419304Speter * Simple driver for PCI VGA display devices. Drivers such as agp(4) and 3519304Speter * drm(4) should attach as children of this device. 3619304Speter * 3719304Speter * XXX: The vgapci name is a hack until we somehow merge the isa vga driver 3819304Speter * in or rename it. 3919304Speter */ 4019304Speter 4119304Speter#include <sys/param.h> 4219304Speter#include <sys/bus.h> 4319304Speter#include <sys/kernel.h> 4419304Speter#include <sys/module.h> 4519304Speter#include <sys/rman.h> 4619304Speter#include <sys/sysctl.h> 4719304Speter#include <sys/systm.h> 4819304Speter 4919304Speter#include <dev/pci/pcireg.h> 5019304Speter#include <dev/pci/pcivar.h> 5119304Speter 5219304Speterstruct vga_resource { 5319304Speter struct resource *vr_res; 5419304Speter int vr_refs; 5519304Speter}; 5619304Speter 5719304Speterstruct vga_pci_softc { 5819304Speter device_t vga_msi_child; /* Child driver using MSI. */ 5919304Speter struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1]; 6019304Speter struct vga_resource vga_bios; 6119304Speter}; 6219304Speter 6319304SpeterSYSCTL_DECL(_hw_pci); 6419304Speter 6519304Speterint vga_pci_default_unit = -1; 6619304SpeterTUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit); 6719304SpeterSYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN, 6819304Speter &vga_pci_default_unit, -1, "Default VGA-compatible display"); 6919304Speter 7019304Speterstatic int 7119304Spetervga_pci_probe(device_t dev) 7219304Speter{ 7319304Speter device_t bdev; 7419304Speter int unit; 7519304Speter uint16_t bctl; 7619304Speter 7719304Speter switch (pci_get_class(dev)) { 7819304Speter case PCIC_DISPLAY: 7919304Speter break; 80254225Speter case PCIC_OLD: 8119304Speter if (pci_get_subclass(dev) != PCIS_OLD_VGA) 8219304Speter return (ENXIO); 8319304Speter break; 8419304Speter default: 8519304Speter return (ENXIO); 8619304Speter } 8719304Speter 8819304Speter /* Probe default display. */ 8919304Speter unit = device_get_unit(dev); 9019304Speter bdev = device_get_parent(device_get_parent(dev)); 9119304Speter bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2); 92254225Speter if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0) 9319304Speter vga_pci_default_unit = unit; 9419304Speter if (vga_pci_default_unit == unit) 9519304Speter device_set_flags(dev, 1); 9619304Speter 9719304Speter device_set_desc(dev, "VGA-compatible display"); 9819304Speter return (BUS_PROBE_GENERIC); 9919304Speter} 10019304Speter 10119304Speterstatic int 102254225Spetervga_pci_attach(device_t dev) 10319304Speter{ 10419304Speter 10519304Speter bus_generic_probe(dev); 10619304Speter 10719304Speter /* Always create a drm child for now to make it easier on drm. */ 10819304Speter device_add_child(dev, "drm", -1); 10919304Speter device_add_child(dev, "drmn", -1); 11019304Speter bus_generic_attach(dev); 11119304Speter return (0); 11219304Speter} 11319304Speter 11419304Speterstatic int 11519304Spetervga_pci_suspend(device_t dev) 11619304Speter{ 11719304Speter 11819304Speter return (bus_generic_suspend(dev)); 11919304Speter} 12019304Speter 121254225Speterstatic int 12219304Spetervga_pci_resume(device_t dev) 12319304Speter{ 12419304Speter 12519304Speter return (bus_generic_resume(dev)); 12619304Speter} 12719304Speter 12819304Speter/* Bus interface. */ 12919304Speter 13019304Speterstatic int 13119304Spetervga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 13219304Speter{ 13319304Speter 13419304Speter return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result)); 13519304Speter} 13619304Speter 13719304Speterstatic int 13819304Spetervga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 13919304Speter{ 14019304Speter 14119304Speter return (EINVAL); 14219304Speter} 14319304Speter 14419304Speterstatic int 14519304Spetervga_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 14619304Speter int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, 14719304Speter void **cookiep) 14819304Speter{ 149254225Speter return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags, 15019304Speter filter, intr, arg, cookiep)); 15119304Speter} 15219304Speter 15319304Speterstatic int 15419304Spetervga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 15519304Speter void *cookie) 15619304Speter{ 15719304Speter return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie)); 15819304Speter} 15919304Speter 16019304Speterstatic struct vga_resource * 16119304Speterlookup_res(struct vga_pci_softc *sc, int rid) 16219304Speter{ 16319304Speter int bar; 16419304Speter 16519304Speter if (rid == PCIR_BIOS) 16619304Speter return (&sc->vga_bios); 16719304Speter bar = PCI_RID2BAR(rid); 16819304Speter if (bar >= 0 && bar <= PCIR_MAX_BAR_0) 16919304Speter return (&sc->vga_bars[bar]); 17019304Speter return (NULL); 17119304Speter} 17219304Speter 17319304Speterstatic struct resource * 17419304Spetervga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 17519304Speter u_long start, u_long end, u_long count, u_int flags) 17619304Speter{ 17719304Speter struct vga_resource *vr; 17819304Speter 17919304Speter switch (type) { 18019304Speter case SYS_RES_MEMORY: 181254225Speter case SYS_RES_IOPORT: 18219304Speter /* 18319304Speter * For BARs, we cache the resource so that we only allocate it 18419304Speter * from the PCI bus once. 18519304Speter */ 18619304Speter vr = lookup_res(device_get_softc(dev), *rid); 18719304Speter if (vr == NULL) 18819304Speter return (NULL); 18919304Speter if (vr->vr_res == NULL) 19019304Speter vr->vr_res = bus_alloc_resource(dev, type, rid, start, 19119304Speter end, count, flags); 19219304Speter if (vr->vr_res != NULL) 19319304Speter vr->vr_refs++; 19419304Speter return (vr->vr_res); 19519304Speter } 19619304Speter return (bus_alloc_resource(dev, type, rid, start, end, count, flags)); 19719304Speter} 19819304Speter 19919304Speterstatic int 200254225Spetervga_pci_release_resource(device_t dev, device_t child, int type, int rid, 20119304Speter struct resource *r) 20219304Speter{ 20319304Speter struct vga_resource *vr; 20419304Speter int error; 20519304Speter 20619304Speter switch (type) { 20719304Speter case SYS_RES_MEMORY: 20819304Speter case SYS_RES_IOPORT: 20919304Speter /* 21019304Speter * For BARs, we release the resource from the PCI bus 21119304Speter * when the last child reference goes away. 21219304Speter */ 21319304Speter vr = lookup_res(device_get_softc(dev), rid); 21419304Speter if (vr == NULL) 21519304Speter return (EINVAL); 21619304Speter if (vr->vr_res == NULL) 21719304Speter return (EINVAL); 21819304Speter KASSERT(vr->vr_res == r, ("vga_pci resource mismatch")); 21919304Speter if (vr->vr_refs > 1) { 22019304Speter vr->vr_refs--; 22119304Speter return (0); 22219304Speter } 22319304Speter KASSERT(vr->vr_refs > 0, 22419304Speter ("vga_pci resource reference count underflow")); 22519304Speter error = bus_release_resource(dev, type, rid, r); 22619304Speter if (error == 0) { 22719304Speter vr->vr_res = NULL; 22819304Speter vr->vr_refs = 0; 22919304Speter } 23019304Speter return (error); 23119304Speter } 23219304Speter 23319304Speter return (bus_release_resource(dev, type, rid, r)); 23419304Speter} 23519304Speter 23619304Speter/* PCI interface. */ 23719304Speter 23819304Speterstatic uint32_t 23919304Spetervga_pci_read_config(device_t dev, device_t child, int reg, int width) 240254225Speter{ 24119304Speter 24219304Speter return (pci_read_config(dev, reg, width)); 24319304Speter} 24419304Speter 24519304Speterstatic void 24619304Spetervga_pci_write_config(device_t dev, device_t child, int reg, 24719304Speter uint32_t val, int width) 24819304Speter{ 24919304Speter 25019304Speter pci_write_config(dev, reg, val, width); 25119304Speter} 252254225Speter 25319304Speterstatic int 25419304Spetervga_pci_enable_busmaster(device_t dev, device_t child) 25519304Speter{ 25619304Speter 25719304Speter return (pci_enable_busmaster(dev)); 25819304Speter} 25919304Speter 26019304Speterstatic int 26119304Spetervga_pci_disable_busmaster(device_t dev, device_t child) 262254225Speter{ 26319304Speter 26419304Speter return (pci_disable_busmaster(dev)); 26519304Speter} 26619304Speter 26719304Speterstatic int 26819304Spetervga_pci_enable_io(device_t dev, device_t child, int space) 26919304Speter{ 27019304Speter 27119304Speter device_printf(dev, "child %s requested pci_enable_io\n", 27219304Speter device_get_nameunit(child)); 27319304Speter return (pci_enable_io(dev, space)); 27419304Speter} 27519304Speter 27619304Speterstatic int 27719304Spetervga_pci_disable_io(device_t dev, device_t child, int space) 27819304Speter{ 27919304Speter 280254225Speter device_printf(dev, "child %s requested pci_disable_io\n", 28119304Speter device_get_nameunit(child)); 28219304Speter return (pci_disable_io(dev, space)); 283254225Speter} 28419304Speter 28519304Speterstatic int 28619304Spetervga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr) 28719304Speter{ 28819304Speter 28919304Speter return (pci_get_vpd_ident(dev, identptr)); 29019304Speter} 29119304Speter 29219304Speterstatic int 29319304Spetervga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw, 29419304Speter const char **vptr) 29519304Speter{ 29619304Speter 29719304Speter return (pci_get_vpd_readonly(dev, kw, vptr)); 29819304Speter} 29919304Speter 30019304Speterstatic int 30119304Spetervga_pci_set_powerstate(device_t dev, device_t child, int state) 302254225Speter{ 30319304Speter 30419304Speter device_printf(dev, "child %s requested pci_set_powerstate\n", 30519304Speter device_get_nameunit(child)); 30619304Speter return (pci_set_powerstate(dev, state)); 30719304Speter} 30819304Speter 30919304Speterstatic int 31019304Spetervga_pci_get_powerstate(device_t dev, device_t child) 31119304Speter{ 31219304Speter 31319304Speter device_printf(dev, "child %s requested pci_get_powerstate\n", 31419304Speter device_get_nameunit(child)); 31519304Speter return (pci_get_powerstate(dev)); 31619304Speter} 31719304Speter 31819304Speterstatic int 31919304Spetervga_pci_assign_interrupt(device_t dev, device_t child) 32019304Speter{ 32119304Speter 32219304Speter device_printf(dev, "child %s requested pci_assign_interrupt\n", 32319304Speter device_get_nameunit(child)); 32419304Speter return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev)); 32519304Speter} 32619304Speter 32719304Speterstatic int 32819304Spetervga_pci_find_cap(device_t dev, device_t child, int capability, 32919304Speter int *capreg) 33019304Speter{ 331254225Speter 33219304Speter return (pci_find_cap(dev, capability, capreg)); 33319304Speter} 33419304Speter 33519304Speterstatic int 33619304Spetervga_pci_find_extcap(device_t dev, device_t child, int capability, 33719304Speter int *capreg) 33819304Speter{ 33919304Speter 34019304Speter return (pci_find_extcap(dev, capability, capreg)); 34119304Speter} 34219304Speter 34319304Speterstatic int 34419304Spetervga_pci_find_htcap(device_t dev, device_t child, int capability, 34519304Speter int *capreg) 34619304Speter{ 34719304Speter 348254225Speter return (pci_find_htcap(dev, capability, capreg)); 34919304Speter} 35019304Speter 35119304Speterstatic int 35219304Spetervga_pci_alloc_msi(device_t dev, device_t child, int *count) 35319304Speter{ 35419304Speter struct vga_pci_softc *sc; 35519304Speter int error; 35619304Speter 35719304Speter sc = device_get_softc(dev); 35819304Speter if (sc->vga_msi_child != NULL) 35919304Speter return (EBUSY); 36019304Speter error = pci_alloc_msi(dev, count); 36119304Speter if (error == 0) 36219304Speter sc->vga_msi_child = child; 36319304Speter return (error); 36419304Speter} 36519304Speter 36619304Speterstatic int 36719304Spetervga_pci_alloc_msix(device_t dev, device_t child, int *count) 36819304Speter{ 36919304Speter struct vga_pci_softc *sc; 37019304Speter int error; 37119304Speter 37219304Speter sc = device_get_softc(dev); 37319304Speter if (sc->vga_msi_child != NULL) 37419304Speter return (EBUSY); 37519304Speter error = pci_alloc_msix(dev, count); 37619304Speter if (error == 0) 37719304Speter sc->vga_msi_child = child; 37819304Speter return (error); 37919304Speter} 38019304Speter 38119304Speterstatic int 38219304Spetervga_pci_remap_msix(device_t dev, device_t child, int count, 38319304Speter const u_int *vectors) 38419304Speter{ 38519304Speter struct vga_pci_softc *sc; 386254225Speter 38719304Speter sc = device_get_softc(dev); 38819304Speter if (sc->vga_msi_child != child) 38919304Speter return (ENXIO); 39019304Speter return (pci_remap_msix(dev, count, vectors)); 39119304Speter} 39219304Speter 39319304Speterstatic int 39419304Spetervga_pci_release_msi(device_t dev, device_t child) 39519304Speter{ 39619304Speter struct vga_pci_softc *sc; 39719304Speter int error; 398254225Speter 39919304Speter sc = device_get_softc(dev); 40019304Speter if (sc->vga_msi_child != child) 40119304Speter return (ENXIO); 40219304Speter error = pci_release_msi(dev); 40319304Speter if (error == 0) 40419304Speter sc->vga_msi_child = NULL; 40519304Speter return (error); 40619304Speter} 40719304Speter 408254225Speterstatic int 40919304Spetervga_pci_msi_count(device_t dev, device_t child) 41019304Speter{ 41119304Speter 41219304Speter return (pci_msi_count(dev)); 41319304Speter} 41419304Speter 41519304Speterstatic int 41619304Spetervga_pci_msix_count(device_t dev, device_t child) 41719304Speter{ 41819304Speter 41919304Speter return (pci_msix_count(dev)); 42019304Speter} 42119304Speter 42219304Speterstatic bus_dma_tag_t 42319304Spetervga_pci_get_dma_tag(device_t bus, device_t child) 42419304Speter{ 42519304Speter 42619304Speter return (bus_get_dma_tag(bus)); 427254225Speter} 42819304Speter 42919304Speterstatic device_method_t vga_pci_methods[] = { 430254225Speter /* Device interface */ 43119304Speter DEVMETHOD(device_probe, vga_pci_probe), 43219304Speter DEVMETHOD(device_attach, vga_pci_attach), 43319304Speter DEVMETHOD(device_shutdown, bus_generic_shutdown), 43419304Speter DEVMETHOD(device_suspend, vga_pci_suspend), 43519304Speter DEVMETHOD(device_resume, vga_pci_resume), 43619304Speter 43719304Speter /* Bus interface */ 43819304Speter DEVMETHOD(bus_read_ivar, vga_pci_read_ivar), 43919304Speter DEVMETHOD(bus_write_ivar, vga_pci_write_ivar), 44019304Speter DEVMETHOD(bus_setup_intr, vga_pci_setup_intr), 44119304Speter DEVMETHOD(bus_teardown_intr, vga_pci_teardown_intr), 44219304Speter DEVMETHOD(bus_alloc_resource, vga_pci_alloc_resource), 44319304Speter DEVMETHOD(bus_release_resource, vga_pci_release_resource), 44419304Speter DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 44519304Speter DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 44619304Speter DEVMETHOD(bus_get_dma_tag, vga_pci_get_dma_tag), 44719304Speter 44819304Speter /* PCI interface */ 449254225Speter DEVMETHOD(pci_read_config, vga_pci_read_config), 45019304Speter DEVMETHOD(pci_write_config, vga_pci_write_config), 45119304Speter DEVMETHOD(pci_enable_busmaster, vga_pci_enable_busmaster), 45219304Speter DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster), 45319304Speter DEVMETHOD(pci_enable_io, vga_pci_enable_io), 45419304Speter DEVMETHOD(pci_disable_io, vga_pci_disable_io), 45519304Speter DEVMETHOD(pci_get_vpd_ident, vga_pci_get_vpd_ident), 45619304Speter DEVMETHOD(pci_get_vpd_readonly, vga_pci_get_vpd_readonly), 45719304Speter DEVMETHOD(pci_get_powerstate, vga_pci_get_powerstate), 45819304Speter DEVMETHOD(pci_set_powerstate, vga_pci_set_powerstate), 45919304Speter DEVMETHOD(pci_assign_interrupt, vga_pci_assign_interrupt), 46019304Speter DEVMETHOD(pci_find_cap, vga_pci_find_cap), 46119304Speter DEVMETHOD(pci_find_extcap, vga_pci_find_extcap), 46219304Speter DEVMETHOD(pci_find_htcap, vga_pci_find_htcap), 46319304Speter DEVMETHOD(pci_alloc_msi, vga_pci_alloc_msi), 46419304Speter DEVMETHOD(pci_alloc_msix, vga_pci_alloc_msix), 46519304Speter DEVMETHOD(pci_remap_msix, vga_pci_remap_msix), 46619304Speter DEVMETHOD(pci_release_msi, vga_pci_release_msi), 46719304Speter DEVMETHOD(pci_msi_count, vga_pci_msi_count), 46819304Speter DEVMETHOD(pci_msix_count, vga_pci_msix_count), 46919304Speter 47019304Speter { 0, 0 } 47119304Speter}; 47219304Speter 47319304Speterstatic driver_t vga_pci_driver = { 47419304Speter "vgapci", 47519304Speter vga_pci_methods, 47619304Speter sizeof(struct vga_pci_softc), 47719304Speter}; 478254225Speter 47919304Speterstatic devclass_t vga_devclass; 48019304Speter 48119304SpeterDRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0); 48219304Speter