1 /* 2 * Copyright (c) 2008 Owain G. Ainsworth <oga@nicotinebsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "drm.h" 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/malloc.h> 22 23 #include <machine/bus.h> 24 25 #include <dev/pci/pcireg.h> 26 #include <dev/pci/pcivar.h> 27 #include <dev/pci/vga_pcivar.h> 28 29 30 #if NDRM > 0 31 int 32 vga_drmsubmatch(struct device *parent, void *match, void *aux) 33 { 34 struct cfdata *cf = match; 35 struct cfdriver *cd; 36 size_t len = 0; 37 char *sm; 38 39 cd = cf->cf_driver; 40 41 /* is this a *drm device? */ 42 len = strlen(cd->cd_name); 43 sm = cd->cd_name + len - 3; 44 if (strncmp(sm, "drm", 3) == 0) 45 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 46 47 return (0); 48 } 49 #endif 50 51 /* 52 * Prepare dev->bars to be used for information. we do this at startup 53 * so we can do the whole array at once, dealing with 64-bit BARs correctly. 54 */ 55 void 56 vga_pci_bar_init(struct vga_pci_softc *dev, struct pci_attach_args *pa) 57 { 58 pcireg_t type; 59 int addr = PCI_MAPREG_START, i = 0; 60 memcpy(&dev->pa, pa, sizeof(dev->pa)); 61 62 while (i < VGA_PCI_MAX_BARS) { 63 dev->bars[i] = malloc(sizeof((*dev->bars[i])), M_DEVBUF, 64 M_NOWAIT | M_ZERO); 65 if (dev->bars[i] == NULL) { 66 return; 67 } 68 69 dev->bars[i]->addr = addr; 70 71 type = dev->bars[i]->maptype = pci_mapreg_type(pa->pa_pc, 72 pa->pa_tag, addr); 73 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, addr, 74 dev->bars[i]->maptype, &dev->bars[i]->base, 75 &dev->bars[i]->maxsize, &dev->bars[i]->flags) != 0) { 76 free(dev->bars[i], M_DEVBUF); 77 dev->bars[i] = NULL; 78 } 79 80 if (type == PCI_MAPREG_MEM_TYPE_64BIT) { 81 addr += 8; 82 i += 2; 83 } else { 84 addr += 4; 85 i++; 86 } 87 } 88 } 89 90 /* 91 * Get the vga_pci_bar struct for the address in question. returns NULL if 92 * invalid BAR is passed. 93 */ 94 struct vga_pci_bar* 95 vga_pci_bar_info(struct vga_pci_softc *dev, int no) 96 { 97 if (dev == NULL || no >= VGA_PCI_MAX_BARS) 98 return (NULL); 99 return (dev->bars[no]); 100 } 101 102 /* 103 * map the BAR in question, returning the vga_pci_bar struct in case any more 104 * processing needs to be done. Returns NULL on failure. Can be called multiple 105 * times. 106 */ 107 struct vga_pci_bar* 108 vga_pci_bar_map(struct vga_pci_softc *dev, int addr, bus_size_t size, 109 int busflags) 110 { 111 struct vga_pci_bar *bar = NULL; 112 int i; 113 114 if (dev == NULL) 115 return (NULL); 116 117 for (i = 0; i < VGA_PCI_MAX_BARS; i++) { 118 if (dev->bars[i] && dev->bars[i]->addr == addr) { 119 bar = dev->bars[i]; 120 break; 121 } 122 } 123 if (bar == NULL) { 124 printf("vga_pci_bar_map: given invalid address 0x%x\n", addr); 125 return (NULL); 126 } 127 128 if (bar->mapped == 0) { 129 if (pci_mapreg_map(&dev->pa, bar->addr, bar->maptype, 130 bar->flags | busflags, &bar->bst, &bar->bsh, NULL, 131 &bar->size, size)) { 132 printf("vga_pci_bar_map: can't map bar 0x%x\n", addr); 133 return (NULL); 134 } 135 } 136 137 bar->mapped++; 138 return (bar); 139 } 140 141 /* 142 * "unmap" the BAR referred to by argument. If more than one place has mapped it 143 * we just decrement the reference counter so nothing untoward happens. 144 */ 145 void 146 vga_pci_bar_unmap(struct vga_pci_bar *bar) 147 { 148 if (bar != NULL && bar->mapped != 0) { 149 if (--bar->mapped == 0) 150 bus_space_unmap(bar->bst, bar->bsh, bar->size); 151 } 152 } 153