Line data Source code
1 : /* $OpenBSD: vga_pci.c,v 1.87 2015/10/29 07:47:03 kettenis 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 : #if defined(__i386__) || defined(__amd64__)
67 : #include "acpi.h"
68 : #endif
69 :
70 : #include <sys/param.h>
71 : #include <sys/systm.h>
72 : #include <sys/kernel.h>
73 : #include <sys/device.h>
74 : #include <sys/malloc.h>
75 : #include <sys/rwlock.h>
76 :
77 : #include <machine/bus.h>
78 :
79 : #include <dev/pci/pcireg.h>
80 : #include <dev/pci/pcivar.h>
81 : #include <dev/pci/pcidevs.h>
82 :
83 : #include <dev/ic/mc6845reg.h>
84 : #include <dev/ic/pcdisplayvar.h>
85 : #include <dev/ic/vgareg.h>
86 : #include <dev/pci/vga_pcivar.h>
87 :
88 : #include <dev/wscons/wsconsio.h>
89 : #include <dev/wscons/wsdisplayvar.h>
90 : #include <dev/ic/vgavar.h>
91 :
92 : #ifdef X86EMU
93 : #include <machine/vga_post.h>
94 : #endif
95 :
96 : int vga_pci_match(struct device *, void *, void *);
97 : void vga_pci_attach(struct device *, struct device *, void *);
98 : int vga_pci_activate(struct device *, int);
99 : paddr_t vga_pci_mmap(void* v, off_t off, int prot);
100 :
101 : #if !defined(SMALL_KERNEL) && NACPI > 0
102 : void vga_save_state(struct vga_pci_softc *);
103 : void vga_restore_state(struct vga_pci_softc *);
104 : #endif
105 :
106 : /*
107 : * Function pointers for wsconsctl parameter handling.
108 : * XXX These should be per-softc, but right now we only attach
109 : * XXX a single vga@pci instance, so this will do.
110 : */
111 : int (*ws_get_param)(struct wsdisplay_param *);
112 : int (*ws_set_param)(struct wsdisplay_param *);
113 :
114 :
115 : struct cfattach vga_pci_ca = {
116 : sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach,
117 : NULL, vga_pci_activate
118 : };
119 :
120 : #if !defined(SMALL_KERNEL) && NACPI > 0
121 : int vga_pci_do_post;
122 :
123 : struct vga_device_description {
124 : u_int16_t rval[4];
125 : u_int16_t rmask[4];
126 : char vga_pci_post;
127 : };
128 :
129 : static const struct vga_device_description vga_devs[] = {
130 : /*
131 : * Header description:
132 : *
133 : * First entry is a list of the pci video information in the following
134 : * order: VENDOR, PRODUCT, SUBVENDOR, SUBPRODUCT
135 : *
136 : * The next entry is a list of corresponding masks.
137 : *
138 : * Finally the last value indicates if we should repost via
139 : * vga_pci (i.e. the x86emulator) * bios.
140 : */
141 : { /* All machines with GMA500/Poulsbo */
142 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15W_IGD,
143 : 0x0000, 0x0000 },
144 : { 0xffff, 0xffff, 0x0000, 0x0000 }, 1
145 : },
146 : { /* All machines with GMA500/Poulsbo */
147 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15L_IGD,
148 : 0x0000, 0x0000 },
149 : { 0xffff, 0xffff, 0x0000, 0x0000 }, 1
150 : },
151 : { /* All machines with GMA600/Oaktrail, 0x4100:4107 */
152 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GMA600_0,
153 : 0x0000, 0x0000 },
154 : { 0xffff, 0xfff8, 0x0000, 0x0000 }, 1
155 : },
156 : { /* All machines with GMA600/Oaktrail, 0x4108 */
157 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GMA600_8,
158 : 0x0000, 0x0000 },
159 : { 0xffff, 0xffff, 0x0000, 0x0000 }, 1
160 : },
161 : { /* All machines with Medfield, 0x0130:0x0137 */
162 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MDFLD_IGD_0,
163 : 0x0000, 0x0000 },
164 : { 0xffff, 0xfff8, 0x0000, 0x0000 }, 1
165 : },
166 : { /* All machines with GMA36x0/Cedartrail, 0x0be0:0x0bef */
167 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GMA3600_0,
168 : 0x0000, 0x0000 },
169 : { 0xffff, 0xfff0, 0x0000, 0x0000 }, 1
170 : },
171 : };
172 : #endif
173 :
174 : int
175 0 : vga_pci_match(struct device *parent, void *match, void *aux)
176 : {
177 0 : struct pci_attach_args *pa = aux;
178 :
179 0 : if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0)
180 0 : return (0);
181 :
182 : /* check whether it is disabled by firmware */
183 0 : if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG)
184 0 : & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
185 0 : != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
186 0 : return (0);
187 :
188 : /* If it's the console, we have a winner! */
189 0 : if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA))
190 0 : return (1);
191 :
192 : /*
193 : * If we might match, make sure that the card actually looks OK.
194 : */
195 0 : if (!vga_common_probe(pa->pa_iot, pa->pa_memt))
196 0 : return (0);
197 :
198 0 : return (1);
199 0 : }
200 :
201 : void
202 0 : vga_pci_attach(struct device *parent, struct device *self, void *aux)
203 : {
204 0 : struct pci_attach_args *pa = aux;
205 : pcireg_t reg;
206 0 : struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
207 : #if !defined(SMALL_KERNEL) && NACPI > 0
208 : int prod, vend, subid, subprod, subvend, i;
209 : #endif
210 :
211 : /*
212 : * Enable bus master; X might need this for accelerated graphics.
213 : */
214 0 : reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
215 0 : reg |= PCI_COMMAND_MASTER_ENABLE;
216 0 : pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
217 :
218 0 : sc->sc_type = WSDISPLAY_TYPE_PCIVGA;
219 :
220 0 : printf("\n");
221 :
222 : #if !defined(SMALL_KERNEL) && NACPI > 0
223 :
224 : #ifdef X86EMU
225 0 : if ((sc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device,
226 0 : pa->pa_function)) == NULL)
227 0 : printf("couldn't set up vga POST handler\n");
228 : #endif
229 :
230 0 : vend = PCI_VENDOR(pa->pa_id);
231 0 : prod = PCI_PRODUCT(pa->pa_id);
232 0 : subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
233 0 : subvend = PCI_VENDOR(subid);
234 0 : subprod = PCI_PRODUCT(subid);
235 :
236 0 : for (i = 0; i < nitems(vga_devs); i++)
237 0 : if ((vend & vga_devs[i].rmask[0]) == vga_devs[i].rval[0] &&
238 0 : (prod & vga_devs[i].rmask[1]) == vga_devs[i].rval[1] &&
239 0 : (subvend & vga_devs[i].rmask[2]) == vga_devs[i].rval[2] &&
240 0 : (subprod & vga_devs[i].rmask[3]) == vga_devs[i].rval[3]) {
241 0 : vga_pci_do_post = vga_devs[i].vga_pci_post;
242 0 : break;
243 : }
244 : #endif
245 :
246 : #ifdef RAMDISK_HOOKS
247 : if (vga_aperture_needed(pa))
248 : printf("%s: aperture needed\n", sc->sc_dev.dv_xname);
249 : #endif
250 :
251 0 : sc->sc_vc = vga_common_attach(self, pa->pa_iot, pa->pa_memt,
252 0 : sc->sc_type);
253 0 : }
254 :
255 : int
256 0 : vga_pci_activate(struct device *self, int act)
257 : {
258 : int rv = 0;
259 :
260 : #if !defined(SMALL_KERNEL) && NACPI > 0
261 0 : struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
262 : #endif
263 :
264 0 : switch (act) {
265 : case DVACT_SUSPEND:
266 0 : rv = config_activate_children(self, act);
267 : #if !defined(SMALL_KERNEL) && NACPI > 0
268 : /*
269 : * Save the common vga state. This should theoretically only
270 : * be necessary if we intend to POST, but it is preferrable
271 : * to do it unconditionnaly, as many systems do not restore
272 : * this state correctly upon resume.
273 : */
274 0 : vga_save_state(sc);
275 : #endif
276 0 : break;
277 : case DVACT_RESUME:
278 : #if !defined(SMALL_KERNEL) && NACPI > 0
279 : #if defined (X86EMU)
280 0 : if (vga_pci_do_post)
281 0 : vga_post_call(sc->sc_posth);
282 : #endif
283 0 : vga_restore_state(sc);
284 : #endif
285 0 : rv = config_activate_children(self, act);
286 0 : break;
287 : default:
288 0 : rv = config_activate_children(self, act);
289 0 : break;
290 : }
291 :
292 0 : return (rv);
293 : }
294 :
295 : paddr_t
296 0 : vga_pci_mmap(void *v, off_t off, int prot)
297 : {
298 0 : return -1;
299 : }
300 :
301 : int
302 0 : vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt,
303 : pci_chipset_tag_t pc, int bus, int device, int function)
304 : {
305 0 : return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0));
306 : }
307 :
308 : int
309 0 : vga_pci_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb)
310 : {
311 : int error = 0;
312 :
313 0 : switch (cmd) {
314 : case WSDISPLAYIO_GETPARAM:
315 0 : if (ws_get_param != NULL)
316 0 : return (*ws_get_param)((struct wsdisplay_param *)addr);
317 : else
318 : error = ENOTTY;
319 0 : break;
320 : case WSDISPLAYIO_SETPARAM:
321 0 : if (ws_set_param != NULL)
322 0 : return (*ws_set_param)((struct wsdisplay_param *)addr);
323 : else
324 : error = ENOTTY;
325 0 : break;
326 : default:
327 : error = ENOTTY;
328 0 : }
329 :
330 0 : return (error);
331 0 : }
332 :
333 : #if !defined(SMALL_KERNEL) && NACPI > 0
334 : void
335 0 : vga_save_state(struct vga_pci_softc *sc)
336 : {
337 0 : struct vga_config *vc = sc->sc_vc;
338 : struct vga_handle *vh;
339 : struct vgascreen *scr;
340 : size_t i;
341 : char *buf;
342 :
343 0 : if (vc == NULL)
344 0 : return;
345 :
346 0 : vh = &vc->hdl;
347 :
348 : /*
349 : * Save sequencer registers
350 : */
351 0 : vga_ts_write(vh, syncreset, 1); /* stop sequencer */
352 0 : buf = (char *)&sc->sc_save_ts;
353 0 : *buf++ = 0;
354 0 : for (i = 1; i < sizeof(sc->sc_save_ts); i++)
355 0 : *buf++ = _vga_ts_read(vh, i);
356 0 : vga_ts_write(vh, syncreset, 3); /* start sequencer */
357 : /* pretend screen is not blanked */
358 0 : sc->sc_save_ts.mode &= ~0x20;
359 0 : sc->sc_save_ts.mode |= 0x80;
360 :
361 : /*
362 : * Save CRTC registers
363 : */
364 0 : buf = (char *)&sc->sc_save_crtc;
365 0 : for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
366 0 : *buf++ = _pcdisplay_6845_read(&vh->vh_ph, i);
367 :
368 : /*
369 : * Save ATC registers
370 : */
371 0 : buf = (char *)&sc->sc_save_atc;
372 0 : for (i = 0; i < sizeof(sc->sc_save_atc); i++)
373 0 : *buf++ = _vga_attr_read(vh, i);
374 :
375 : /*
376 : * Save GDC registers
377 : */
378 0 : buf = (char *)&sc->sc_save_gdc;
379 0 : for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
380 0 : *buf++ = _vga_gdc_read(vh, i);
381 :
382 0 : vga_save_palette(vc);
383 :
384 : /* XXX should also save font data */
385 :
386 : /*
387 : * Save current screen contents if we have backing store for it,
388 : * and intend to POST on resume.
389 : * XXX Since we don't allocate backing store unless the second VT is
390 : * XXX created, we could theoretically have no backing store available
391 : * XXX at this point.
392 : */
393 0 : if (vga_pci_do_post) {
394 0 : scr = vc->active;
395 0 : if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
396 0 : bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
397 : scr->pcs.dispoffset, scr->pcs.mem,
398 : scr->pcs.type->ncols * scr->pcs.type->nrows);
399 : }
400 0 : }
401 :
402 : void
403 0 : vga_restore_state(struct vga_pci_softc *sc)
404 : {
405 0 : struct vga_config *vc = sc->sc_vc;
406 : struct vga_handle *vh;
407 : struct vgascreen *scr;
408 : size_t i;
409 : char *buf;
410 :
411 0 : if (vc == NULL)
412 0 : return;
413 :
414 0 : vh = &vc->hdl;
415 :
416 : /*
417 : * Restore sequencer registers
418 : */
419 0 : vga_ts_write(vh, syncreset, 1); /* stop sequencer */
420 0 : buf = (char *)&sc->sc_save_ts + 1;
421 0 : for (i = 1; i < sizeof(sc->sc_save_ts); i++)
422 0 : _vga_ts_write(vh, i, *buf++);
423 0 : vga_ts_write(vh, syncreset, 3); /* start sequencer */
424 :
425 : /*
426 : * Restore CRTC registers
427 : */
428 : /* unprotect registers 00-07 */
429 0 : vga_6845_write(vh, vsynce,
430 : vga_6845_read(vh, vsynce) & ~0x80);
431 0 : buf = (char *)&sc->sc_save_crtc;
432 0 : for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
433 0 : _pcdisplay_6845_write(&vh->vh_ph, i, *buf++);
434 :
435 : /*
436 : * Restore ATC registers
437 : */
438 0 : buf = (char *)&sc->sc_save_atc;
439 0 : for (i = 0; i < sizeof(sc->sc_save_atc); i++)
440 0 : _vga_attr_write(vh, i, *buf++);
441 :
442 : /*
443 : * Restore GDC registers
444 : */
445 0 : buf = (char *)&sc->sc_save_gdc;
446 0 : for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
447 0 : _vga_gdc_write(vh, i, *buf++);
448 :
449 0 : vga_restore_fonts(vc);
450 0 : vga_restore_palette(vc);
451 :
452 : /*
453 : * Restore current screen contents if we have backing store for it,
454 : * and have POSTed on resume.
455 : * XXX Since we don't allocate backing store unless the second VT is
456 : * XXX created, we could theoretically have no backing store available
457 : * XXX at this point.
458 : */
459 0 : if (vga_pci_do_post) {
460 0 : scr = vc->active;
461 0 : if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
462 0 : bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
463 : scr->pcs.dispoffset, scr->pcs.mem,
464 : scr->pcs.type->ncols * scr->pcs.type->nrows);
465 : }
466 0 : }
467 : #endif
|