xref: /netbsd-src/sys/dev/pci/vga_pci.c (revision 46f5119e40af2e51998f686b2fdcc76b5488f7f3)
1 /*	$NetBSD: vga_pci.c,v 1.53 2011/01/22 15:14:28 cegger Exp $	*/
2 
3 /*
4  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
5  * All rights reserved.
6  *
7  * Author: Chris G. Demetriou
8  *
9  * Permission to use, copy, modify and distribute this software and
10  * its documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie the
27  * rights to redistribute these changes.
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: vga_pci.c,v 1.53 2011/01/22 15:14:28 cegger Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/device.h>
37 #include <sys/malloc.h>
38 
39 #include <dev/pci/pcireg.h>
40 #include <dev/pci/pcivar.h>
41 #include <dev/pci/pcidevs.h>
42 #include <dev/pci/pciio.h>
43 
44 #include <dev/ic/mc6845reg.h>
45 #include <dev/ic/pcdisplayvar.h>
46 #include <dev/ic/vgareg.h>
47 #include <dev/ic/vgavar.h>
48 #include <dev/pci/vga_pcivar.h>
49 
50 #include <dev/isa/isareg.h>	/* For legacy VGA address ranges */
51 
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wsdisplayvar.h>
54 #include <dev/pci/wsdisplay_pci.h>
55 
56 #include "opt_vga.h"
57 
58 #ifdef VGA_POST
59 #  if defined(__i386__) || defined(__amd64__)
60 #    include "acpica.h"
61 #  endif
62 #include <x86/vga_post.h>
63 #endif
64 
65 #define	NBARS		6	/* number of PCI BARs */
66 
67 struct vga_bar {
68 	bus_addr_t vb_base;
69 	bus_size_t vb_size;
70 	pcireg_t vb_type;
71 	int vb_flags;
72 };
73 
74 struct vga_pci_softc {
75 	struct vga_softc sc_vga;
76 
77 	pci_chipset_tag_t sc_pc;
78 	pcitag_t sc_pcitag;
79 
80 	struct vga_bar sc_bars[NBARS];
81 	struct vga_bar sc_rom;
82 
83 #ifdef VGA_POST
84 	struct vga_post *sc_posth;
85 #endif
86 
87 	struct pci_attach_args sc_paa;
88 };
89 
90 static int	vga_pci_match(device_t, cfdata_t, void *);
91 static void	vga_pci_attach(device_t, device_t, void *);
92 static int	vga_pci_rescan(device_t, const char *, const int *);
93 static int	vga_pci_lookup_quirks(struct pci_attach_args *);
94 static bool	vga_pci_resume(device_t dv, const pmf_qual_t *);
95 
96 CFATTACH_DECL2_NEW(vga_pci, sizeof(struct vga_pci_softc),
97     vga_pci_match, vga_pci_attach, NULL, NULL, vga_pci_rescan, NULL);
98 
99 static int	vga_pci_ioctl(void *, u_long, void *, int, struct lwp *);
100 static paddr_t	vga_pci_mmap(void *, off_t, int);
101 
102 static const struct vga_funcs vga_pci_funcs = {
103 	vga_pci_ioctl,
104 	vga_pci_mmap,
105 };
106 
107 static const struct {
108 	int id;
109 	int quirks;
110 } vga_pci_quirks[] = {
111 	{PCI_ID_CODE(PCI_VENDOR_SILMOTION, PCI_PRODUCT_SILMOTION_SM712),
112 	 VGA_QUIRK_NOFASTSCROLL},
113 	{PCI_ID_CODE(PCI_VENDOR_CYRIX, PCI_PRODUCT_CYRIX_CX5530_VIDEO),
114 	 VGA_QUIRK_NOFASTSCROLL},
115 };
116 
117 static const struct {
118 	int vid;
119 	int quirks;
120 } vga_pci_vquirks[] = {
121 	{PCI_VENDOR_ATI, VGA_QUIRK_ONEFONT},
122 };
123 
124 static int
125 vga_pci_lookup_quirks(struct pci_attach_args *pa)
126 {
127 	int i;
128 
129 	for (i = 0; i < sizeof(vga_pci_quirks) / sizeof (vga_pci_quirks[0]);
130 	     i++) {
131 		if (vga_pci_quirks[i].id == pa->pa_id)
132 			return (vga_pci_quirks[i].quirks);
133 	}
134 	for (i = 0; i < sizeof(vga_pci_vquirks) / sizeof (vga_pci_vquirks[0]);
135 	     i++) {
136 		if (vga_pci_vquirks[i].vid == PCI_VENDOR(pa->pa_id))
137 			return (vga_pci_vquirks[i].quirks);
138 	}
139 	return (0);
140 }
141 
142 static int
143 vga_pci_match(device_t parent, cfdata_t match, void *aux)
144 {
145 	struct pci_attach_args *pa = aux;
146 	int potential;
147 
148 	potential = 0;
149 
150 	/*
151 	 * If it's prehistoric/vga or display/vga, we might match.
152 	 * For the console device, this is just a sanity check.
153 	 */
154 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_PREHISTORIC &&
155 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_PREHISTORIC_VGA)
156 		potential = 1;
157 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY &&
158 	     PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA)
159 		potential = 1;
160 
161 	if (!potential)
162 		return (0);
163 
164 	/* check whether it is disabled by firmware */
165 	if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG)
166 	    & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
167 	    != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
168 		return (0);
169 
170 	/* If it's the console, we have a winner! */
171 	if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA))
172 		return (1);
173 
174 	/*
175 	 * If we might match, make sure that the card actually looks OK.
176 	 */
177 	if (!vga_common_probe(pa->pa_iot, pa->pa_memt))
178 		return (0);
179 
180 	return (1);
181 }
182 
183 static void
184 vga_pci_attach(device_t parent, device_t self, void *aux)
185 {
186 	struct vga_pci_softc *psc = device_private(self);
187 	struct vga_softc *sc = &psc->sc_vga;
188 	struct pci_attach_args *pa = aux;
189 	char devinfo[256];
190 	int bar, reg;
191 
192 	sc->sc_dev = self;
193 	psc->sc_pc = pa->pa_pc;
194 	psc->sc_pcitag = pa->pa_tag;
195 	psc->sc_paa = *pa;
196 
197 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
198 	aprint_naive("\n");
199 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
200 	    PCI_REVISION(pa->pa_class));
201 
202 	/*
203 	 * Gather info about all the BARs.  These are used to allow
204 	 * the X server to map the VGA device.
205 	 */
206 	for (bar = 0; bar < NBARS; bar++) {
207 		reg = PCI_MAPREG_START + (bar * 4);
208 		if (!pci_mapreg_probe(psc->sc_pc, psc->sc_pcitag, reg,
209 				      &psc->sc_bars[bar].vb_type)) {
210 			/* there is no valid mapping register */
211 			continue;
212 		}
213 		if (PCI_MAPREG_TYPE(psc->sc_bars[bar].vb_type) ==
214 		    PCI_MAPREG_TYPE_IO) {
215 			/* Don't bother fetching I/O BARs. */
216 			continue;
217 		}
218 #ifndef __LP64__
219 		if (PCI_MAPREG_MEM_TYPE(psc->sc_bars[bar].vb_type) ==
220 		    PCI_MAPREG_MEM_TYPE_64BIT) {
221 			/* XXX */
222 			aprint_error_dev(self,
223 			    "WARNING: ignoring 64-bit BAR @ 0x%02x\n", reg);
224 			bar++;
225 			continue;
226 		}
227 #endif
228 		if (pci_mapreg_info(psc->sc_pc, psc->sc_pcitag, reg,
229 		     psc->sc_bars[bar].vb_type,
230 		     &psc->sc_bars[bar].vb_base,
231 		     &psc->sc_bars[bar].vb_size,
232 		     &psc->sc_bars[bar].vb_flags))
233 			aprint_error_dev(self,
234 			    "WARNING: strange BAR @ 0x%02x\n", reg);
235 	}
236 
237 	/* XXX Expansion ROM? */
238 
239 	vga_common_attach(sc, pa->pa_iot, pa->pa_memt, WSDISPLAY_TYPE_PCIVGA,
240 			  vga_pci_lookup_quirks(pa), &vga_pci_funcs);
241 
242 #ifdef VGA_POST
243 	psc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device, pa->pa_function);
244 	if (psc->sc_posth == NULL)
245 		aprint_error_dev(self, "WARNING: could not prepare POST handler\n");
246 #endif
247 
248 	/*
249 	 * XXX Do not use the generic PCI framework for now as
250 	 * XXX it would power down the device when the console
251 	 * XXX is still using it.
252 	 */
253 	if (!pmf_device_register(self, NULL, vga_pci_resume))
254 		aprint_error_dev(self, "couldn't establish power handler\n");
255 	config_found_ia(self, "drm", aux, vga_drm_print);
256 }
257 
258 static int
259 vga_pci_rescan(device_t self, const char *ifattr, const int *locators)
260 {
261 	struct vga_pci_softc *psc = device_private(self);
262 
263 	config_found_ia(self, "drm", &psc->sc_paa, vga_drm_print);
264 
265 	return 0;
266 }
267 
268 static bool
269 vga_pci_resume(device_t dv, const pmf_qual_t *qual)
270 {
271 #if defined(VGA_POST) && NACPICA > 0
272 	extern int acpi_md_vbios_reset;
273 #endif
274 	struct vga_pci_softc *sc = device_private(dv);
275 
276 	vga_resume(&sc->sc_vga);
277 
278 #if defined(VGA_POST) && NACPICA > 0
279 	if (sc->sc_posth != NULL && acpi_md_vbios_reset == 2)
280 		vga_post_call(sc->sc_posth);
281 #endif
282 
283 	return true;
284 }
285 
286 int
287 vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt,
288     pci_chipset_tag_t pc, int bus, int device,
289     int function)
290 {
291 
292 	return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0));
293 }
294 
295 int
296 vga_drm_print(void *aux, const char *pnp)
297 {
298 	if (pnp)
299 		aprint_normal("drm at %s", pnp);
300 	return (UNCONF);
301 }
302 
303 
304 static int
305 vga_pci_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
306 {
307 	struct vga_config *vc = v;
308 	struct vga_pci_softc *psc = (void *) vc->softc;
309 
310 	switch (cmd) {
311 	/* PCI config read/write passthrough. */
312 	case PCI_IOC_CFGREAD:
313 	case PCI_IOC_CFGWRITE:
314 		return pci_devioctl(psc->sc_pc, psc->sc_pcitag,
315 		    cmd, data, flag, l);
316 
317 	case WSDISPLAYIO_GET_BUSID:
318 		return wsdisplayio_busid_pci(vc->softc->sc_dev,
319 		    psc->sc_pc, psc->sc_pcitag, data);
320 
321 	default:
322 		return EPASSTHROUGH;
323 	}
324 }
325 
326 static paddr_t
327 vga_pci_mmap(void *v, off_t offset, int prot)
328 {
329 	struct vga_config *vc = v;
330 	struct vga_pci_softc *psc = (void *) vc->softc;
331 	struct vga_bar *vb;
332 	int bar;
333 
334 	for (bar = 0; bar < NBARS; bar++) {
335 		vb = &psc->sc_bars[bar];
336 		if (vb->vb_size == 0)
337 			continue;
338 		if (offset >= vb->vb_base &&
339 		    offset < (vb->vb_base + vb->vb_size)) {
340 			/* XXX This the right thing to do with flags? */
341 			return (bus_space_mmap(vc->hdl.vh_memt, vb->vb_base,
342 			    (offset - vb->vb_base), prot, vb->vb_flags));
343 		}
344 	}
345 
346 	/* XXX Expansion ROM? */
347 
348 	/*
349 	 * Allow mmap access to the legacy ISA hole.  This is where
350 	 * the legacy video BIOS will be located, and also where
351 	 * the legacy VGA display buffer is located.
352 	 *
353 	 * XXX Security implications, here?
354 	 */
355 	if (offset >= IOM_BEGIN && offset < IOM_END)
356 		return (bus_space_mmap(vc->hdl.vh_memt, IOM_BEGIN,
357 		    (offset - IOM_BEGIN), prot, 0));
358 
359 #ifdef PCI_MAGIC_IO_RANGE
360 	/* allow to map our IO space on non-x86 machines */
361 	if ((offset >= PCI_MAGIC_IO_RANGE) &&
362 	    (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
363 		return bus_space_mmap(vc->hdl.vh_iot,
364 		    offset - PCI_MAGIC_IO_RANGE,
365 		    0, prot, BUS_SPACE_MAP_LINEAR);
366 	}
367 #endif
368 
369 	/* Range not found. */
370 	return (-1);
371 }
372