xref: /openbsd/sys/arch/macppc/pci/vgafb.c (revision 7b44a193)
1 /*	$OpenBSD: vgafb.c,v 1.65 2023/04/13 15:07:43 miod 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 *, uint32_t *);
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
vgafb_match(struct device * parent,void * match,void * aux)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
vgafb_attach(struct device * parent,struct device * self,void * aux)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
vgafb_console_init(struct vgafb_softc * sc)179 vgafb_console_init(struct vgafb_softc *sc)
180 {
181 	struct rasops_info *ri = &sc->sc_ri;
182 	uint32_t 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.pack_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
vgafb_restore_default_colors(struct vgafb_softc * sc)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
vgafb_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)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->stride = ri->ri_stride;
232 		wdf->offset = 0;
233 		wdf->cmsize = 256;
234 		break;
235 	case WSDISPLAYIO_LINEBYTES:
236 		*(uint *)data = ri->ri_stride;
237 		break;
238 	case WSDISPLAYIO_GETCMAP:
239 		cm = (struct wsdisplay_cmap *)data;
240 		rc = vgafb_getcmap(sc->sc_cmap, cm);
241 		if (rc != 0)
242 			return rc;
243 		break;
244 	case WSDISPLAYIO_PUTCMAP:
245 		cm = (struct wsdisplay_cmap *)data;
246 		rc = vgafb_putcmap(sc->sc_cmap, cm);
247 		if (rc != 0)
248 			return (rc);
249 		if (ri->ri_depth == 8)
250 			of_setcolors(sc->sc_cmap, cm->index, cm->count);
251 		break;
252 	case WSDISPLAYIO_SMODE:
253 		sc->sc_mode = *(u_int *)data;
254 		if (ri->ri_depth == 8)
255 			vgafb_restore_default_colors(sc);
256 		break;
257 	case WSDISPLAYIO_GETPARAM:
258 	{
259 		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
260 
261 		switch (dp->param) {
262 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
263 			if (cons_backlight_available != 0) {
264 				dp->min = MIN_BRIGHTNESS;
265 				dp->max = MAX_BRIGHTNESS;
266 				dp->curval = cons_brightness;
267 				return 0;
268 			}
269 			return -1;
270 		case WSDISPLAYIO_PARAM_BACKLIGHT:
271 			if (cons_backlight_available != 0) {
272 				dp->min = 0;
273 				dp->max = 1;
274 				dp->curval = sc->sc_backlight_on;
275 				return 0;
276 			} else
277 				return -1;
278 		}
279 	}
280 		return -1;
281 
282 	case WSDISPLAYIO_SETPARAM:
283 	{
284 		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
285 
286 		switch (dp->param) {
287 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
288 			if (cons_backlight_available == 1) {
289 				of_setbrightness(dp->curval);
290 				return 0;
291 			} else
292 				return -1;
293 		case WSDISPLAYIO_PARAM_BACKLIGHT:
294 			if (cons_backlight_available != 0) {
295 				vgafb_burn(sc,
296 				    dp->curval ? WSDISPLAYIO_VIDEO_ON :
297 				      WSDISPLAYIO_VIDEO_OFF, 0);
298 				return 0;
299 			} else
300 				return -1;
301 		}
302 	}
303 		return -1;
304 
305 	case WSDISPLAYIO_SVIDEO:
306 	case WSDISPLAYIO_GVIDEO:
307 		break;
308 
309 	case WSDISPLAYIO_GCURPOS:
310 	case WSDISPLAYIO_SCURPOS:
311 	case WSDISPLAYIO_GCURMAX:
312 	case WSDISPLAYIO_GCURSOR:
313 	case WSDISPLAYIO_SCURSOR:
314 	default:
315 		return -1; /* not supported yet */
316 	}
317 
318 	return (0);
319 }
320 
321 paddr_t
vgafb_mmap(void * v,off_t off,int prot)322 vgafb_mmap(void *v, off_t off, int prot)
323 {
324 	struct vgafb_softc *sc = v;
325 
326 	if (off & PGOFSET)
327 		return (-1);
328 
329 	switch (sc->sc_mode) {
330 	case WSDISPLAYIO_MODE_MAPPED:
331 #ifdef APERTURE
332 		if (allowaperture == 0)
333 			return (-1);
334 #endif
335 
336 		if (sc->sc_mmio_size == 0)
337 			return (-1);
338 
339 		if (off >= sc->sc_mem_addr &&
340 		    off < (sc->sc_mem_addr + sc->sc_mem_size))
341 			return (off);
342 
343 		if (off >= sc->sc_mmio_addr &&
344 		    off < (sc->sc_mmio_addr + sc->sc_mmio_size))
345 			return (off);
346 		break;
347 
348 	case WSDISPLAYIO_MODE_DUMBFB:
349 		if (off >= 0x00000 && off < sc->sc_mem_size)
350 			return (sc->sc_mem_addr + off);
351 		break;
352 
353 	}
354 
355 	return (-1);
356 }
357 
358 int
vgafb_is_console(int node)359 vgafb_is_console(int node)
360 {
361 	extern int fbnode;
362 
363 	return (fbnode == node);
364 }
365 
366 int
vgafb_getcmap(uint8_t * cmap,struct wsdisplay_cmap * cm)367 vgafb_getcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
368 {
369 	uint index = cm->index, count = cm->count, i;
370 	uint8_t ramp[256], *dst, *src;
371 	int rc;
372 
373 	if (index >= 256 || count > 256 - index)
374 		return EINVAL;
375 
376 	index *= 3;
377 
378 	src = cmap + index;
379 	dst = ramp;
380 	for (i = 0; i < count; i++)
381 		*dst++ = *src, src += 3;
382 	rc = copyout(ramp, cm->red, count);
383 	if (rc != 0)
384 		return rc;
385 
386 	src = cmap + index + 1;
387 	dst = ramp;
388 	for (i = 0; i < count; i++)
389 		*dst++ = *src, src += 3;
390 	rc = copyout(ramp, cm->green, count);
391 	if (rc != 0)
392 		return rc;
393 
394 	src = cmap + index + 2;
395 	dst = ramp;
396 	for (i = 0; i < count; i++)
397 		*dst++ = *src, src += 3;
398 	rc = copyout(ramp, cm->blue, count);
399 	if (rc != 0)
400 		return rc;
401 
402 	return 0;
403 }
404 
405 int
vgafb_putcmap(uint8_t * cmap,struct wsdisplay_cmap * cm)406 vgafb_putcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
407 {
408 	uint index = cm->index, count = cm->count, i;
409 	uint8_t ramp[256], *dst, *src;
410 	int rc;
411 
412 	if (index >= 256 || count > 256 - index)
413 		return EINVAL;
414 
415 	index *= 3;
416 
417 	rc = copyin(cm->red, ramp, count);
418 	if (rc != 0)
419 		return rc;
420 	dst = cmap + index;
421 	src = ramp;
422 	for (i = 0; i < count; i++)
423 		*dst = *src++, dst += 3;
424 
425 	rc = copyin(cm->green, ramp, count);
426 	if (rc != 0)
427 		return rc;
428 	dst = cmap + index + 1;
429 	src = ramp;
430 	for (i = 0; i < count; i++)
431 		*dst = *src++, dst += 3;
432 
433 	rc = copyin(cm->blue, ramp, count);
434 	if (rc != 0)
435 		return rc;
436 	dst = cmap + index + 2;
437 	src = ramp;
438 	for (i = 0; i < count; i++)
439 		*dst = *src++, dst += 3;
440 
441 	return 0;
442 }
443 
444 void
vgafb_burn(void * v,u_int on,u_int flags)445 vgafb_burn(void *v, u_int on, u_int flags)
446 {
447 	struct vgafb_softc *sc = v;
448 
449 	if (sc->sc_backlight_on != on) {
450 		of_setbacklight(on == WSDISPLAYIO_VIDEO_ON);
451 		sc->sc_backlight_on = on;
452 	}
453 }
454 
455 int
vgafb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,uint32_t * attrp)456 vgafb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
457     int *curxp, int *curyp, uint32_t *attrp)
458 {
459 	struct vgafb_softc *sc = v;
460 	struct rasops_info *ri = &sc->sc_ri;
461 
462 	return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
463 }
464 
465 void
vgafb_free_screen(void * v,void * cookie)466 vgafb_free_screen(void *v, void *cookie)
467 {
468 	struct vgafb_softc *sc = v;
469 	struct rasops_info *ri = &sc->sc_ri;
470 
471 	return rasops_free_screen(ri, cookie);
472 }
473 
474 int
vgafb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)475 vgafb_show_screen(void *v, void *cookie, int waitok,
476     void (*cb)(void *, int, int), void *cbarg)
477 {
478 	struct vgafb_softc *sc = v;
479 	struct rasops_info *ri = &sc->sc_ri;
480 
481 	if (cookie == ri->ri_active)
482 		return (0);
483 
484 	return rasops_show_screen(ri, cookie, waitok, cb, cbarg);
485 }
486 
487 int
vgafb_load_font(void * v,void * emulcookie,struct wsdisplay_font * font)488 vgafb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
489 {
490 	struct vgafb_softc *sc = v;
491 	struct rasops_info *ri = &sc->sc_ri;
492 
493 	return rasops_load_font(ri, emulcookie, font);
494 }
495 
496 int
vgafb_list_font(void * v,struct wsdisplay_font * font)497 vgafb_list_font(void *v, struct wsdisplay_font *font)
498 {
499 	struct vgafb_softc *sc = v;
500 	struct rasops_info *ri = &sc->sc_ri;
501 
502 	return rasops_list_font(ri, font);
503 }
504 
505 int
vgafb_mapregs(struct vgafb_softc * sc,struct pci_attach_args * pa)506 vgafb_mapregs(struct vgafb_softc *sc, struct pci_attach_args *pa)
507 {
508 	bus_addr_t ba;
509 	bus_size_t bs;
510 	int hasmem = 0, hasmmio = 0;
511 	uint32_t bar, cf;
512 	int rv;
513 
514 	/*
515 	 * Look for the first 2 mem regions.  For r128, this skips the
516 	 * io region 0x14 and finds frame memory 0x10 and mmio 0x18.
517 	 * For nvidia, this finds mmio 0x10 and frame memory 0x14.
518 	 * Some nvidias have a 3rd mem region 0x18, which we ignore.
519 	 */
520 	for (bar = PCI_MAPREG_START; bar <= PCI_MAPREG_PPB_END; bar += 4) {
521 		cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
522 		if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_MEM) {
523 			/* Memory mapping... frame memory or mmio? */
524 			rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar,
525 			    _PCI_MAPREG_TYPEBITS(cf), &ba, &bs, NULL);
526 			if (rv != 0)
527 				continue;
528 
529 			if (bs == 0 /* || ba == 0 */) {
530 				/* ignore this entry */
531 			} else if (hasmem == 0) {
532 				/*
533 				 * first memory slot found goes into memory,
534 				 * this is for the case of no mmio
535 				 */
536 				sc->sc_mem_addr = ba;
537 				sc->sc_mem_size = bs;
538 				hasmem = 1;
539 			} else {
540 				/*
541 				 * Oh, we have a second `memory'
542 				 * region, is this region the vga memory
543 				 * or mmio, we guess that memory is
544 				 * the larger of the two.
545 				 */
546 				if (sc->sc_mem_size >= bs) {
547 					/* this is the mmio */
548 					sc->sc_mmio_addr = ba;
549 					sc->sc_mmio_size = bs;
550 					hasmmio = 1;
551 				} else {
552 					/* this is the memory */
553 					sc->sc_mmio_addr = sc->sc_mem_addr;
554 					sc->sc_mmio_size = sc->sc_mem_size;
555 					sc->sc_mem_addr = ba;
556 					sc->sc_mem_size = bs;
557 				}
558 				/* Ignore any other mem region. */
559 				break;
560 			}
561 			if (PCI_MAPREG_MEM_TYPE(cf) ==
562 			    PCI_MAPREG_MEM_TYPE_64BIT)
563 				bar += 4;
564 		}
565 	}
566 
567 	/* failure to initialize io ports should not prevent attachment */
568 	if (hasmem == 0) {
569 		printf(": could not find memory space\n");
570 		return (1);
571 	}
572 
573 	if (hasmmio)
574 		printf (", mmio");
575 	printf("\n");
576 
577 	return (0);
578 }
579