xref: /openbsd-src/sys/dev/pci/vga_pci.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /* $OpenBSD: vga_pci.c,v 1.81 2014/07/28 15:00:27 jsg 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/pci/agpvar.h>
85 
86 #include <dev/ic/mc6845reg.h>
87 #include <dev/ic/pcdisplayvar.h>
88 #include <dev/ic/vgareg.h>
89 #include <dev/ic/vgavar.h>
90 #include <dev/pci/vga_pcivar.h>
91 
92 #include <dev/wscons/wsconsio.h>
93 #include <dev/wscons/wsdisplayvar.h>
94 
95 #ifdef X86EMU
96 #include <machine/vga_post.h>
97 #endif
98 
99 #ifdef VESAFB
100 #include <dev/vesa/vesabiosvar.h>
101 #endif
102 
103 #include "intagp.h"
104 
105 int	vga_pci_match(struct device *, void *, void *);
106 void	vga_pci_attach(struct device *, struct device *, void *);
107 int	vga_pci_activate(struct device *, int);
108 paddr_t	vga_pci_mmap(void* v, off_t off, int prot);
109 
110 #if NINTAGP > 0
111 int	intagpsubmatch(struct device *, void *, void *);
112 int	intagp_print(void *, const char *);
113 #endif
114 
115 #ifdef VESAFB
116 int	vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *);
117 int	vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *);
118 #endif
119 
120 #if !defined(SMALL_KERNEL) && NACPI > 0
121 void	vga_save_state(struct vga_pci_softc *);
122 void	vga_restore_state(struct vga_pci_softc *);
123 #endif
124 
125 /*
126  * Function pointers for wsconsctl parameter handling.
127  * XXX These should be per-softc, but right now we only attach
128  * XXX a single vga@pci instance, so this will do.
129  */
130 int	(*ws_get_param)(struct wsdisplay_param *);
131 int	(*ws_set_param)(struct wsdisplay_param *);
132 
133 
134 struct cfattach vga_pci_ca = {
135 	sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach,
136 	NULL, vga_pci_activate
137 };
138 
139 #if !defined(SMALL_KERNEL) && NACPI > 0
140 int vga_pci_do_post;
141 
142 struct vga_device_description {
143 	u_int16_t	rval[4];
144 	u_int16_t	rmask[4];
145 	char		vga_pci_post;
146 };
147 
148 static const struct vga_device_description vga_devs[] = {
149 	/*
150 	 * Header description:
151 	 *
152 	 * First entry is a list of the pci video information in the following
153 	 * order: VENDOR, PRODUCT, SUBVENDOR, SUBPRODUCT
154 	 *
155 	 * The next entry is a list of corresponding masks.
156 	 *
157 	 * Finally the last value indicates if we should repost via
158 	 * vga_pci (i.e. the x86emulator) * bios.
159 	 */
160 	{	/* All machines with Intel US15W (until more evidence) */
161 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15W_IGD,
162 	    	0x0000, 0x0000 },
163 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1
164 	},
165 	{	/* All machines with Intel US15L (until more evidence) */
166 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15L_IGD,
167 	    	0x0000, 0x0000 },
168 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1
169 	},
170 };
171 #endif
172 
173 int
174 vga_pci_match(struct device *parent, void *match, void *aux)
175 {
176 	struct pci_attach_args *pa = aux;
177 
178 	if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0)
179 		return (0);
180 
181 	/* check whether it is disabled by firmware */
182 	if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG)
183 	    & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
184 	    != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
185 		return (0);
186 
187 	/* If it's the console, we have a winner! */
188 	if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA))
189 		return (1);
190 
191 	/*
192 	 * If we might match, make sure that the card actually looks OK.
193 	 */
194 	if (!vga_common_probe(pa->pa_iot, pa->pa_memt))
195 		return (0);
196 
197 	return (1);
198 }
199 
200 void
201 vga_pci_attach(struct device *parent, struct device *self, void *aux)
202 {
203 	struct pci_attach_args *pa = aux;
204 	pcireg_t reg;
205 	struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
206 #if !defined(SMALL_KERNEL) && NACPI > 0
207 	int prod, vend, subid, subprod, subvend, i;
208 #endif
209 
210 	/*
211 	 * Enable bus master; X might need this for accelerated graphics.
212 	 */
213 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
214 	reg |= PCI_COMMAND_MASTER_ENABLE;
215 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
216 
217 	sc->sc_type = WSDISPLAY_TYPE_PCIVGA;
218 
219 #ifdef VESAFB
220 	if (vesabios_softc != NULL && vesabios_softc->sc_nmodes > 0) {
221 		sc->sc_textmode = vesafb_get_mode(sc);
222 		printf(", vesafb\n");
223 		sc->sc_vc = vga_extended_attach(self, pa->pa_iot, pa->pa_memt,
224 		    sc->sc_type, vga_pci_mmap);
225 		return;
226 	}
227 #endif
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 #ifdef VESAFB
346 	struct vga_config *vc = (struct vga_config *)v;
347 	struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc;
348 
349 	if (sc->sc_mode == WSDISPLAYIO_MODE_DUMBFB) {
350 		if (off < 0 || off > vesabios_softc->sc_size)
351 			return (-1);
352 		return (sc->sc_base + off);
353 	}
354 #endif
355 	return -1;
356 }
357 
358 int
359 vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt,
360     pci_chipset_tag_t pc, int bus, int device, int function)
361 {
362 	return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0));
363 }
364 
365 int
366 vga_pci_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb)
367 {
368 	int error = 0;
369 #ifdef VESAFB
370 	struct vga_config *vc = (struct vga_config *)v;
371 	struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc;
372 	struct wsdisplay_fbinfo *wdf;
373 	struct wsdisplay_gfx_mode *gfxmode;
374 	int mode;
375 #endif
376 
377 	switch (cmd) {
378 #ifdef VESAFB
379 	case WSDISPLAYIO_SMODE:
380 		mode = *(u_int *)addr;
381 		switch (mode) {
382 		case WSDISPLAYIO_MODE_EMUL:
383 			/* back to text mode */
384 			vesafb_set_mode(sc, sc->sc_textmode);
385 			sc->sc_mode = mode;
386 			break;
387 		case WSDISPLAYIO_MODE_DUMBFB:
388 			if (sc->sc_gfxmode == -1)
389 				return (-1);
390 			vesafb_set_mode(sc, sc->sc_gfxmode);
391 			sc->sc_mode = mode;
392 			break;
393 		default:
394 			error = -1;
395 		}
396 		break;
397 	case WSDISPLAYIO_GINFO:
398 		if (sc->sc_gfxmode == -1)
399 			return (-1);
400 		wdf = (void *)addr;
401 		wdf->height = sc->sc_height;
402 		wdf->width = sc->sc_width;
403 		wdf->depth = sc->sc_depth;
404 		wdf->cmsize = 256;
405 		break;
406 
407 	case WSDISPLAYIO_LINEBYTES:
408 		if (sc->sc_gfxmode == -1)
409 			return (-1);
410 		*(u_int *)addr = sc->sc_linebytes;
411 		break;
412 
413 	case WSDISPLAYIO_SVIDEO:
414 	case WSDISPLAYIO_GVIDEO:
415 		break;
416 	case WSDISPLAYIO_GETCMAP:
417 		if (sc->sc_depth == 8)
418 			error = vesafb_getcmap(sc,
419 			    (struct wsdisplay_cmap *)addr);
420 		break;
421 
422 	case WSDISPLAYIO_PUTCMAP:
423 		if (sc->sc_depth == 8)
424 			error = vesafb_putcmap(sc,
425 			    (struct wsdisplay_cmap *)addr);
426 		break;
427 
428 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
429 		*(int *)addr = vesafb_get_supported_depth(sc);
430 		break;
431 
432 	case WSDISPLAYIO_SETGFXMODE:
433 		gfxmode = (struct wsdisplay_gfx_mode *)addr;
434 		sc->sc_gfxmode = vesafb_find_mode(sc, gfxmode->width,
435 		    gfxmode->height, gfxmode->depth);
436 		if (sc->sc_gfxmode == -1)
437 			error = -1;
438 		break;
439 
440 #endif
441 	case WSDISPLAYIO_GETPARAM:
442 		if (ws_get_param != NULL)
443 			return (*ws_get_param)((struct wsdisplay_param *)addr);
444 		else
445 			error = ENOTTY;
446 		break;
447 	case WSDISPLAYIO_SETPARAM:
448 		if (ws_set_param != NULL)
449 			return (*ws_set_param)((struct wsdisplay_param *)addr);
450 		else
451 			error = ENOTTY;
452 		break;
453 	default:
454 		error = ENOTTY;
455 	}
456 
457 	return (error);
458 }
459 
460 #if !defined(SMALL_KERNEL) && NACPI > 0
461 void
462 vga_save_state(struct vga_pci_softc *sc)
463 {
464 	struct vga_config *vc = sc->sc_vc;
465 	struct vga_handle *vh;
466 	struct vgascreen *scr;
467 	size_t i;
468 	char *buf;
469 
470 	if (vc == NULL)
471 		return;
472 
473 	vh = &vc->hdl;
474 
475 	/*
476 	 * Save sequencer registers
477 	 */
478 	vga_ts_write(vh, syncreset, 1);	/* stop sequencer */
479 	buf = (char *)&sc->sc_save_ts;
480 	*buf++ = 0;
481 	for (i = 1; i < sizeof(sc->sc_save_ts); i++)
482 		*buf++ = _vga_ts_read(vh, i);
483 	vga_ts_write(vh, syncreset, 3);	/* start sequencer */
484 	/* pretend screen is not blanked */
485 	sc->sc_save_ts.mode &= ~0x20;
486 	sc->sc_save_ts.mode |= 0x80;
487 
488 	/*
489 	 * Save CRTC registers
490 	 */
491 	buf = (char *)&sc->sc_save_crtc;
492 	for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
493 		*buf++ = _pcdisplay_6845_read(&vh->vh_ph, i);
494 
495 	/*
496 	 * Save ATC registers
497 	 */
498 	buf = (char *)&sc->sc_save_atc;
499 	for (i = 0; i < sizeof(sc->sc_save_atc); i++)
500 		*buf++ = _vga_attr_read(vh, i);
501 
502 	/*
503 	 * Save GDC registers
504 	 */
505 	buf = (char *)&sc->sc_save_gdc;
506 	for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
507 		*buf++ = _vga_gdc_read(vh, i);
508 
509 	vga_save_palette(vc);
510 
511 	/* XXX should also save font data */
512 
513 	/*
514 	 * Save current screen contents if we have backing store for it,
515 	 * and intend to POST on resume.
516 	 * XXX Since we don't allocate backing store unless the second VT is
517 	 * XXX created, we could theoretically have no backing store available
518 	 * XXX at this point.
519 	 */
520 	if (vga_pci_do_post) {
521 		scr = vc->active;
522 		if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
523 			bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
524 			    scr->pcs.dispoffset, scr->pcs.mem,
525 			    scr->pcs.type->ncols * scr->pcs.type->nrows);
526 	}
527 }
528 
529 void
530 vga_restore_state(struct vga_pci_softc *sc)
531 {
532 	struct vga_config *vc = sc->sc_vc;
533 	struct vga_handle *vh;
534 	struct vgascreen *scr;
535 	size_t i;
536 	char *buf;
537 
538 	if (vc == NULL)
539 		return;
540 
541 	vh = &vc->hdl;
542 
543 	/*
544 	 * Restore sequencer registers
545 	 */
546 	vga_ts_write(vh, syncreset, 1);	/* stop sequencer */
547 	buf = (char *)&sc->sc_save_ts + 1;
548 	for (i = 1; i < sizeof(sc->sc_save_ts); i++)
549 		_vga_ts_write(vh, i, *buf++);
550 	vga_ts_write(vh, syncreset, 3);	/* start sequencer */
551 
552 	/*
553 	 * Restore CRTC registers
554 	 */
555 	/* unprotect registers 00-07 */
556 	vga_6845_write(vh, vsynce,
557 	    vga_6845_read(vh, vsynce) & ~0x80);
558 	buf = (char *)&sc->sc_save_crtc;
559 	for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
560 		_pcdisplay_6845_write(&vh->vh_ph, i, *buf++);
561 
562 	/*
563 	 * Restore ATC registers
564 	 */
565 	buf = (char *)&sc->sc_save_atc;
566 	for (i = 0; i < sizeof(sc->sc_save_atc); i++)
567 		_vga_attr_write(vh, i, *buf++);
568 
569 	/*
570 	 * Restore GDC registers
571 	 */
572 	buf = (char *)&sc->sc_save_gdc;
573 	for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
574 		_vga_gdc_write(vh, i, *buf++);
575 
576 	vga_restore_palette(vc);
577 
578 	/*
579 	 * Restore current screen contents if we have backing store for it,
580 	 * and have POSTed on resume.
581 	 * XXX Since we don't allocate backing store unless the second VT is
582 	 * XXX created, we could theoretically have no backing store available
583 	 * XXX at this point.
584 	 */
585 	if (vga_pci_do_post) {
586 		scr = vc->active;
587 		if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
588 			bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
589 			    scr->pcs.dispoffset, scr->pcs.mem,
590 			    scr->pcs.type->ncols * scr->pcs.type->nrows);
591 	}
592 }
593 #endif
594