xref: /openbsd-src/sys/dev/pci/vga_pci_common.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
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