xref: /freebsd/sys/dev/vt/hw/fb/vt_fb.c (revision 718cf2ccb9956613756ab15d7a0e28f2c8e91cab)
127cf7d04SAleksandr Rybalko /*-
2*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*718cf2ccSPedro F. Giffuni  *
427cf7d04SAleksandr Rybalko  * Copyright (c) 2013 The FreeBSD Foundation
527cf7d04SAleksandr Rybalko  * All rights reserved.
627cf7d04SAleksandr Rybalko  *
727cf7d04SAleksandr Rybalko  * This software was developed by Aleksandr Rybalko under sponsorship from the
827cf7d04SAleksandr Rybalko  * FreeBSD Foundation.
927cf7d04SAleksandr Rybalko  *
1027cf7d04SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
1127cf7d04SAleksandr Rybalko  * modification, are permitted provided that the following conditions
1227cf7d04SAleksandr Rybalko  * are met:
1327cf7d04SAleksandr Rybalko  * 1. Redistributions of source code must retain the above copyright
1427cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer.
1527cf7d04SAleksandr Rybalko  * 2. Redistributions in binary form must reproduce the above copyright
1627cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer in the
1727cf7d04SAleksandr Rybalko  *    documentation and/or other materials provided with the distribution.
1827cf7d04SAleksandr Rybalko  *
1927cf7d04SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2027cf7d04SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2127cf7d04SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2227cf7d04SAleksandr Rybalko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2327cf7d04SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2427cf7d04SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2527cf7d04SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2627cf7d04SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2727cf7d04SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2827cf7d04SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2927cf7d04SAleksandr Rybalko  * SUCH DAMAGE.
3027cf7d04SAleksandr Rybalko  */
3127cf7d04SAleksandr Rybalko 
3227cf7d04SAleksandr Rybalko #include <sys/cdefs.h>
3327cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$");
3427cf7d04SAleksandr Rybalko 
3527cf7d04SAleksandr Rybalko #include <sys/param.h>
3627cf7d04SAleksandr Rybalko #include <sys/systm.h>
3727cf7d04SAleksandr Rybalko #include <sys/malloc.h>
3827cf7d04SAleksandr Rybalko #include <sys/queue.h>
3927cf7d04SAleksandr Rybalko #include <sys/fbio.h>
4027cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
4127cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h>
4227cf7d04SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h>
4327cf7d04SAleksandr Rybalko 
44a985ae9bSHans Petter Selasky #include <vm/vm.h>
45a985ae9bSHans Petter Selasky #include <vm/pmap.h>
46a985ae9bSHans Petter Selasky 
4727cf7d04SAleksandr Rybalko static struct vt_driver vt_fb_driver = {
484dde1640SAleksandr Rybalko 	.vd_name = "fb",
4927cf7d04SAleksandr Rybalko 	.vd_init = vt_fb_init,
5076e2f976SJean-Sébastien Pédron 	.vd_fini = vt_fb_fini,
5127cf7d04SAleksandr Rybalko 	.vd_blank = vt_fb_blank,
52c285e4a5SJean-Sébastien Pédron 	.vd_bitblt_text = vt_fb_bitblt_text,
53631bb572SJean-Sébastien Pédron 	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
549e497e7bSAleksandr Rybalko 	.vd_drawrect = vt_fb_drawrect,
559e497e7bSAleksandr Rybalko 	.vd_setpixel = vt_fb_setpixel,
5627cf7d04SAleksandr Rybalko 	.vd_postswitch = vt_fb_postswitch,
5727cf7d04SAleksandr Rybalko 	.vd_priority = VD_PRIORITY_GENERIC+10,
587a1a32c4SAleksandr Rybalko 	.vd_fb_ioctl = vt_fb_ioctl,
597a1a32c4SAleksandr Rybalko 	.vd_fb_mmap = vt_fb_mmap,
606dfa4578SAndriy Gapon 	.vd_suspend = vt_fb_suspend,
616dfa4578SAndriy Gapon 	.vd_resume = vt_fb_resume,
6227cf7d04SAleksandr Rybalko };
6327cf7d04SAleksandr Rybalko 
644dde1640SAleksandr Rybalko VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
654dde1640SAleksandr Rybalko 
669ed297c8SNathan Whitehorn static void
679ed297c8SNathan Whitehorn vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
689ed297c8SNathan Whitehorn {
699ed297c8SNathan Whitehorn 
709ed297c8SNathan Whitehorn 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
719ed297c8SNathan Whitehorn 	*(uint8_t *)(sc->fb_vbase + o) = v;
729ed297c8SNathan Whitehorn }
739ed297c8SNathan Whitehorn 
749ed297c8SNathan Whitehorn static void
759ed297c8SNathan Whitehorn vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
769ed297c8SNathan Whitehorn {
779ed297c8SNathan Whitehorn 
789ed297c8SNathan Whitehorn 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
799ed297c8SNathan Whitehorn 	*(uint16_t *)(sc->fb_vbase + o) = v;
809ed297c8SNathan Whitehorn }
819ed297c8SNathan Whitehorn 
829ed297c8SNathan Whitehorn static void
839ed297c8SNathan Whitehorn vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
849ed297c8SNathan Whitehorn {
859ed297c8SNathan Whitehorn 
869ed297c8SNathan Whitehorn 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
879ed297c8SNathan Whitehorn 	*(uint32_t *)(sc->fb_vbase + o) = v;
889ed297c8SNathan Whitehorn }
899ed297c8SNathan Whitehorn 
9060d7ea3dSNathan Whitehorn int
917a1a32c4SAleksandr Rybalko vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
927a1a32c4SAleksandr Rybalko {
937a1a32c4SAleksandr Rybalko 	struct fb_info *info;
9460d7ea3dSNathan Whitehorn 	int error = 0;
957a1a32c4SAleksandr Rybalko 
967a1a32c4SAleksandr Rybalko 	info = vd->vd_softc;
977a1a32c4SAleksandr Rybalko 
9860d7ea3dSNathan Whitehorn 	switch (cmd) {
9960d7ea3dSNathan Whitehorn 	case FBIOGTYPE:
10060d7ea3dSNathan Whitehorn 		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
10160d7ea3dSNathan Whitehorn 		break;
1027a1a32c4SAleksandr Rybalko 
10360d7ea3dSNathan Whitehorn 	case FBIO_GETWINORG:	/* get frame buffer window origin */
10460d7ea3dSNathan Whitehorn 		*(u_int *)data = 0;
10560d7ea3dSNathan Whitehorn 		break;
10660d7ea3dSNathan Whitehorn 
10760d7ea3dSNathan Whitehorn 	case FBIO_GETDISPSTART:	/* get display start address */
10860d7ea3dSNathan Whitehorn 		((video_display_start_t *)data)->x = 0;
10960d7ea3dSNathan Whitehorn 		((video_display_start_t *)data)->y = 0;
11060d7ea3dSNathan Whitehorn 		break;
11160d7ea3dSNathan Whitehorn 
11260d7ea3dSNathan Whitehorn 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
11360d7ea3dSNathan Whitehorn 		*(u_int *)data = info->fb_stride;
11460d7ea3dSNathan Whitehorn 		break;
11560d7ea3dSNathan Whitehorn 
11660d7ea3dSNathan Whitehorn 	case FBIO_BLANK:	/* blank display */
11760d7ea3dSNathan Whitehorn 		if (vd->vd_driver->vd_blank == NULL)
11860d7ea3dSNathan Whitehorn 			return (ENODEV);
11960d7ea3dSNathan Whitehorn 		vd->vd_driver->vd_blank(vd, TC_BLACK);
12060d7ea3dSNathan Whitehorn 		break;
12160d7ea3dSNathan Whitehorn 
12260d7ea3dSNathan Whitehorn 	default:
12360d7ea3dSNathan Whitehorn 		error = ENOIOCTL;
12460d7ea3dSNathan Whitehorn 		break;
1257a1a32c4SAleksandr Rybalko 	}
1267a1a32c4SAleksandr Rybalko 
12760d7ea3dSNathan Whitehorn 	return (error);
12860d7ea3dSNathan Whitehorn }
12960d7ea3dSNathan Whitehorn 
13060d7ea3dSNathan Whitehorn int
1315beb07abSAleksandr Rybalko vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
1325beb07abSAleksandr Rybalko     int prot, vm_memattr_t *memattr)
1337a1a32c4SAleksandr Rybalko {
1347a1a32c4SAleksandr Rybalko 	struct fb_info *info;
1357a1a32c4SAleksandr Rybalko 
1367a1a32c4SAleksandr Rybalko 	info = vd->vd_softc;
1377a1a32c4SAleksandr Rybalko 
13860d7ea3dSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOMMAP)
13960d7ea3dSNathan Whitehorn 		return (ENODEV);
1407a1a32c4SAleksandr Rybalko 
14160d7ea3dSNathan Whitehorn 	if (offset >= 0 && offset < info->fb_size) {
142a985ae9bSHans Petter Selasky 		if (info->fb_pbase == 0) {
143a985ae9bSHans Petter Selasky 			*paddr = vtophys((uint8_t *)info->fb_vbase + offset);
144a985ae9bSHans Petter Selasky 		} else {
14560d7ea3dSNathan Whitehorn 			*paddr = info->fb_pbase + offset;
14660d7ea3dSNathan Whitehorn #ifdef VM_MEMATTR_WRITE_COMBINING
14760d7ea3dSNathan Whitehorn 			*memattr = VM_MEMATTR_WRITE_COMBINING;
14860d7ea3dSNathan Whitehorn #endif
149a985ae9bSHans Petter Selasky 		}
15060d7ea3dSNathan Whitehorn 		return (0);
15160d7ea3dSNathan Whitehorn 	}
15260d7ea3dSNathan Whitehorn 
15360d7ea3dSNathan Whitehorn 	return (EINVAL);
1547a1a32c4SAleksandr Rybalko }
1557a1a32c4SAleksandr Rybalko 
1561365d077SJean-Sébastien Pédron void
1579e497e7bSAleksandr Rybalko vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
1589e497e7bSAleksandr Rybalko {
1599e497e7bSAleksandr Rybalko 	struct fb_info *info;
1609e497e7bSAleksandr Rybalko 	uint32_t c;
1619e497e7bSAleksandr Rybalko 	u_int o;
1629e497e7bSAleksandr Rybalko 
1639e497e7bSAleksandr Rybalko 	info = vd->vd_softc;
1649e497e7bSAleksandr Rybalko 	c = info->fb_cmap[color];
1659e497e7bSAleksandr Rybalko 	o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
1669e497e7bSAleksandr Rybalko 
167f1d2752fSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOWRITE)
168f1d2752fSNathan Whitehorn 		return;
169f1d2752fSNathan Whitehorn 
1709ed297c8SNathan Whitehorn 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
1719ed297c8SNathan Whitehorn 
1729e497e7bSAleksandr Rybalko 	switch (FBTYPE_GET_BYTESPP(info)) {
1739e497e7bSAleksandr Rybalko 	case 1:
1749ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o, c);
1759e497e7bSAleksandr Rybalko 		break;
1769e497e7bSAleksandr Rybalko 	case 2:
1779ed297c8SNathan Whitehorn 		vt_fb_mem_wr2(info, o, c);
1789e497e7bSAleksandr Rybalko 		break;
1799e497e7bSAleksandr Rybalko 	case 3:
1809ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o, (c >> 16) & 0xff);
1819ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff);
1829ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o + 2, c & 0xff);
1839e497e7bSAleksandr Rybalko 		break;
1849e497e7bSAleksandr Rybalko 	case 4:
1859ed297c8SNathan Whitehorn 		vt_fb_mem_wr4(info, o, c);
1869e497e7bSAleksandr Rybalko 		break;
1879e497e7bSAleksandr Rybalko 	default:
1889e497e7bSAleksandr Rybalko 		/* panic? */
1899e497e7bSAleksandr Rybalko 		return;
1909e497e7bSAleksandr Rybalko 	}
1919e497e7bSAleksandr Rybalko }
1929e497e7bSAleksandr Rybalko 
1931365d077SJean-Sébastien Pédron void
1949e497e7bSAleksandr Rybalko vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
1959e497e7bSAleksandr Rybalko     term_color_t color)
1969e497e7bSAleksandr Rybalko {
1979e497e7bSAleksandr Rybalko 	int x, y;
1989e497e7bSAleksandr Rybalko 
1999e497e7bSAleksandr Rybalko 	for (y = y1; y <= y2; y++) {
2009e497e7bSAleksandr Rybalko 		if (fill || (y == y1) || (y == y2)) {
2019e497e7bSAleksandr Rybalko 			for (x = x1; x <= x2; x++)
2029e497e7bSAleksandr Rybalko 				vt_fb_setpixel(vd, x, y, color);
2039e497e7bSAleksandr Rybalko 		} else {
2049e497e7bSAleksandr Rybalko 			vt_fb_setpixel(vd, x1, y, color);
2059e497e7bSAleksandr Rybalko 			vt_fb_setpixel(vd, x2, y, color);
2069e497e7bSAleksandr Rybalko 		}
2079e497e7bSAleksandr Rybalko 	}
2089e497e7bSAleksandr Rybalko }
2099e497e7bSAleksandr Rybalko 
2109e497e7bSAleksandr Rybalko void
21127cf7d04SAleksandr Rybalko vt_fb_blank(struct vt_device *vd, term_color_t color)
21227cf7d04SAleksandr Rybalko {
21327cf7d04SAleksandr Rybalko 	struct fb_info *info;
21427cf7d04SAleksandr Rybalko 	uint32_t c;
21560d7ea3dSNathan Whitehorn 	u_int o, h;
21627cf7d04SAleksandr Rybalko 
21727cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
21827cf7d04SAleksandr Rybalko 	c = info->fb_cmap[color];
21927cf7d04SAleksandr Rybalko 
220f1d2752fSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOWRITE)
221f1d2752fSNathan Whitehorn 		return;
222f1d2752fSNathan Whitehorn 
2239ed297c8SNathan Whitehorn 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
2249ed297c8SNathan Whitehorn 
22527cf7d04SAleksandr Rybalko 	switch (FBTYPE_GET_BYTESPP(info)) {
22627cf7d04SAleksandr Rybalko 	case 1:
22735e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
22827cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o++)
2299ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o, c);
23027cf7d04SAleksandr Rybalko 		break;
23127cf7d04SAleksandr Rybalko 	case 2:
23235e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
23327cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o += 2)
2349ed297c8SNathan Whitehorn 				vt_fb_mem_wr2(info, h*info->fb_stride + o, c);
23527cf7d04SAleksandr Rybalko 		break;
23627cf7d04SAleksandr Rybalko 	case 3:
23735e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
23827cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o += 3) {
2399ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o,
24060d7ea3dSNathan Whitehorn 				    (c >> 16) & 0xff);
2419ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 1,
24260d7ea3dSNathan Whitehorn 				    (c >> 8) & 0xff);
2439ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 2,
24460d7ea3dSNathan Whitehorn 				    c & 0xff);
24527cf7d04SAleksandr Rybalko 			}
24627cf7d04SAleksandr Rybalko 		break;
24727cf7d04SAleksandr Rybalko 	case 4:
24835e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
24927cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o += 4)
2509ed297c8SNathan Whitehorn 				vt_fb_mem_wr4(info, h*info->fb_stride + o, c);
25127cf7d04SAleksandr Rybalko 		break;
25227cf7d04SAleksandr Rybalko 	default:
25327cf7d04SAleksandr Rybalko 		/* panic? */
25427cf7d04SAleksandr Rybalko 		return;
25527cf7d04SAleksandr Rybalko 	}
25627cf7d04SAleksandr Rybalko }
25727cf7d04SAleksandr Rybalko 
258631bb572SJean-Sébastien Pédron void
259c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
260c285e4a5SJean-Sébastien Pédron     const uint8_t *pattern, const uint8_t *mask,
261c285e4a5SJean-Sébastien Pédron     unsigned int width, unsigned int height,
262c285e4a5SJean-Sébastien Pédron     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
26327cf7d04SAleksandr Rybalko {
26427cf7d04SAleksandr Rybalko 	struct fb_info *info;
26527cf7d04SAleksandr Rybalko 	uint32_t fgc, bgc, cc, o;
2662c48063bSEd Maste 	int bpp, bpl, xi, yi;
2672c48063bSEd Maste 	int bit, byte;
26827cf7d04SAleksandr Rybalko 
26927cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
27027cf7d04SAleksandr Rybalko 	bpp = FBTYPE_GET_BYTESPP(info);
27127cf7d04SAleksandr Rybalko 	fgc = info->fb_cmap[fg];
27227cf7d04SAleksandr Rybalko 	bgc = info->fb_cmap[bg];
2732c48063bSEd Maste 	bpl = (width + 7) / 8; /* Bytes per source line. */
27427cf7d04SAleksandr Rybalko 
275f1d2752fSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOWRITE)
276f1d2752fSNathan Whitehorn 		return;
277f1d2752fSNathan Whitehorn 
2789ed297c8SNathan Whitehorn 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
2799ed297c8SNathan Whitehorn 
2802c48063bSEd Maste 	/* Bound by right and bottom edges. */
2812c48063bSEd Maste 	if (y + height > vw->vw_draw_area.tr_end.tp_row) {
2822c48063bSEd Maste 		if (y >= vw->vw_draw_area.tr_end.tp_row)
2832c48063bSEd Maste 			return;
2842c48063bSEd Maste 		height = vw->vw_draw_area.tr_end.tp_row - y;
28527cf7d04SAleksandr Rybalko 	}
2862c48063bSEd Maste 	if (x + width > vw->vw_draw_area.tr_end.tp_col) {
2872c48063bSEd Maste 		if (x >= vw->vw_draw_area.tr_end.tp_col)
2882c48063bSEd Maste 			return;
2892c48063bSEd Maste 		width = vw->vw_draw_area.tr_end.tp_col - x;
2902c48063bSEd Maste 	}
2912c48063bSEd Maste 	for (yi = 0; yi < height; yi++) {
2922c48063bSEd Maste 		for (xi = 0; xi < width; xi++) {
2932c48063bSEd Maste 			byte = yi * bpl + xi / 8;
2942c48063bSEd Maste 			bit = 0x80 >> (xi % 8);
2952c48063bSEd Maste 			/* Skip pixel write, if mask bit not set. */
2962c48063bSEd Maste 			if (mask != NULL && (mask[byte] & bit) == 0)
2972c48063bSEd Maste 				continue;
2982c48063bSEd Maste 			o = (y + yi) * info->fb_stride + (x + xi) * bpp;
299ec6b1f6aSMarcel Moolenaar 			o += vd->vd_transpose;
3002c48063bSEd Maste 			cc = pattern[byte] & bit ? fgc : bgc;
30127cf7d04SAleksandr Rybalko 
30227cf7d04SAleksandr Rybalko 			switch(bpp) {
30327cf7d04SAleksandr Rybalko 			case 1:
3049ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o, cc);
30527cf7d04SAleksandr Rybalko 				break;
30627cf7d04SAleksandr Rybalko 			case 2:
3079ed297c8SNathan Whitehorn 				vt_fb_mem_wr2(info, o, cc);
30827cf7d04SAleksandr Rybalko 				break;
30927cf7d04SAleksandr Rybalko 			case 3:
31027cf7d04SAleksandr Rybalko 				/* Packed mode, so unaligned. Byte access. */
3119ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff);
3129ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff);
3139ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o + 2, cc & 0xff);
31427cf7d04SAleksandr Rybalko 				break;
31527cf7d04SAleksandr Rybalko 			case 4:
3169ed297c8SNathan Whitehorn 				vt_fb_mem_wr4(info, o, cc);
31727cf7d04SAleksandr Rybalko 				break;
31827cf7d04SAleksandr Rybalko 			default:
31927cf7d04SAleksandr Rybalko 				/* panic? */
32027cf7d04SAleksandr Rybalko 				break;
32127cf7d04SAleksandr Rybalko 			}
32227cf7d04SAleksandr Rybalko 		}
32327cf7d04SAleksandr Rybalko 	}
32427cf7d04SAleksandr Rybalko }
32527cf7d04SAleksandr Rybalko 
32627cf7d04SAleksandr Rybalko void
327c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
328c285e4a5SJean-Sébastien Pédron     const term_rect_t *area)
329c285e4a5SJean-Sébastien Pédron {
330c285e4a5SJean-Sébastien Pédron 	unsigned int col, row, x, y;
331c285e4a5SJean-Sébastien Pédron 	struct vt_font *vf;
332c285e4a5SJean-Sébastien Pédron 	term_char_t c;
333c285e4a5SJean-Sébastien Pédron 	term_color_t fg, bg;
334c285e4a5SJean-Sébastien Pédron 	const uint8_t *pattern;
335c285e4a5SJean-Sébastien Pédron 
336c285e4a5SJean-Sébastien Pédron 	vf = vw->vw_font;
337c285e4a5SJean-Sébastien Pédron 
338c285e4a5SJean-Sébastien Pédron 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
339c285e4a5SJean-Sébastien Pédron 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
340c285e4a5SJean-Sébastien Pédron 		    ++col) {
34183fbb296SJean-Sébastien Pédron 			x = col * vf->vf_width +
34283fbb296SJean-Sébastien Pédron 			    vw->vw_draw_area.tr_begin.tp_col;
34383fbb296SJean-Sébastien Pédron 			y = row * vf->vf_height +
34483fbb296SJean-Sébastien Pédron 			    vw->vw_draw_area.tr_begin.tp_row;
345c285e4a5SJean-Sébastien Pédron 
346c285e4a5SJean-Sébastien Pédron 			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
347c285e4a5SJean-Sébastien Pédron 			pattern = vtfont_lookup(vf, c);
348c285e4a5SJean-Sébastien Pédron 			vt_determine_colors(c,
349c285e4a5SJean-Sébastien Pédron 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
350c285e4a5SJean-Sébastien Pédron 
351c285e4a5SJean-Sébastien Pédron 			vt_fb_bitblt_bitmap(vd, vw,
352c285e4a5SJean-Sébastien Pédron 			    pattern, NULL, vf->vf_width, vf->vf_height,
353c285e4a5SJean-Sébastien Pédron 			    x, y, fg, bg);
354c285e4a5SJean-Sébastien Pédron 		}
355c285e4a5SJean-Sébastien Pédron 	}
356c285e4a5SJean-Sébastien Pédron 
357c285e4a5SJean-Sébastien Pédron #ifndef SC_NO_CUTPASTE
358c285e4a5SJean-Sébastien Pédron 	if (!vd->vd_mshown)
359c285e4a5SJean-Sébastien Pédron 		return;
360c285e4a5SJean-Sébastien Pédron 
361c285e4a5SJean-Sébastien Pédron 	term_rect_t drawn_area;
362c285e4a5SJean-Sébastien Pédron 
36384d623c6SJean-Sébastien Pédron 	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
36484d623c6SJean-Sébastien Pédron 	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
36584d623c6SJean-Sébastien Pédron 	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
36684d623c6SJean-Sébastien Pédron 	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
367c285e4a5SJean-Sébastien Pédron 
368c285e4a5SJean-Sébastien Pédron 	if (vt_is_cursor_in_area(vd, &drawn_area)) {
369c285e4a5SJean-Sébastien Pédron 		vt_fb_bitblt_bitmap(vd, vw,
370c285e4a5SJean-Sébastien Pédron 		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
371c285e4a5SJean-Sébastien Pédron 		    vd->vd_mcursor->width, vd->vd_mcursor->height,
37284d623c6SJean-Sébastien Pédron 		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
37384d623c6SJean-Sébastien Pédron 		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
374c285e4a5SJean-Sébastien Pédron 		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
375c285e4a5SJean-Sébastien Pédron 	}
376c285e4a5SJean-Sébastien Pédron #endif
377c285e4a5SJean-Sébastien Pédron }
378c285e4a5SJean-Sébastien Pédron 
379c285e4a5SJean-Sébastien Pédron void
38027cf7d04SAleksandr Rybalko vt_fb_postswitch(struct vt_device *vd)
38127cf7d04SAleksandr Rybalko {
38227cf7d04SAleksandr Rybalko 	struct fb_info *info;
38327cf7d04SAleksandr Rybalko 
38427cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
38527cf7d04SAleksandr Rybalko 
38627cf7d04SAleksandr Rybalko 	if (info->enter != NULL)
38727cf7d04SAleksandr Rybalko 		info->enter(info->fb_priv);
38827cf7d04SAleksandr Rybalko }
38927cf7d04SAleksandr Rybalko 
39027cf7d04SAleksandr Rybalko static int
39127cf7d04SAleksandr Rybalko vt_fb_init_cmap(uint32_t *cmap, int depth)
39227cf7d04SAleksandr Rybalko {
39327cf7d04SAleksandr Rybalko 
39427cf7d04SAleksandr Rybalko 	switch (depth) {
39527cf7d04SAleksandr Rybalko 	case 8:
39619e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
39727cf7d04SAleksandr Rybalko 		    0x7, 5, 0x7, 2, 0x3, 0));
39827cf7d04SAleksandr Rybalko 	case 15:
39919e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
40027cf7d04SAleksandr Rybalko 		    0x1f, 10, 0x1f, 5, 0x1f, 0));
40127cf7d04SAleksandr Rybalko 	case 16:
40219e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
40327cf7d04SAleksandr Rybalko 		    0x1f, 11, 0x3f, 5, 0x1f, 0));
40427cf7d04SAleksandr Rybalko 	case 24:
40527cf7d04SAleksandr Rybalko 	case 32: /* Ignore alpha. */
40619e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
40719e2ce2dSJean-Sébastien Pédron 		    0xff, 16, 0xff, 8, 0xff, 0));
40827cf7d04SAleksandr Rybalko 	default:
40927cf7d04SAleksandr Rybalko 		return (1);
41027cf7d04SAleksandr Rybalko 	}
41127cf7d04SAleksandr Rybalko }
41227cf7d04SAleksandr Rybalko 
41327cf7d04SAleksandr Rybalko int
41427cf7d04SAleksandr Rybalko vt_fb_init(struct vt_device *vd)
41527cf7d04SAleksandr Rybalko {
41627cf7d04SAleksandr Rybalko 	struct fb_info *info;
417ec6b1f6aSMarcel Moolenaar 	u_int margin;
41827cf7d04SAleksandr Rybalko 	int err;
41927cf7d04SAleksandr Rybalko 
42027cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
421f41bde66SConrad Meyer 	vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height);
422ec6b1f6aSMarcel Moolenaar 	margin = (info->fb_height - vd->vd_height) >> 1;
423ec6b1f6aSMarcel Moolenaar 	vd->vd_transpose = margin * info->fb_stride;
424f41bde66SConrad Meyer 	vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width);
425ec6b1f6aSMarcel Moolenaar 	margin = (info->fb_width - vd->vd_width) >> 1;
426ec6b1f6aSMarcel Moolenaar 	vd->vd_transpose += margin * (info->fb_bpp / NBBY);
42776e2f976SJean-Sébastien Pédron 	vd->vd_video_dev = info->fb_video_dev;
42827cf7d04SAleksandr Rybalko 
4299ed297c8SNathan Whitehorn 	if (info->fb_size == 0)
4309ed297c8SNathan Whitehorn 		return (CN_DEAD);
4319ed297c8SNathan Whitehorn 
432a985ae9bSHans Petter Selasky 	if (info->fb_pbase == 0 && info->fb_vbase == 0)
4339ed297c8SNathan Whitehorn 		info->fb_flags |= FB_FLAG_NOMMAP;
4349ed297c8SNathan Whitehorn 
43527cf7d04SAleksandr Rybalko 	if (info->fb_cmsize <= 0) {
43627cf7d04SAleksandr Rybalko 		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
43727cf7d04SAleksandr Rybalko 		if (err)
43827cf7d04SAleksandr Rybalko 			return (CN_DEAD);
43927cf7d04SAleksandr Rybalko 		info->fb_cmsize = 16;
44027cf7d04SAleksandr Rybalko 	}
44127cf7d04SAleksandr Rybalko 
44227cf7d04SAleksandr Rybalko 	/* Clear the screen. */
4432661dd32SNathan Whitehorn 	vd->vd_driver->vd_blank(vd, TC_BLACK);
44427cf7d04SAleksandr Rybalko 
44527cf7d04SAleksandr Rybalko 	/* Wakeup screen. KMS need this. */
44627cf7d04SAleksandr Rybalko 	vt_fb_postswitch(vd);
44727cf7d04SAleksandr Rybalko 
44827cf7d04SAleksandr Rybalko 	return (CN_INTERNAL);
44927cf7d04SAleksandr Rybalko }
45027cf7d04SAleksandr Rybalko 
45176e2f976SJean-Sébastien Pédron void
45276e2f976SJean-Sébastien Pédron vt_fb_fini(struct vt_device *vd, void *softc)
45376e2f976SJean-Sébastien Pédron {
45476e2f976SJean-Sébastien Pédron 
45576e2f976SJean-Sébastien Pédron 	vd->vd_video_dev = NULL;
45676e2f976SJean-Sébastien Pédron }
45776e2f976SJean-Sébastien Pédron 
45827cf7d04SAleksandr Rybalko int
45927cf7d04SAleksandr Rybalko vt_fb_attach(struct fb_info *info)
46027cf7d04SAleksandr Rybalko {
46127cf7d04SAleksandr Rybalko 
46227cf7d04SAleksandr Rybalko 	vt_allocate(&vt_fb_driver, info);
46327cf7d04SAleksandr Rybalko 
46427cf7d04SAleksandr Rybalko 	return (0);
46527cf7d04SAleksandr Rybalko }
46627cf7d04SAleksandr Rybalko 
46776e2f976SJean-Sébastien Pédron int
46876e2f976SJean-Sébastien Pédron vt_fb_detach(struct fb_info *info)
46976e2f976SJean-Sébastien Pédron {
47076e2f976SJean-Sébastien Pédron 
47176e2f976SJean-Sébastien Pédron 	vt_deallocate(&vt_fb_driver, info);
47276e2f976SJean-Sébastien Pédron 
47376e2f976SJean-Sébastien Pédron 	return (0);
47476e2f976SJean-Sébastien Pédron }
47576e2f976SJean-Sébastien Pédron 
47627cf7d04SAleksandr Rybalko void
4776dfa4578SAndriy Gapon vt_fb_suspend(struct vt_device *vd)
47827cf7d04SAleksandr Rybalko {
47927cf7d04SAleksandr Rybalko 
4806dfa4578SAndriy Gapon 	vt_suspend(vd);
48127cf7d04SAleksandr Rybalko }
48227cf7d04SAleksandr Rybalko 
48327cf7d04SAleksandr Rybalko void
4846dfa4578SAndriy Gapon vt_fb_resume(struct vt_device *vd)
48527cf7d04SAleksandr Rybalko {
48627cf7d04SAleksandr Rybalko 
4876dfa4578SAndriy Gapon 	vt_resume(vd);
48827cf7d04SAleksandr Rybalko }
489