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