xref: /openbsd-src/sys/arch/macppc/pci/vgafb.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: vgafb.c,v 1.60 2014/07/28 15:00:27 jsg Exp $	*/
2 /*	$NetBSD: vga.c,v 1.3 1996/12/02 22:24:54 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Author: Chris G. Demetriou
9  *
10  * Permission to use, copy, modify and distribute this software and
11  * its documentation is hereby granted, provided that both the copyright
12  * notice and this permission notice appear in all copies of the
13  * software, derivative works or modified versions, and any portions
14  * thereof, and that both notices appear in supporting documentation.
15  *
16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19  *
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 
35 #include <machine/bus.h>
36 
37 #include <dev/wscons/wsconsio.h>
38 #include <dev/wscons/wsdisplayvar.h>
39 #include <dev/rasops/rasops.h>
40 
41 #include <dev/ofw/openfirm.h>
42 #include <macppc/macppc/ofw_machdep.h>
43 
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/vga_pcivar.h>
47 
48 struct vgafb_softc {
49 	struct device		sc_dev;
50 	int			sc_node;
51 
52 	bus_addr_t		sc_mem_addr, sc_mmio_addr;
53 	bus_size_t		sc_mem_size, sc_mmio_size;
54 
55 	struct rasops_info	sc_ri;
56 	uint8_t			sc_cmap[256 * 3];
57 	u_int			sc_mode;
58 
59 	struct	wsscreen_descr	sc_wsd;
60 	struct	wsscreen_list	sc_wsl;
61 	struct	wsscreen_descr *sc_scrlist[1];
62 
63 	int			sc_backlight_on;
64 };
65 
66 int	vgafb_ioctl(void *, u_long, caddr_t, int, struct proc *);
67 paddr_t	vgafb_mmap(void *, off_t, int);
68 int	vgafb_alloc_screen(void *, const struct wsscreen_descr *, void **,
69 	    int *, int *, long *);
70 void	vgafb_free_screen(void *, void *);
71 int	vgafb_show_screen(void *, void *, int, void (*cb)(void *, int, int),
72 	    void *);
73 int	vgafb_load_font(void *, void *, struct wsdisplay_font *);
74 int	vgafb_list_font(void *, struct wsdisplay_font *);
75 void	vgafb_burn(void *v, u_int , u_int);
76 void	vgafb_restore_default_colors(struct vgafb_softc *);
77 int	vgafb_is_console(int);
78 int	vgafb_console_init(struct vgafb_softc *);
79 int	vgafb_mapregs(struct vgafb_softc *, struct pci_attach_args *);
80 
81 struct wsdisplay_accessops vgafb_accessops = {
82 	.ioctl = vgafb_ioctl,
83 	.mmap = vgafb_mmap,
84 	.alloc_screen = vgafb_alloc_screen,
85 	.free_screen = vgafb_free_screen,
86 	.show_screen = vgafb_show_screen,
87 	.load_font = vgafb_load_font,
88 	.list_font = vgafb_list_font,
89 	.burn_screen = vgafb_burn
90 };
91 
92 int	vgafb_getcmap(uint8_t *, struct wsdisplay_cmap *);
93 int	vgafb_putcmap(uint8_t *, struct wsdisplay_cmap *);
94 
95 int	vgafb_match(struct device *, void *, void *);
96 void	vgafb_attach(struct device *, struct device *, void *);
97 
98 const struct cfattach vgafb_ca = {
99 	sizeof(struct vgafb_softc), vgafb_match, vgafb_attach,
100 };
101 
102 struct cfdriver vgafb_cd = {
103 	NULL, "vgafb", DV_DULL,
104 };
105 
106 #ifdef APERTURE
107 extern int allowaperture;
108 #endif
109 
110 int
111 vgafb_match(struct device *parent, void *match, void *aux)
112 {
113 	struct pci_attach_args *pa = aux;
114 	int node;
115 
116 	if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0) {
117 		/*
118 		 * XXX Graphic cards found in iMac G3 have a ``Misc''
119 		 * subclass, match them all.
120 		 */
121 		if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
122 		    PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_MISC)
123 			return (0);
124 	}
125 
126 	/*
127 	 * XXX Non-console devices do not get configured by the PROM,
128 	 * XXX so do not attach them yet.
129 	 */
130 	node = PCITAG_NODE(pa->pa_tag);
131 	if (!vgafb_is_console(node))
132 		return (0);
133 
134 	return (1);
135 }
136 
137 void
138 vgafb_attach(struct device *parent, struct device *self, void *aux)
139 {
140 	struct vgafb_softc *sc = (struct vgafb_softc *)self;
141 	struct pci_attach_args *pa = aux;
142 	struct wsemuldisplaydev_attach_args waa;
143 
144 	sc->sc_node = PCITAG_NODE(pa->pa_tag);
145 
146 	if (vgafb_mapregs(sc, pa))
147 		return;
148 
149 	if (vgafb_console_init(sc))
150 		return;
151 
152 	sc->sc_scrlist[0] = &sc->sc_wsd;
153 	sc->sc_wsl.nscreens = 1;
154 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
155 
156 	waa.console = 1;
157 	waa.scrdata = &sc->sc_wsl;
158 	waa.accessops = &vgafb_accessops;
159 	waa.accesscookie = sc;
160 	waa.defaultscreens = 0;
161 
162 	/* no need to keep the burner function if no hw support */
163 	if (cons_backlight_available == 0)
164 		vgafb_accessops.burn_screen = NULL;
165 	else {
166 		sc->sc_backlight_on = WSDISPLAYIO_VIDEO_OFF;
167 		vgafb_burn(sc, WSDISPLAYIO_VIDEO_ON, 0);	/* paranoia */
168 	}
169 
170 #ifdef RAMDISK_HOOKS
171 	if (vga_aperture_needed(pa))
172 		printf("%s: aperture needed\n", sc->sc_dev.dv_xname);
173 #endif
174 
175 	config_found(self, &waa, wsemuldisplaydevprint);
176 }
177 
178 int
179 vgafb_console_init(struct vgafb_softc *sc)
180 {
181 	struct rasops_info *ri = &sc->sc_ri;
182 	long defattr;
183 
184 	ri->ri_flg = RI_CENTER | RI_VCONS | RI_WRONLY;
185 	ri->ri_hw = sc;
186 
187 	ofwconsswitch(ri);
188 
189 	rasops_init(ri, 160, 160);
190 
191 	strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
192 	sc->sc_wsd.capabilities = ri->ri_caps;
193 	sc->sc_wsd.nrows = ri->ri_rows;
194 	sc->sc_wsd.ncols = ri->ri_cols;
195 	sc->sc_wsd.textops = &ri->ri_ops;
196 	sc->sc_wsd.fontwidth = ri->ri_font->fontwidth;
197 	sc->sc_wsd.fontheight = ri->ri_font->fontheight;
198 
199 	ri->ri_ops.alloc_attr(ri->ri_active, 0, 0, 0, &defattr);
200 	wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active, ri->ri_ccol, ri->ri_crow,
201 	    defattr);
202 
203 	return (0);
204 }
205 
206 void
207 vgafb_restore_default_colors(struct vgafb_softc *sc)
208 {
209 	bcopy(rasops_cmap, sc->sc_cmap, sizeof(sc->sc_cmap));
210 	of_setcolors(sc->sc_cmap, 0, 256);
211 }
212 
213 int
214 vgafb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
215 {
216 	struct vgafb_softc *sc = v;
217 	struct rasops_info *ri = &sc->sc_ri;
218 	struct wsdisplay_cmap *cm;
219 	struct wsdisplay_fbinfo *wdf;
220 	int rc;
221 
222 	switch (cmd) {
223 	case WSDISPLAYIO_GTYPE:
224 		*(u_int *)data = WSDISPLAY_TYPE_PCIVGA;
225 		break;
226 	case WSDISPLAYIO_GINFO:
227 		wdf = (struct wsdisplay_fbinfo *)data;
228 		wdf->width = ri->ri_width;
229 		wdf->height = ri->ri_height;
230 		wdf->depth = ri->ri_depth;
231 		wdf->cmsize = 256;
232 		break;
233 	case WSDISPLAYIO_LINEBYTES:
234 		*(uint *)data = ri->ri_stride;
235 		break;
236 	case WSDISPLAYIO_GETCMAP:
237 		cm = (struct wsdisplay_cmap *)data;
238 		rc = vgafb_getcmap(sc->sc_cmap, cm);
239 		if (rc != 0)
240 			return rc;
241 		break;
242 	case WSDISPLAYIO_PUTCMAP:
243 		cm = (struct wsdisplay_cmap *)data;
244 		rc = vgafb_putcmap(sc->sc_cmap, cm);
245 		if (rc != 0)
246 			return (rc);
247 		if (ri->ri_depth == 8)
248 			of_setcolors(sc->sc_cmap, cm->index, cm->count);
249 		break;
250 	case WSDISPLAYIO_SMODE:
251 		sc->sc_mode = *(u_int *)data;
252 		if (ri->ri_depth == 8)
253 			vgafb_restore_default_colors(sc);
254 		break;
255 	case WSDISPLAYIO_GETPARAM:
256 	{
257 		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
258 
259 		switch (dp->param) {
260 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
261 			if (cons_backlight_available != 0) {
262 				dp->min = MIN_BRIGHTNESS;
263 				dp->max = MAX_BRIGHTNESS;
264 				dp->curval = cons_brightness;
265 				return 0;
266 			}
267 			return -1;
268 		case WSDISPLAYIO_PARAM_BACKLIGHT:
269 			if (cons_backlight_available != 0) {
270 				dp->min = 0;
271 				dp->max = 1;
272 				dp->curval = sc->sc_backlight_on;
273 				return 0;
274 			} else
275 				return -1;
276 		}
277 	}
278 		return -1;
279 
280 	case WSDISPLAYIO_SETPARAM:
281 	{
282 		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
283 
284 		switch (dp->param) {
285 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
286 			if (cons_backlight_available == 1) {
287 				of_setbrightness(dp->curval);
288 				return 0;
289 			} else
290 				return -1;
291 		case WSDISPLAYIO_PARAM_BACKLIGHT:
292 			if (cons_backlight_available != 0) {
293 				vgafb_burn(sc,
294 				    dp->curval ? WSDISPLAYIO_VIDEO_ON :
295 				      WSDISPLAYIO_VIDEO_OFF, 0);
296 				return 0;
297 			} else
298 				return -1;
299 		}
300 	}
301 		return -1;
302 
303 	case WSDISPLAYIO_SVIDEO:
304 	case WSDISPLAYIO_GVIDEO:
305 		break;
306 
307 	case WSDISPLAYIO_GCURPOS:
308 	case WSDISPLAYIO_SCURPOS:
309 	case WSDISPLAYIO_GCURMAX:
310 	case WSDISPLAYIO_GCURSOR:
311 	case WSDISPLAYIO_SCURSOR:
312 	default:
313 		return -1; /* not supported yet */
314 	}
315 
316 	return (0);
317 }
318 
319 paddr_t
320 vgafb_mmap(void *v, off_t off, int prot)
321 {
322 	struct vgafb_softc *sc = v;
323 
324 	if (off & PGOFSET)
325 		return (-1);
326 
327 	switch (sc->sc_mode) {
328 	case WSDISPLAYIO_MODE_MAPPED:
329 #ifdef APERTURE
330 		if (allowaperture == 0)
331 			return (-1);
332 #endif
333 
334 		if (sc->sc_mmio_size == 0)
335 			return (-1);
336 
337 		if (off >= sc->sc_mem_addr &&
338 		    off < (sc->sc_mem_addr + sc->sc_mem_size))
339 			return (off);
340 
341 		if (off >= sc->sc_mmio_addr &&
342 		    off < (sc->sc_mmio_addr + sc->sc_mmio_size))
343 			return (off);
344 		break;
345 
346 	case WSDISPLAYIO_MODE_DUMBFB:
347 		if (off >= 0x00000 && off < sc->sc_mem_size)
348 			return (sc->sc_mem_addr + off);
349 		break;
350 
351 	}
352 
353 	return (-1);
354 }
355 
356 int
357 vgafb_is_console(int node)
358 {
359 	extern int fbnode;
360 
361 	return (fbnode == node);
362 }
363 
364 int
365 vgafb_getcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
366 {
367 	uint index = cm->index, count = cm->count, i;
368 	uint8_t ramp[256], *dst, *src;
369 	int rc;
370 
371 	if (index >= 256 || count > 256 - index)
372 		return EINVAL;
373 
374 	index *= 3;
375 
376 	src = cmap + index;
377 	dst = ramp;
378 	for (i = 0; i < count; i++)
379 		*dst++ = *src, src += 3;
380 	rc = copyout(ramp, cm->red, count);
381 	if (rc != 0)
382 		return rc;
383 
384 	src = cmap + index + 1;
385 	dst = ramp;
386 	for (i = 0; i < count; i++)
387 		*dst++ = *src, src += 3;
388 	rc = copyout(ramp, cm->green, count);
389 	if (rc != 0)
390 		return rc;
391 
392 	src = cmap + index + 2;
393 	dst = ramp;
394 	for (i = 0; i < count; i++)
395 		*dst++ = *src, src += 3;
396 	rc = copyout(ramp, cm->blue, count);
397 	if (rc != 0)
398 		return rc;
399 
400 	return 0;
401 }
402 
403 int
404 vgafb_putcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
405 {
406 	uint index = cm->index, count = cm->count, i;
407 	uint8_t ramp[256], *dst, *src;
408 	int rc;
409 
410 	if (index >= 256 || count > 256 - index)
411 		return EINVAL;
412 
413 	index *= 3;
414 
415 	rc = copyin(cm->red, ramp, count);
416 	if (rc != 0)
417 		return rc;
418 	dst = cmap + index;
419 	src = ramp;
420 	for (i = 0; i < count; i++)
421 		*dst = *src++, dst += 3;
422 
423 	rc = copyin(cm->green, ramp, count);
424 	if (rc != 0)
425 		return rc;
426 	dst = cmap + index + 1;
427 	src = ramp;
428 	for (i = 0; i < count; i++)
429 		*dst = *src++, dst += 3;
430 
431 	rc = copyin(cm->blue, ramp, count);
432 	if (rc != 0)
433 		return rc;
434 	dst = cmap + index + 2;
435 	src = ramp;
436 	for (i = 0; i < count; i++)
437 		*dst = *src++, dst += 3;
438 
439 	return 0;
440 }
441 
442 void
443 vgafb_burn(void *v, u_int on, u_int flags)
444 {
445 	struct vgafb_softc *sc = v;
446 
447 	if (sc->sc_backlight_on != on) {
448 		of_setbacklight(on == WSDISPLAYIO_VIDEO_ON);
449 		sc->sc_backlight_on = on;
450 	}
451 }
452 
453 int
454 vgafb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
455     int *curxp, int *curyp, long *attrp)
456 {
457 	struct vgafb_softc *sc = v;
458 	struct rasops_info *ri = &sc->sc_ri;
459 
460 	return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
461 }
462 
463 void
464 vgafb_free_screen(void *v, void *cookie)
465 {
466 	struct vgafb_softc *sc = v;
467 	struct rasops_info *ri = &sc->sc_ri;
468 
469 	return rasops_free_screen(ri, cookie);
470 }
471 
472 int
473 vgafb_show_screen(void *v, void *cookie, int waitok,
474     void (*cb)(void *, int, int), void *cbarg)
475 {
476 	struct vgafb_softc *sc = v;
477 	struct rasops_info *ri = &sc->sc_ri;
478 
479 	if (cookie == ri->ri_active)
480 		return (0);
481 
482 	return rasops_show_screen(ri, cookie, waitok, cb, cbarg);
483 }
484 
485 int
486 vgafb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
487 {
488 	struct vgafb_softc *sc = v;
489 	struct rasops_info *ri = &sc->sc_ri;
490 
491 	return rasops_load_font(ri, emulcookie, font);
492 }
493 
494 int
495 vgafb_list_font(void *v, struct wsdisplay_font *font)
496 {
497 	struct vgafb_softc *sc = v;
498 	struct rasops_info *ri = &sc->sc_ri;
499 
500 	return rasops_list_font(ri, font);
501 }
502 
503 int
504 vgafb_mapregs(struct vgafb_softc *sc, struct pci_attach_args *pa)
505 {
506 	bus_addr_t ba;
507 	bus_size_t bs;
508 	int hasmem = 0, hasmmio = 0;
509 	uint32_t i, cf;
510 	int rv;
511 
512 	for (i = PCI_MAPREG_START; i <= PCI_MAPREG_PPB_END; i += 4) {
513 		cf = pci_conf_read(pa->pa_pc, pa->pa_tag, i);
514 		if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_MEM) {
515 			/* Memory mapping... frame memory or mmio? */
516 			rv = pci_mem_find(pa->pa_pc, pa->pa_tag, i,
517 			    &ba, &bs, NULL);
518 			if (rv != 0)
519 				continue;
520 
521 			if (bs == 0 /* || ba == 0 */) {
522 				/* ignore this entry */
523 			} else if (hasmem == 0) {
524 				/*
525 				 * first memory slot found goes into memory,
526 				 * this is for the case of no mmio
527 				 */
528 				sc->sc_mem_addr = ba;
529 				sc->sc_mem_size = bs;
530 				hasmem = 1;
531 			} else {
532 				/*
533 				 * Oh, we have a second `memory'
534 				 * region, is this region the vga memory
535 				 * or mmio, we guess that memory is
536 				 * the larger of the two.
537 				 */
538 				if (sc->sc_mem_size >= bs) {
539 					/* this is the mmio */
540 					sc->sc_mmio_addr = ba;
541 					sc->sc_mmio_size = bs;
542 					hasmmio = 1;
543 				} else {
544 					/* this is the memory */
545 					sc->sc_mmio_addr = sc->sc_mem_addr;
546 					sc->sc_mmio_size = sc->sc_mem_size;
547 					sc->sc_mem_addr = ba;
548 					sc->sc_mem_size = bs;
549 				}
550 			}
551 		}
552 	}
553 
554 	/* failure to initialize io ports should not prevent attachment */
555 	if (hasmem == 0) {
556 		printf(": could not find memory space\n");
557 		return (1);
558 	}
559 
560 	if (hasmmio)
561 		printf (", mmio");
562 	printf("\n");
563 
564 	return (0);
565 }
566