xref: /freebsd-14.2/sys/dev/vt/hw/fb/vt_fb.c (revision b8aeb710)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 The FreeBSD Foundation
5  *
6  * This software was developed by Aleksandr Rybalko under sponsorship from the
7  * FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/queue.h>
36 #include <sys/fbio.h>
37 #include <sys/kernel.h>
38 #include <dev/vt/vt.h>
39 #include <dev/vt/hw/fb/vt_fb.h>
40 #include <dev/vt/colors/vt_termcolors.h>
41 
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44 
45 static struct vt_driver vt_fb_driver = {
46 	.vd_name = "fb",
47 	.vd_init = vt_fb_init,
48 	.vd_fini = vt_fb_fini,
49 	.vd_blank = vt_fb_blank,
50 	.vd_bitblt_text = vt_fb_bitblt_text,
51 	.vd_invalidate_text = vt_fb_invalidate_text,
52 	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
53 	.vd_bitblt_argb = vt_fb_bitblt_argb,
54 	.vd_drawrect = vt_fb_drawrect,
55 	.vd_setpixel = vt_fb_setpixel,
56 	.vd_postswitch = vt_fb_postswitch,
57 	.vd_priority = VD_PRIORITY_GENERIC+10,
58 	.vd_fb_ioctl = vt_fb_ioctl,
59 	.vd_fb_mmap = vt_fb_mmap,
60 	.vd_suspend = vt_fb_suspend,
61 	.vd_resume = vt_fb_resume,
62 };
63 
64 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
65 
66 static void
67 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
68 {
69 
70 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
71 	*(uint8_t *)(sc->fb_vbase + o) = v;
72 }
73 
74 static void
75 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
76 {
77 
78 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
79 	*(uint16_t *)(sc->fb_vbase + o) = v;
80 }
81 
82 static void
83 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
84 {
85 
86 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
87 	*(uint32_t *)(sc->fb_vbase + o) = v;
88 }
89 
90 int
91 vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
92 {
93 	struct fb_info *info;
94 	int error = 0;
95 
96 	info = vd->vd_softc;
97 
98 	switch (cmd) {
99 	case FBIOGTYPE:
100 		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
101 		break;
102 
103 	case FBIO_GETWINORG:	/* get frame buffer window origin */
104 		*(u_int *)data = 0;
105 		break;
106 
107 	case FBIO_GETDISPSTART:	/* get display start address */
108 		((video_display_start_t *)data)->x = 0;
109 		((video_display_start_t *)data)->y = 0;
110 		break;
111 
112 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
113 		*(u_int *)data = info->fb_stride;
114 		break;
115 
116 	case FBIO_BLANK:	/* blank display */
117 		if (vd->vd_driver->vd_blank == NULL)
118 			return (ENODEV);
119 		vd->vd_driver->vd_blank(vd, TC_BLACK);
120 		break;
121 
122 	case FBIO_GETRGBOFFS:	/* get RGB offsets */
123 		if (info->fb_rgboffs.red == 0 && info->fb_rgboffs.green == 0 &&
124 		    info->fb_rgboffs.blue == 0)
125 			return (ENOTTY);
126 		memcpy((struct fb_rgboffs *)data, &info->fb_rgboffs,
127 		    sizeof(struct fb_rgboffs));
128 		break;
129 
130 	default:
131 		error = ENOIOCTL;
132 		break;
133 	}
134 
135 	return (error);
136 }
137 
138 int
139 vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
140     int prot, vm_memattr_t *memattr)
141 {
142 	struct fb_info *info;
143 
144 	info = vd->vd_softc;
145 
146 	if (info->fb_flags & FB_FLAG_NOMMAP)
147 		return (ENODEV);
148 
149 	if (offset < info->fb_size) {
150 		if (info->fb_pbase == 0) {
151 			*paddr = vtophys((uint8_t *)info->fb_vbase + offset);
152 		} else {
153 			*paddr = info->fb_pbase + offset;
154 			if (info->fb_flags & FB_FLAG_MEMATTR)
155 				*memattr = info->fb_memattr;
156 #ifdef VM_MEMATTR_WRITE_COMBINING
157 			else
158 				*memattr = VM_MEMATTR_WRITE_COMBINING;
159 #endif
160 		}
161 		return (0);
162 	}
163 
164 	return (EINVAL);
165 }
166 
167 void
168 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
169 {
170 	struct fb_info *info;
171 	uint32_t c;
172 	u_int o;
173 
174 	info = vd->vd_softc;
175 	c = info->fb_cmap[color];
176 	o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
177 
178 	if (info->fb_flags & FB_FLAG_NOWRITE)
179 		return;
180 
181 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
182 
183 	switch (FBTYPE_GET_BYTESPP(info)) {
184 	case 1:
185 		vt_fb_mem_wr1(info, o, c);
186 		break;
187 	case 2:
188 		vt_fb_mem_wr2(info, o, c);
189 		break;
190 	case 3:
191 		vt_fb_mem_wr1(info, o, (c >> 16) & 0xff);
192 		vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff);
193 		vt_fb_mem_wr1(info, o + 2, c & 0xff);
194 		break;
195 	case 4:
196 		vt_fb_mem_wr4(info, o, c);
197 		break;
198 	default:
199 		/* panic? */
200 		return;
201 	}
202 }
203 
204 void
205 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
206     term_color_t color)
207 {
208 	int x, y;
209 
210 	for (y = y1; y <= y2; y++) {
211 		if (fill || (y == y1) || (y == y2)) {
212 			for (x = x1; x <= x2; x++)
213 				vt_fb_setpixel(vd, x, y, color);
214 		} else {
215 			vt_fb_setpixel(vd, x1, y, color);
216 			vt_fb_setpixel(vd, x2, y, color);
217 		}
218 	}
219 }
220 
221 void
222 vt_fb_blank(struct vt_device *vd, term_color_t color)
223 {
224 	struct fb_info *info;
225 	uint32_t c;
226 	u_int o, h;
227 
228 	info = vd->vd_softc;
229 	c = info->fb_cmap[color];
230 
231 	if (info->fb_flags & FB_FLAG_NOWRITE)
232 		return;
233 
234 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
235 
236 	switch (FBTYPE_GET_BYTESPP(info)) {
237 	case 1:
238 		for (h = 0; h < info->fb_height; h++)
239 			for (o = 0; o < info->fb_stride; o++)
240 				vt_fb_mem_wr1(info, h*info->fb_stride + o, c);
241 		break;
242 	case 2:
243 		for (h = 0; h < info->fb_height; h++)
244 			for (o = 0; o < info->fb_stride - 1; o += 2)
245 				vt_fb_mem_wr2(info, h*info->fb_stride + o, c);
246 		break;
247 	case 3:
248 		for (h = 0; h < info->fb_height; h++)
249 			for (o = 0; o < info->fb_stride - 2; o += 3) {
250 				vt_fb_mem_wr1(info, h*info->fb_stride + o,
251 				    (c >> 16) & 0xff);
252 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 1,
253 				    (c >> 8) & 0xff);
254 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 2,
255 				    c & 0xff);
256 			}
257 		break;
258 	case 4:
259 		for (h = 0; h < info->fb_height; h++)
260 			for (o = 0; o < info->fb_stride - 3; o += 4)
261 				vt_fb_mem_wr4(info, h*info->fb_stride + o, c);
262 		break;
263 	default:
264 		/* panic? */
265 		return;
266 	}
267 }
268 
269 void
270 vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
271     const uint8_t *pattern, const uint8_t *mask,
272     unsigned int width, unsigned int height,
273     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
274 {
275 	struct fb_info *info;
276 	uint32_t fgc, bgc, cc, o;
277 	int bpp, bpl, xi, yi;
278 	int bit, byte;
279 
280 	info = vd->vd_softc;
281 	bpp = FBTYPE_GET_BYTESPP(info);
282 	fgc = info->fb_cmap[fg];
283 	bgc = info->fb_cmap[bg];
284 	bpl = (width + 7) / 8; /* Bytes per source line. */
285 
286 	if (info->fb_flags & FB_FLAG_NOWRITE)
287 		return;
288 
289 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
290 
291 	/* Bound by right and bottom edges. */
292 	if (y + height > vw->vw_draw_area.tr_end.tp_row) {
293 		if (y >= vw->vw_draw_area.tr_end.tp_row)
294 			return;
295 		height = vw->vw_draw_area.tr_end.tp_row - y;
296 	}
297 	if (x + width > vw->vw_draw_area.tr_end.tp_col) {
298 		if (x >= vw->vw_draw_area.tr_end.tp_col)
299 			return;
300 		width = vw->vw_draw_area.tr_end.tp_col - x;
301 	}
302 	for (yi = 0; yi < height; yi++) {
303 		for (xi = 0; xi < width; xi++) {
304 			byte = yi * bpl + xi / 8;
305 			bit = 0x80 >> (xi % 8);
306 			/* Skip pixel write, if mask bit not set. */
307 			if (mask != NULL && (mask[byte] & bit) == 0)
308 				continue;
309 			o = (y + yi) * info->fb_stride + (x + xi) * bpp;
310 			o += vd->vd_transpose;
311 			cc = pattern[byte] & bit ? fgc : bgc;
312 
313 			switch(bpp) {
314 			case 1:
315 				vt_fb_mem_wr1(info, o, cc);
316 				break;
317 			case 2:
318 				vt_fb_mem_wr2(info, o, cc);
319 				break;
320 			case 3:
321 				/* Packed mode, so unaligned. Byte access. */
322 				vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff);
323 				vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff);
324 				vt_fb_mem_wr1(info, o + 2, cc & 0xff);
325 				break;
326 			case 4:
327 				vt_fb_mem_wr4(info, o, cc);
328 				break;
329 			default:
330 				/* panic? */
331 				break;
332 			}
333 		}
334 	}
335 }
336 
337 int
338 vt_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw,
339     const uint8_t *argb,
340     unsigned int width, unsigned int height,
341   unsigned int x, unsigned int y)
342 {
343 	struct fb_info *info;
344 	uint32_t o, cc;
345 	int bpp, xi, yi;
346 
347 	info = vd->vd_softc;
348 	bpp = FBTYPE_GET_BYTESPP(info);
349 	if (bpp != 4)
350 		return (EOPNOTSUPP);
351 
352 	if (info->fb_flags & FB_FLAG_NOWRITE)
353 		return (0);
354 
355 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
356 
357 	/* Bound by right and bottom edges. */
358 	if (y + height > vw->vw_draw_area.tr_end.tp_row) {
359 		if (y >= vw->vw_draw_area.tr_end.tp_row)
360 			return (EINVAL);
361 		height = vw->vw_draw_area.tr_end.tp_row - y;
362 	}
363 	if (x + width > vw->vw_draw_area.tr_end.tp_col) {
364 		if (x >= vw->vw_draw_area.tr_end.tp_col)
365 			return (EINVAL);
366 		width = vw->vw_draw_area.tr_end.tp_col - x;
367 	}
368 	for (yi = 0; yi < height; yi++) {
369 		for (xi = 0; xi < (width * 4); xi += 4) {
370 			o = (y + yi) * info->fb_stride + (x + (xi / 4)) * bpp;
371 			o += vd->vd_transpose;
372 			cc = (argb[yi * width * 4 + xi] << 16) |
373 				(argb[yi * width * 4 + xi + 1] << 8) |
374 				(argb[yi * width * 4 + xi + 2]) |
375 				(argb[yi * width * 4 + xi + 3] << 24);
376 			vt_fb_mem_wr4(info, o, cc);
377 		}
378 	}
379 
380 	return (0);
381 }
382 
383 void
384 vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
385     const term_rect_t *area)
386 {
387 	unsigned int col, row, x, y;
388 	struct vt_font *vf;
389 	term_char_t c;
390 	term_color_t fg, bg;
391 	const uint8_t *pattern;
392 	size_t z;
393 
394 	vf = vw->vw_font;
395 
396 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
397 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
398 		    ++col) {
399 			x = col * vf->vf_width +
400 			    vw->vw_draw_area.tr_begin.tp_col;
401 			y = row * vf->vf_height +
402 			    vw->vw_draw_area.tr_begin.tp_row;
403 
404 			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
405 			pattern = vtfont_lookup(vf, c);
406 			vt_determine_colors(c,
407 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
408 
409 			z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
410 			if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) *
411 			    PIXEL_WIDTH(VT_FB_MAX_WIDTH))
412 				continue;
413 			if (vd->vd_drawn && (vd->vd_drawn[z] == c) &&
414 			    vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) &&
415 			    vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg))
416 				continue;
417 
418 			vt_fb_bitblt_bitmap(vd, vw,
419 			    pattern, NULL, vf->vf_width, vf->vf_height,
420 			    x, y, fg, bg);
421 
422 			if (vd->vd_drawn)
423 				vd->vd_drawn[z] = c;
424 			if (vd->vd_drawnfg)
425 				vd->vd_drawnfg[z] = fg;
426 			if (vd->vd_drawnbg)
427 				vd->vd_drawnbg[z] = bg;
428 		}
429 	}
430 
431 #ifndef SC_NO_CUTPASTE
432 	if (!vd->vd_mshown)
433 		return;
434 
435 	term_rect_t drawn_area;
436 
437 	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
438 	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
439 	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
440 	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
441 
442 	if (vt_is_cursor_in_area(vd, &drawn_area)) {
443 		vt_fb_bitblt_bitmap(vd, vw,
444 		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
445 		    vd->vd_mcursor->width, vd->vd_mcursor->height,
446 		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
447 		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
448 		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
449 	}
450 #endif
451 }
452 
453 void
454 vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area)
455 {
456 	unsigned int col, row;
457 	size_t z;
458 
459 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
460 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
461 		    ++col) {
462 			z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
463 			if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) *
464 			    PIXEL_WIDTH(VT_FB_MAX_WIDTH))
465 				continue;
466 			if (vd->vd_drawn)
467 				vd->vd_drawn[z] = 0;
468 			if (vd->vd_drawnfg)
469 				vd->vd_drawnfg[z] = 0;
470 			if (vd->vd_drawnbg)
471 				vd->vd_drawnbg[z] = 0;
472 		}
473 	}
474 }
475 
476 void
477 vt_fb_postswitch(struct vt_device *vd)
478 {
479 	struct fb_info *info;
480 
481 	info = vd->vd_softc;
482 
483 	if (info->enter != NULL)
484 		info->enter(info->fb_priv);
485 }
486 
487 static int
488 vt_fb_init_colors(struct fb_info *info)
489 {
490 
491 	switch (FBTYPE_GET_BPP(info)) {
492 	case 8:
493 		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
494 		    0x7, 5, 0x7, 2, 0x3, 0));
495 	case 15:
496 		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
497 		    0x1f, 10, 0x1f, 5, 0x1f, 0));
498 	case 16:
499 		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
500 		    0x1f, 11, 0x3f, 5, 0x1f, 0));
501 	case 24:
502 	case 32: /* Ignore alpha. */
503 		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
504 		    0xff, 16, 0xff, 8, 0xff, 0));
505 	default:
506 		return (1);
507 	}
508 }
509 
510 int
511 vt_fb_init(struct vt_device *vd)
512 {
513 	struct fb_info *info;
514 	u_int margin;
515 	int bg, err;
516 	term_color_t c;
517 
518 	info = vd->vd_softc;
519 	vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height);
520 	margin = (info->fb_height - vd->vd_height) >> 1;
521 	vd->vd_transpose = margin * info->fb_stride;
522 	vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width);
523 	margin = (info->fb_width - vd->vd_width) >> 1;
524 	vd->vd_transpose += margin * (info->fb_bpp / NBBY);
525 	vd->vd_video_dev = info->fb_video_dev;
526 
527 	if (info->fb_size == 0)
528 		return (CN_DEAD);
529 
530 	if (info->fb_pbase == 0 && info->fb_vbase == 0)
531 		info->fb_flags |= FB_FLAG_NOMMAP;
532 
533 	if (info->fb_cmsize <= 0) {
534 		err = vt_fb_init_colors(info);
535 		if (err)
536 			return (CN_DEAD);
537 		info->fb_cmsize = 16;
538 	}
539 
540 	c = TC_BLACK;
541 	if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) {
542 		if (bg == TC_WHITE)
543 			bg |= TC_LIGHT;
544 		c = bg;
545 	}
546 	/* Clear the screen. */
547 	vd->vd_driver->vd_blank(vd, c);
548 
549 	/* Wakeup screen. KMS need this. */
550 	vt_fb_postswitch(vd);
551 
552 	return (CN_INTERNAL);
553 }
554 
555 void
556 vt_fb_fini(struct vt_device *vd, void *softc)
557 {
558 
559 	vd->vd_video_dev = NULL;
560 }
561 
562 int
563 vt_fb_attach(struct fb_info *info)
564 {
565 	int ret;
566 
567 	ret = vt_allocate(&vt_fb_driver, info);
568 
569 	return (ret);
570 }
571 
572 int
573 vt_fb_detach(struct fb_info *info)
574 {
575 	int ret;
576 
577 	ret = vt_deallocate(&vt_fb_driver, info);
578 
579 	return (ret);
580 }
581 
582 void
583 vt_fb_suspend(struct vt_device *vd)
584 {
585 
586 	vt_suspend(vd);
587 }
588 
589 void
590 vt_fb_resume(struct vt_device *vd)
591 {
592 
593 	vt_resume(vd);
594 }
595