xref: /openbsd-src/sys/dev/pci/vga_pci.c (revision 9b9d2a55a62c8e82206c25f94fcc7f4e2765250e)
1 /* $OpenBSD: vga_pci.c,v 1.86 2015/08/20 04:41:46 mlarkin Exp $ */
2 /* $NetBSD: vga_pci.c,v 1.3 1998/06/08 06:55:58 thorpej Exp $ */
3 
4 /*
5  * Copyright (c) 2001 Wasabi Systems, Inc.
6  * All rights reserved.
7  *
8  * Written by Frank van der Linden for Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed for the NetBSD Project by
21  *	Wasabi Systems, Inc.
22  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23  *    or promote products derived from this software without specific prior
24  *    written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /*
39  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
40  * All rights reserved.
41  *
42  * Author: Chris G. Demetriou
43  *
44  * Permission to use, copy, modify and distribute this software and
45  * its documentation is hereby granted, provided that both the copyright
46  * notice and this permission notice appear in all copies of the
47  * software, derivative works or modified versions, and any portions
48  * thereof, and that both notices appear in supporting documentation.
49  *
50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53  *
54  * Carnegie Mellon requests users of this software to return to
55  *
56  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57  *  School of Computer Science
58  *  Carnegie Mellon University
59  *  Pittsburgh PA 15213-3890
60  *
61  * any improvements or extensions that they make and grant Carnegie the
62  * rights to redistribute these changes.
63  */
64 
65 #include "vga.h"
66 #include "drm.h"
67 #if defined(__i386__) || defined(__amd64__)
68 #include "acpi.h"
69 #endif
70 
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/device.h>
75 #include <sys/malloc.h>
76 #include <sys/rwlock.h>
77 
78 #include <machine/bus.h>
79 
80 #include <dev/pci/pcireg.h>
81 #include <dev/pci/pcivar.h>
82 #include <dev/pci/pcidevs.h>
83 
84 #include <dev/ic/mc6845reg.h>
85 #include <dev/ic/pcdisplayvar.h>
86 #include <dev/ic/vgareg.h>
87 #include <dev/pci/vga_pcivar.h>
88 
89 #include <dev/wscons/wsconsio.h>
90 #include <dev/wscons/wsdisplayvar.h>
91 #include <dev/ic/vgavar.h>
92 
93 #ifdef X86EMU
94 #include <machine/vga_post.h>
95 #endif
96 
97 #include "intagp.h"
98 
99 int	vga_pci_match(struct device *, void *, void *);
100 void	vga_pci_attach(struct device *, struct device *, void *);
101 int	vga_pci_activate(struct device *, int);
102 paddr_t	vga_pci_mmap(void* v, off_t off, int prot);
103 
104 #if NINTAGP > 0
105 int	intagpsubmatch(struct device *, void *, void *);
106 int	intagp_print(void *, const char *);
107 #endif
108 
109 #if !defined(SMALL_KERNEL) && NACPI > 0
110 void	vga_save_state(struct vga_pci_softc *);
111 void	vga_restore_state(struct vga_pci_softc *);
112 #endif
113 
114 /*
115  * Function pointers for wsconsctl parameter handling.
116  * XXX These should be per-softc, but right now we only attach
117  * XXX a single vga@pci instance, so this will do.
118  */
119 int	(*ws_get_param)(struct wsdisplay_param *);
120 int	(*ws_set_param)(struct wsdisplay_param *);
121 
122 
123 struct cfattach vga_pci_ca = {
124 	sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach,
125 	NULL, vga_pci_activate
126 };
127 
128 #if !defined(SMALL_KERNEL) && NACPI > 0
129 int vga_pci_do_post;
130 
131 struct vga_device_description {
132 	u_int16_t	rval[4];
133 	u_int16_t	rmask[4];
134 	char		vga_pci_post;
135 };
136 
137 static const struct vga_device_description vga_devs[] = {
138 	/*
139 	 * Header description:
140 	 *
141 	 * First entry is a list of the pci video information in the following
142 	 * order: VENDOR, PRODUCT, SUBVENDOR, SUBPRODUCT
143 	 *
144 	 * The next entry is a list of corresponding masks.
145 	 *
146 	 * Finally the last value indicates if we should repost via
147 	 * vga_pci (i.e. the x86emulator) * bios.
148 	 */
149 	{	/* All machines with GMA500/Poulsbo */
150 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15W_IGD,
151 	    	0x0000, 0x0000 },
152 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1
153 	},
154 	{	/* All machines with GMA500/Poulsbo */
155 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15L_IGD,
156 	    	0x0000, 0x0000 },
157 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1
158 	},
159 	{	/* All machines with GMA600/Oaktrail, 0x4100:4107 */
160 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GMA600_0,
161 	    	0x0000, 0x0000 },
162 	    {	0xffff, 0xfff8, 0x0000, 0x0000 }, 1
163 	},
164 	{	/* All machines with GMA600/Oaktrail, 0x4108 */
165 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GMA600_8,
166 	    	0x0000, 0x0000 },
167 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1
168 	},
169 	{	/* All machines with Medfield, 0x0130:0x0137 */
170 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MDFLD_IGD_0,
171 	    	0x0000, 0x0000 },
172 	    {	0xffff, 0xfff8, 0x0000, 0x0000 }, 1
173 	},
174 	{	/* All machines with GMA36x0/Cedartrail, 0x0be0:0x0bef */
175 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GMA3600_0,
176 	    	0x0000, 0x0000 },
177 	    {	0xffff, 0xfff0, 0x0000, 0x0000 }, 1
178 	},
179 };
180 #endif
181 
182 int
183 vga_pci_match(struct device *parent, void *match, void *aux)
184 {
185 	struct pci_attach_args *pa = aux;
186 
187 	if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0)
188 		return (0);
189 
190 	/* check whether it is disabled by firmware */
191 	if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG)
192 	    & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
193 	    != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
194 		return (0);
195 
196 	/* If it's the console, we have a winner! */
197 	if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA))
198 		return (1);
199 
200 	/*
201 	 * If we might match, make sure that the card actually looks OK.
202 	 */
203 	if (!vga_common_probe(pa->pa_iot, pa->pa_memt))
204 		return (0);
205 
206 	return (1);
207 }
208 
209 void
210 vga_pci_attach(struct device *parent, struct device *self, void *aux)
211 {
212 	struct pci_attach_args *pa = aux;
213 	pcireg_t reg;
214 	struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
215 #if !defined(SMALL_KERNEL) && NACPI > 0
216 	int prod, vend, subid, subprod, subvend, i;
217 #endif
218 
219 	/*
220 	 * Enable bus master; X might need this for accelerated graphics.
221 	 */
222 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
223 	reg |= PCI_COMMAND_MASTER_ENABLE;
224 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
225 
226 	sc->sc_type = WSDISPLAY_TYPE_PCIVGA;
227 
228 	printf("\n");
229 
230 	vga_pci_bar_init(sc, pa);
231 
232 #if !defined(SMALL_KERNEL) && NACPI > 0
233 
234 #ifdef X86EMU
235 	if ((sc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device,
236 	    pa->pa_function)) == NULL)
237 		printf("couldn't set up vga POST handler\n");
238 #endif
239 
240 	vend = PCI_VENDOR(pa->pa_id);
241 	prod = PCI_PRODUCT(pa->pa_id);
242 	subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
243 	subvend = PCI_VENDOR(subid);
244 	subprod = PCI_PRODUCT(subid);
245 
246 	for (i = 0; i < nitems(vga_devs); i++)
247 		if ((vend & vga_devs[i].rmask[0]) == vga_devs[i].rval[0] &&
248 		    (prod & vga_devs[i].rmask[1]) == vga_devs[i].rval[1] &&
249 		    (subvend & vga_devs[i].rmask[2]) == vga_devs[i].rval[2] &&
250 		    (subprod & vga_devs[i].rmask[3]) == vga_devs[i].rval[3]) {
251 			vga_pci_do_post = vga_devs[i].vga_pci_post;
252 			break;
253 		}
254 #endif
255 
256 #ifdef RAMDISK_HOOKS
257 	if (vga_aperture_needed(pa))
258 		printf("%s: aperture needed\n", sc->sc_dev.dv_xname);
259 #endif
260 
261 #if NINTAGP > 0
262 	/*
263 	 * attach intagp here instead of pchb so it can share mappings
264 	 * with the DRM.
265 	 */
266 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) {
267 		config_found_sm(self, aux, intagp_print, intagpsubmatch);
268 
269 	}
270 #endif
271 
272 #if NDRM > 0
273 	config_found_sm(self, aux, NULL, vga_drmsubmatch);
274 #endif
275 
276 	sc->sc_vc = vga_common_attach(self, pa->pa_iot, pa->pa_memt,
277 	    sc->sc_type);
278 }
279 
280 int
281 vga_pci_activate(struct device *self, int act)
282 {
283 	int rv = 0;
284 
285 #if !defined(SMALL_KERNEL) && NACPI > 0
286 	struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
287 #endif
288 
289 	switch (act) {
290 	case DVACT_SUSPEND:
291 		rv = config_activate_children(self, act);
292 #if !defined(SMALL_KERNEL) && NACPI > 0
293 		/*
294 		 * Save the common vga state. This should theoretically only
295 		 * be necessary if we intend to POST, but it is preferrable
296 		 * to do it unconditionnaly, as many systems do not restore
297 		 * this state correctly upon resume.
298 		 */
299 		vga_save_state(sc);
300 #endif
301 		break;
302 	case DVACT_RESUME:
303 #if !defined(SMALL_KERNEL) && NACPI > 0
304 #if defined (X86EMU)
305 		if (vga_pci_do_post)
306 			vga_post_call(sc->sc_posth);
307 #endif
308 		vga_restore_state(sc);
309 #endif
310 		rv = config_activate_children(self, act);
311 		break;
312 	default:
313 		rv = config_activate_children(self, act);
314 		break;
315 	}
316 
317 	return (rv);
318 }
319 
320 #if NINTAGP > 0
321 int
322 intagpsubmatch(struct device *parent, void *match, void *aux)
323 {
324 	extern struct cfdriver intagp_cd;
325 	struct cfdata *cf = match;
326 
327 	/* only allow intagp to attach */
328 	if (cf->cf_driver == &intagp_cd)
329 		return ((*cf->cf_attach->ca_match)(parent, match, aux));
330 	return (0);
331 }
332 
333 int
334 intagp_print(void *vaa, const char *pnp)
335 {
336 	if (pnp)
337 		printf("intagp at %s", pnp);
338 	return (UNCONF);
339 }
340 #endif
341 
342 paddr_t
343 vga_pci_mmap(void *v, off_t off, int prot)
344 {
345 	return -1;
346 }
347 
348 int
349 vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt,
350     pci_chipset_tag_t pc, int bus, int device, int function)
351 {
352 	return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0));
353 }
354 
355 int
356 vga_pci_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb)
357 {
358 	int error = 0;
359 
360 	switch (cmd) {
361 	case WSDISPLAYIO_GETPARAM:
362 		if (ws_get_param != NULL)
363 			return (*ws_get_param)((struct wsdisplay_param *)addr);
364 		else
365 			error = ENOTTY;
366 		break;
367 	case WSDISPLAYIO_SETPARAM:
368 		if (ws_set_param != NULL)
369 			return (*ws_set_param)((struct wsdisplay_param *)addr);
370 		else
371 			error = ENOTTY;
372 		break;
373 	default:
374 		error = ENOTTY;
375 	}
376 
377 	return (error);
378 }
379 
380 #if !defined(SMALL_KERNEL) && NACPI > 0
381 void
382 vga_save_state(struct vga_pci_softc *sc)
383 {
384 	struct vga_config *vc = sc->sc_vc;
385 	struct vga_handle *vh;
386 	struct vgascreen *scr;
387 	size_t i;
388 	char *buf;
389 
390 	if (vc == NULL)
391 		return;
392 
393 	vh = &vc->hdl;
394 
395 	/*
396 	 * Save sequencer registers
397 	 */
398 	vga_ts_write(vh, syncreset, 1);	/* stop sequencer */
399 	buf = (char *)&sc->sc_save_ts;
400 	*buf++ = 0;
401 	for (i = 1; i < sizeof(sc->sc_save_ts); i++)
402 		*buf++ = _vga_ts_read(vh, i);
403 	vga_ts_write(vh, syncreset, 3);	/* start sequencer */
404 	/* pretend screen is not blanked */
405 	sc->sc_save_ts.mode &= ~0x20;
406 	sc->sc_save_ts.mode |= 0x80;
407 
408 	/*
409 	 * Save CRTC registers
410 	 */
411 	buf = (char *)&sc->sc_save_crtc;
412 	for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
413 		*buf++ = _pcdisplay_6845_read(&vh->vh_ph, i);
414 
415 	/*
416 	 * Save ATC registers
417 	 */
418 	buf = (char *)&sc->sc_save_atc;
419 	for (i = 0; i < sizeof(sc->sc_save_atc); i++)
420 		*buf++ = _vga_attr_read(vh, i);
421 
422 	/*
423 	 * Save GDC registers
424 	 */
425 	buf = (char *)&sc->sc_save_gdc;
426 	for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
427 		*buf++ = _vga_gdc_read(vh, i);
428 
429 	vga_save_palette(vc);
430 
431 	/* XXX should also save font data */
432 
433 	/*
434 	 * Save current screen contents if we have backing store for it,
435 	 * and intend to POST on resume.
436 	 * XXX Since we don't allocate backing store unless the second VT is
437 	 * XXX created, we could theoretically have no backing store available
438 	 * XXX at this point.
439 	 */
440 	if (vga_pci_do_post) {
441 		scr = vc->active;
442 		if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
443 			bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
444 			    scr->pcs.dispoffset, scr->pcs.mem,
445 			    scr->pcs.type->ncols * scr->pcs.type->nrows);
446 	}
447 }
448 
449 void
450 vga_restore_state(struct vga_pci_softc *sc)
451 {
452 	struct vga_config *vc = sc->sc_vc;
453 	struct vga_handle *vh;
454 	struct vgascreen *scr;
455 	size_t i;
456 	char *buf;
457 
458 	if (vc == NULL)
459 		return;
460 
461 	vh = &vc->hdl;
462 
463 	/*
464 	 * Restore sequencer registers
465 	 */
466 	vga_ts_write(vh, syncreset, 1);	/* stop sequencer */
467 	buf = (char *)&sc->sc_save_ts + 1;
468 	for (i = 1; i < sizeof(sc->sc_save_ts); i++)
469 		_vga_ts_write(vh, i, *buf++);
470 	vga_ts_write(vh, syncreset, 3);	/* start sequencer */
471 
472 	/*
473 	 * Restore CRTC registers
474 	 */
475 	/* unprotect registers 00-07 */
476 	vga_6845_write(vh, vsynce,
477 	    vga_6845_read(vh, vsynce) & ~0x80);
478 	buf = (char *)&sc->sc_save_crtc;
479 	for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
480 		_pcdisplay_6845_write(&vh->vh_ph, i, *buf++);
481 
482 	/*
483 	 * Restore ATC registers
484 	 */
485 	buf = (char *)&sc->sc_save_atc;
486 	for (i = 0; i < sizeof(sc->sc_save_atc); i++)
487 		_vga_attr_write(vh, i, *buf++);
488 
489 	/*
490 	 * Restore GDC registers
491 	 */
492 	buf = (char *)&sc->sc_save_gdc;
493 	for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
494 		_vga_gdc_write(vh, i, *buf++);
495 
496 	vga_restore_fonts(vc);
497 	vga_restore_palette(vc);
498 
499 	/*
500 	 * Restore current screen contents if we have backing store for it,
501 	 * and have POSTed on resume.
502 	 * XXX Since we don't allocate backing store unless the second VT is
503 	 * XXX created, we could theoretically have no backing store available
504 	 * XXX at this point.
505 	 */
506 	if (vga_pci_do_post) {
507 		scr = vc->active;
508 		if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
509 			bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
510 			    scr->pcs.dispoffset, scr->pcs.mem,
511 			    scr->pcs.type->ncols * scr->pcs.type->nrows);
512 	}
513 }
514 #endif
515