xref: /trueos/sys/dev/vt/hw/fb/vt_fb.c (revision 5868f7205430cd67aa3b655419d3f15f83b70119)
1 /*-
2  * Copyright (c) 2013 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Aleksandr Rybalko under sponsorship from the
6  * FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/queue.h>
39 #include <sys/fbio.h>
40 #include <dev/vt/vt.h>
41 #include <dev/vt/hw/fb/vt_fb.h>
42 #include <dev/vt/colors/vt_termcolors.h>
43 
44 static struct vt_driver vt_fb_driver = {
45 	.vd_name = "fb",
46 	.vd_init = vt_fb_init,
47 	.vd_blank = vt_fb_blank,
48 	.vd_bitblt_text = vt_fb_bitblt_text,
49 	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
50 	.vd_drawrect = vt_fb_drawrect,
51 	.vd_setpixel = vt_fb_setpixel,
52 	.vd_postswitch = vt_fb_postswitch,
53 	.vd_priority = VD_PRIORITY_GENERIC+10,
54 	.vd_fb_ioctl = vt_fb_ioctl,
55 	.vd_fb_mmap = vt_fb_mmap,
56 	.vd_suspend = vt_fb_suspend,
57 	.vd_resume = vt_fb_resume,
58 };
59 
60 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
61 
62 static void
vt_fb_mem_wr1(struct fb_info * sc,uint32_t o,uint8_t v)63 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
64 {
65 
66 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
67 	*(uint8_t *)(sc->fb_vbase + o) = v;
68 }
69 
70 static void
vt_fb_mem_wr2(struct fb_info * sc,uint32_t o,uint16_t v)71 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
72 {
73 
74 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
75 	*(uint16_t *)(sc->fb_vbase + o) = v;
76 }
77 
78 static void
vt_fb_mem_wr4(struct fb_info * sc,uint32_t o,uint32_t v)79 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
80 {
81 
82 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
83 	*(uint32_t *)(sc->fb_vbase + o) = v;
84 }
85 
86 int
vt_fb_ioctl(struct vt_device * vd,u_long cmd,caddr_t data,struct thread * td)87 vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
88 {
89 	struct fb_info *info;
90 	int error = 0;
91 
92 	info = vd->vd_softc;
93 
94 	switch (cmd) {
95 	case FBIOGTYPE:
96 		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
97 		break;
98 
99 	case FBIO_GETWINORG:	/* get frame buffer window origin */
100 		*(u_int *)data = 0;
101 		break;
102 
103 	case FBIO_GETDISPSTART:	/* get display start address */
104 		((video_display_start_t *)data)->x = 0;
105 		((video_display_start_t *)data)->y = 0;
106 		break;
107 
108 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
109 		*(u_int *)data = info->fb_stride;
110 		break;
111 
112 	case FBIO_BLANK:	/* blank display */
113 		if (vd->vd_driver->vd_blank == NULL)
114 			return (ENODEV);
115 		vd->vd_driver->vd_blank(vd, TC_BLACK);
116 		break;
117 
118 	default:
119 		error = ENOIOCTL;
120 		break;
121 	}
122 
123 	return (error);
124 }
125 
126 int
vt_fb_mmap(struct vt_device * vd,vm_ooffset_t offset,vm_paddr_t * paddr,int prot,vm_memattr_t * memattr)127 vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
128     int prot, vm_memattr_t *memattr)
129 {
130 	struct fb_info *info;
131 
132 	info = vd->vd_softc;
133 
134 	if (info->fb_flags & FB_FLAG_NOMMAP)
135 		return (ENODEV);
136 
137 	if (offset >= 0 && offset < info->fb_size) {
138 		*paddr = info->fb_pbase + offset;
139 	#ifdef VM_MEMATTR_WRITE_COMBINING
140 		*memattr = VM_MEMATTR_WRITE_COMBINING;
141 	#endif
142 		return (0);
143 	}
144 
145 	return (EINVAL);
146 }
147 
148 void
vt_fb_setpixel(struct vt_device * vd,int x,int y,term_color_t color)149 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
150 {
151 	struct fb_info *info;
152 	uint32_t c;
153 	u_int o;
154 
155 	info = vd->vd_softc;
156 	c = info->fb_cmap[color];
157 	o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
158 
159 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
160 
161 	switch (FBTYPE_GET_BYTESPP(info)) {
162 	case 1:
163 		vt_fb_mem_wr1(info, o, c);
164 		break;
165 	case 2:
166 		vt_fb_mem_wr2(info, o, c);
167 		break;
168 	case 3:
169 		vt_fb_mem_wr1(info, o, (c >> 16) & 0xff);
170 		vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff);
171 		vt_fb_mem_wr1(info, o + 2, c & 0xff);
172 		break;
173 	case 4:
174 		vt_fb_mem_wr4(info, o, c);
175 		break;
176 	default:
177 		/* panic? */
178 		return;
179 	}
180 
181 }
182 
183 void
vt_fb_drawrect(struct vt_device * vd,int x1,int y1,int x2,int y2,int fill,term_color_t color)184 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
185     term_color_t color)
186 {
187 	int x, y;
188 
189 	for (y = y1; y <= y2; y++) {
190 		if (fill || (y == y1) || (y == y2)) {
191 			for (x = x1; x <= x2; x++)
192 				vt_fb_setpixel(vd, x, y, color);
193 		} else {
194 			vt_fb_setpixel(vd, x1, y, color);
195 			vt_fb_setpixel(vd, x2, y, color);
196 		}
197 	}
198 }
199 
200 void
vt_fb_blank(struct vt_device * vd,term_color_t color)201 vt_fb_blank(struct vt_device *vd, term_color_t color)
202 {
203 	struct fb_info *info;
204 	uint32_t c;
205 	u_int o, h;
206 
207 	info = vd->vd_softc;
208 	c = info->fb_cmap[color];
209 
210 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
211 
212 	switch (FBTYPE_GET_BYTESPP(info)) {
213 	case 1:
214 		for (h = 0; h < info->fb_height; h++)
215 			for (o = 0; o < info->fb_stride; o++)
216 				vt_fb_mem_wr1(info, h*info->fb_stride + o, c);
217 		break;
218 	case 2:
219 		for (h = 0; h < info->fb_height; h++)
220 			for (o = 0; o < info->fb_stride; o += 2)
221 				vt_fb_mem_wr2(info, h*info->fb_stride + o, c);
222 		break;
223 	case 3:
224 		for (h = 0; h < info->fb_height; h++)
225 			for (o = 0; o < info->fb_stride; o += 3) {
226 				vt_fb_mem_wr1(info, h*info->fb_stride + o,
227 				    (c >> 16) & 0xff);
228 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 1,
229 				    (c >> 8) & 0xff);
230 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 2,
231 				    c & 0xff);
232 			}
233 		break;
234 	case 4:
235 		for (h = 0; h < info->fb_height; h++)
236 			for (o = 0; o < info->fb_stride; o += 4)
237 				vt_fb_mem_wr4(info, h*info->fb_stride + o, c);
238 		break;
239 	default:
240 		/* panic? */
241 		return;
242 	}
243 }
244 
245 void
vt_fb_bitblt_bitmap(struct vt_device * vd,const struct vt_window * vw,const uint8_t * pattern,const uint8_t * mask,unsigned int width,unsigned int height,unsigned int x,unsigned int y,term_color_t fg,term_color_t bg)246 vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
247     const uint8_t *pattern, const uint8_t *mask,
248     unsigned int width, unsigned int height,
249     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
250 {
251 	struct fb_info *info;
252 	uint32_t fgc, bgc, cc, o;
253 	int bpp, bpl, xi, yi;
254 	int bit, byte;
255 
256 	info = vd->vd_softc;
257 	bpp = FBTYPE_GET_BYTESPP(info);
258 	fgc = info->fb_cmap[fg];
259 	bgc = info->fb_cmap[bg];
260 	bpl = (width + 7) / 8; /* Bytes per source line. */
261 
262 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
263 
264 	/* Bound by right and bottom edges. */
265 	if (y + height > vw->vw_draw_area.tr_end.tp_row) {
266 		if (y >= vw->vw_draw_area.tr_end.tp_row)
267 			return;
268 		height = vw->vw_draw_area.tr_end.tp_row - y;
269 	}
270 	if (x + width > vw->vw_draw_area.tr_end.tp_col) {
271 		if (x >= vw->vw_draw_area.tr_end.tp_col)
272 			return;
273 		width = vw->vw_draw_area.tr_end.tp_col - x;
274 	}
275 	for (yi = 0; yi < height; yi++) {
276 		for (xi = 0; xi < width; xi++) {
277 			byte = yi * bpl + xi / 8;
278 			bit = 0x80 >> (xi % 8);
279 			/* Skip pixel write, if mask bit not set. */
280 			if (mask != NULL && (mask[byte] & bit) == 0)
281 				continue;
282 			o = (y + yi) * info->fb_stride + (x + xi) * bpp;
283 			cc = pattern[byte] & bit ? fgc : bgc;
284 
285 			switch(bpp) {
286 			case 1:
287 				vt_fb_mem_wr1(info, o, cc);
288 				break;
289 			case 2:
290 				vt_fb_mem_wr2(info, o, cc);
291 				break;
292 			case 3:
293 				/* Packed mode, so unaligned. Byte access. */
294 				vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff);
295 				vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff);
296 				vt_fb_mem_wr1(info, o + 2, cc & 0xff);
297 				break;
298 			case 4:
299 				vt_fb_mem_wr4(info, o, cc);
300 				break;
301 			default:
302 				/* panic? */
303 				break;
304 			}
305 		}
306 	}
307 }
308 
309 void
vt_fb_bitblt_text(struct vt_device * vd,const struct vt_window * vw,const term_rect_t * area)310 vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
311     const term_rect_t *area)
312 {
313 	unsigned int col, row, x, y;
314 	struct vt_font *vf;
315 	term_char_t c;
316 	term_color_t fg, bg;
317 	const uint8_t *pattern;
318 
319 	vf = vw->vw_font;
320 
321 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
322 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
323 		    ++col) {
324 			x = col * vf->vf_width +
325 			    vw->vw_draw_area.tr_begin.tp_col;
326 			y = row * vf->vf_height +
327 			    vw->vw_draw_area.tr_begin.tp_row;
328 
329 			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
330 			pattern = vtfont_lookup(vf, c);
331 			vt_determine_colors(c,
332 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
333 
334 			vt_fb_bitblt_bitmap(vd, vw,
335 			    pattern, NULL, vf->vf_width, vf->vf_height,
336 			    x, y, fg, bg);
337 		}
338 	}
339 
340 #ifndef SC_NO_CUTPASTE
341 	if (!vd->vd_mshown)
342 		return;
343 
344 	term_rect_t drawn_area;
345 
346 	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
347 	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
348 	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
349 	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
350 
351 	if (vt_is_cursor_in_area(vd, &drawn_area)) {
352 		vt_fb_bitblt_bitmap(vd, vw,
353 		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
354 		    vd->vd_mcursor->width, vd->vd_mcursor->height,
355 		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
356 		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
357 		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
358 	}
359 #endif
360 }
361 
362 void
vt_fb_postswitch(struct vt_device * vd)363 vt_fb_postswitch(struct vt_device *vd)
364 {
365 	struct fb_info *info;
366 
367 	info = vd->vd_softc;
368 
369 	if (info->enter != NULL)
370 		info->enter(info->fb_priv);
371 }
372 
373 static int
vt_fb_init_cmap(uint32_t * cmap,int depth)374 vt_fb_init_cmap(uint32_t *cmap, int depth)
375 {
376 
377 	switch (depth) {
378 	case 8:
379 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
380 		    0x7, 5, 0x7, 2, 0x3, 0));
381 	case 15:
382 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
383 		    0x1f, 10, 0x1f, 5, 0x1f, 0));
384 	case 16:
385 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
386 		    0x1f, 11, 0x3f, 5, 0x1f, 0));
387 	case 24:
388 	case 32: /* Ignore alpha. */
389 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
390 		    0xff, 16, 0xff, 8, 0xff, 0));
391 	default:
392 		return (1);
393 	}
394 }
395 
396 int
vt_fb_init(struct vt_device * vd)397 vt_fb_init(struct vt_device *vd)
398 {
399 	struct fb_info *info;
400 	int err;
401 
402 	info = vd->vd_softc;
403 	vd->vd_height = info->fb_height;
404 	vd->vd_width = info->fb_width;
405 
406 	if (info->fb_size == 0)
407 		return (CN_DEAD);
408 
409 	if (info->fb_pbase == 0)
410 		info->fb_flags |= FB_FLAG_NOMMAP;
411 
412 	if (info->fb_cmsize <= 0) {
413 		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
414 		if (err)
415 			return (CN_DEAD);
416 		info->fb_cmsize = 16;
417 	}
418 
419 	/* Clear the screen. */
420 	vd->vd_driver->vd_blank(vd, TC_BLACK);
421 
422 	/* Wakeup screen. KMS need this. */
423 	vt_fb_postswitch(vd);
424 
425 	return (CN_INTERNAL);
426 }
427 
428 int
vt_fb_attach(struct fb_info * info)429 vt_fb_attach(struct fb_info *info)
430 {
431 
432 	vt_allocate(&vt_fb_driver, info);
433 
434 	return (0);
435 }
436 
437 void
vt_fb_suspend(struct vt_device * vd)438 vt_fb_suspend(struct vt_device *vd)
439 {
440 
441 	vt_suspend(vd);
442 }
443 
444 void
vt_fb_resume(struct vt_device * vd)445 vt_fb_resume(struct vt_device *vd)
446 {
447 
448 	vt_resume(vd);
449 }
450