vt_fb.c revision 269437
1256904Sray/*-
2256904Sray * Copyright (c) 2013 The FreeBSD Foundation
3256904Sray * All rights reserved.
4256904Sray *
5256904Sray * This software was developed by Aleksandr Rybalko under sponsorship from the
6256904Sray * FreeBSD Foundation.
7256904Sray *
8256904Sray * Redistribution and use in source and binary forms, with or without
9256904Sray * modification, are permitted provided that the following conditions
10256904Sray * are met:
11256904Sray * 1. Redistributions of source code must retain the above copyright
12256904Sray *    notice, this list of conditions and the following disclaimer.
13256904Sray * 2. Redistributions in binary form must reproduce the above copyright
14256904Sray *    notice, this list of conditions and the following disclaimer in the
15256904Sray *    documentation and/or other materials provided with the distribution.
16256904Sray *
17256904Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18256904Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19256904Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20256904Sray * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21256904Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22256904Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23256904Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24256904Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25256904Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26256904Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27256904Sray * SUCH DAMAGE.
28256904Sray *
29256904Sray * $FreeBSD: head/sys/dev/vt/hw/fb/vt_fb.c 269437 2014-08-02 17:45:08Z nwhitehorn $
30256904Sray */
31256904Sray
32256904Sray#include <sys/cdefs.h>
33256904Sray__FBSDID("$FreeBSD: head/sys/dev/vt/hw/fb/vt_fb.c 269437 2014-08-02 17:45:08Z nwhitehorn $");
34256904Sray
35256904Sray#include <sys/param.h>
36256904Sray#include <sys/systm.h>
37256904Sray#include <sys/malloc.h>
38256904Sray#include <sys/queue.h>
39256904Sray#include <sys/fbio.h>
40256904Sray#include <dev/vt/vt.h>
41256904Sray#include <dev/vt/hw/fb/vt_fb.h>
42256904Sray#include <dev/vt/colors/vt_termcolors.h>
43256904Sray
44261552Srayvoid vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2,
45261552Sray    int fill, term_color_t color);
46261552Srayvoid vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color);
47259777Sray
48256904Sraystatic struct vt_driver vt_fb_driver = {
49265397Sray	.vd_name = "fb",
50256904Sray	.vd_init = vt_fb_init,
51256904Sray	.vd_blank = vt_fb_blank,
52256904Sray	.vd_bitbltchr = vt_fb_bitbltchr,
53265397Sray	.vd_maskbitbltchr = vt_fb_maskbitbltchr,
54261552Sray	.vd_drawrect = vt_fb_drawrect,
55261552Sray	.vd_setpixel = vt_fb_setpixel,
56256904Sray	.vd_postswitch = vt_fb_postswitch,
57256904Sray	.vd_priority = VD_PRIORITY_GENERIC+10,
58259777Sray	.vd_fb_ioctl = vt_fb_ioctl,
59259777Sray	.vd_fb_mmap = vt_fb_mmap,
60256904Sray};
61256904Sray
62265397SrayVT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
63265397Sray
64268771Snwhitehornint
65259777Srayvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
66259777Sray{
67259777Sray	struct fb_info *info;
68268771Snwhitehorn	int error = 0;
69259777Sray
70259777Sray	info = vd->vd_softc;
71259777Sray
72268771Snwhitehorn	switch (cmd) {
73268771Snwhitehorn	case FBIOGTYPE:
74268771Snwhitehorn		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
75268771Snwhitehorn		break;
76259777Sray
77268771Snwhitehorn	case FBIO_GETWINORG:	/* get frame buffer window origin */
78268771Snwhitehorn		*(u_int *)data = 0;
79268771Snwhitehorn		break;
80268771Snwhitehorn
81268771Snwhitehorn	case FBIO_GETDISPSTART:	/* get display start address */
82268771Snwhitehorn		((video_display_start_t *)data)->x = 0;
83268771Snwhitehorn		((video_display_start_t *)data)->y = 0;
84268771Snwhitehorn		break;
85268771Snwhitehorn
86268771Snwhitehorn	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
87268771Snwhitehorn		*(u_int *)data = info->fb_stride;
88268771Snwhitehorn		break;
89268771Snwhitehorn
90268771Snwhitehorn	case FBIO_BLANK:	/* blank display */
91268771Snwhitehorn		if (vd->vd_driver->vd_blank == NULL)
92268771Snwhitehorn			return (ENODEV);
93268771Snwhitehorn		vd->vd_driver->vd_blank(vd, TC_BLACK);
94268771Snwhitehorn		break;
95268771Snwhitehorn
96268771Snwhitehorn	default:
97268771Snwhitehorn		error = ENOIOCTL;
98268771Snwhitehorn		break;
99268771Snwhitehorn	}
100268771Snwhitehorn
101268771Snwhitehorn	return (error);
102259777Sray}
103259777Sray
104268771Snwhitehornint
105260953Srayvt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
106260953Sray    int prot, vm_memattr_t *memattr)
107259777Sray{
108259777Sray	struct fb_info *info;
109259777Sray
110259777Sray	info = vd->vd_softc;
111259777Sray
112268771Snwhitehorn	if (info->fb_flags & FB_FLAG_NOMMAP)
113268771Snwhitehorn		return (ENODEV);
114259777Sray
115268771Snwhitehorn	if (offset >= 0 && offset < info->fb_size) {
116268771Snwhitehorn		*paddr = info->fb_pbase + offset;
117268771Snwhitehorn	#ifdef VM_MEMATTR_WRITE_COMBINING
118268771Snwhitehorn		*memattr = VM_MEMATTR_WRITE_COMBINING;
119268771Snwhitehorn	#endif
120268771Snwhitehorn		return (0);
121268771Snwhitehorn	}
122268771Snwhitehorn
123268771Snwhitehorn	return (EINVAL);
124259777Sray}
125259777Sray
126257725Srayvoid
127261552Srayvt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
128261552Sray{
129261552Sray	struct fb_info *info;
130261552Sray	uint32_t c;
131261552Sray	u_int o;
132261552Sray
133261552Sray	info = vd->vd_softc;
134261552Sray	c = info->fb_cmap[color];
135261552Sray	o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
136261552Sray
137261552Sray	switch (FBTYPE_GET_BYTESPP(info)) {
138261552Sray	case 1:
139261552Sray		info->wr1(info, o, c);
140261552Sray		break;
141261552Sray	case 2:
142261552Sray		info->wr2(info, o, c);
143261552Sray		break;
144261552Sray	case 3:
145261552Sray		info->wr1(info, o, (c >> 16) & 0xff);
146261552Sray		info->wr1(info, o + 1, (c >> 8) & 0xff);
147261552Sray		info->wr1(info, o + 2, c & 0xff);
148261552Sray		break;
149261552Sray	case 4:
150261552Sray		info->wr4(info, o, c);
151261552Sray		break;
152261552Sray	default:
153261552Sray		/* panic? */
154261552Sray		return;
155261552Sray	}
156261552Sray
157261552Sray}
158261552Sray
159261552Srayvoid
160261552Srayvt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
161261552Sray    term_color_t color)
162261552Sray{
163261552Sray	int x, y;
164261552Sray
165261552Sray	for (y = y1; y <= y2; y++) {
166261552Sray		if (fill || (y == y1) || (y == y2)) {
167261552Sray			for (x = x1; x <= x2; x++)
168261552Sray				vt_fb_setpixel(vd, x, y, color);
169261552Sray		} else {
170261552Sray			vt_fb_setpixel(vd, x1, y, color);
171261552Sray			vt_fb_setpixel(vd, x2, y, color);
172261552Sray		}
173261552Sray	}
174261552Sray}
175261552Sray
176261552Srayvoid
177256904Srayvt_fb_blank(struct vt_device *vd, term_color_t color)
178256904Sray{
179256904Sray	struct fb_info *info;
180256904Sray	uint32_t c;
181268771Snwhitehorn	u_int o, h;
182256904Sray
183256904Sray	info = vd->vd_softc;
184256904Sray	c = info->fb_cmap[color];
185257725Sray
186256904Sray	switch (FBTYPE_GET_BYTESPP(info)) {
187256904Sray	case 1:
188268796Snwhitehorn		for (h = 0; h < info->fb_height; h++)
189268771Snwhitehorn			for (o = 0; o < info->fb_stride; o++)
190268771Snwhitehorn				info->wr1(info, h*info->fb_stride + o, c);
191256904Sray		break;
192256904Sray	case 2:
193268796Snwhitehorn		for (h = 0; h < info->fb_height; h++)
194268771Snwhitehorn			for (o = 0; o < info->fb_stride; o += 2)
195268771Snwhitehorn				info->wr2(info, h*info->fb_stride + o, c);
196256904Sray		break;
197256904Sray	case 3:
198268796Snwhitehorn		for (h = 0; h < info->fb_height; h++)
199268771Snwhitehorn			for (o = 0; o < info->fb_stride; o += 3) {
200268771Snwhitehorn				info->wr1(info, h*info->fb_stride + o,
201268771Snwhitehorn				    (c >> 16) & 0xff);
202268771Snwhitehorn				info->wr1(info, h*info->fb_stride + o + 1,
203268771Snwhitehorn				    (c >> 8) & 0xff);
204268771Snwhitehorn				info->wr1(info, h*info->fb_stride + o + 2,
205268771Snwhitehorn				    c & 0xff);
206268771Snwhitehorn			}
207256904Sray		break;
208256904Sray	case 4:
209268796Snwhitehorn		for (h = 0; h < info->fb_height; h++)
210268771Snwhitehorn			for (o = 0; o < info->fb_stride; o += 4)
211268796Snwhitehorn				info->wr4(info, h*info->fb_stride + o, c);
212256904Sray		break;
213256904Sray	default:
214256904Sray		/* panic? */
215256904Sray		return;
216256904Sray	}
217256904Sray}
218256904Sray
219257725Srayvoid
220257988Srayvt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
221257988Sray    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
222257988Sray    unsigned int height, term_color_t fg, term_color_t bg)
223256904Sray{
224256904Sray	struct fb_info *info;
225256904Sray	uint32_t fgc, bgc, cc, o;
226256904Sray	int c, l, bpp;
227256904Sray	u_long line;
228265397Sray	uint8_t b;
229265397Sray	const uint8_t *ch;
230265397Sray
231265397Sray	info = vd->vd_softc;
232265397Sray	bpp = FBTYPE_GET_BYTESPP(info);
233265397Sray	fgc = info->fb_cmap[fg];
234265397Sray	bgc = info->fb_cmap[bg];
235265397Sray	b = 0;
236265397Sray	if (bpl == 0)
237265397Sray		bpl = (width + 7) >> 3; /* Bytes per sorce line. */
238265397Sray
239265397Sray	/* Don't try to put off screen pixels */
240265397Sray	if (((left + width) > info->fb_width) || ((top + height) >
241265397Sray	    info->fb_height))
242265397Sray		return;
243265397Sray
244265397Sray	line = (info->fb_stride * top) + (left * bpp);
245265397Sray	for (l = 0; l < height; l++) {
246265397Sray		ch = src;
247265397Sray		for (c = 0; c < width; c++) {
248265397Sray			if (c % 8 == 0)
249265397Sray				b = *ch++;
250265397Sray			else
251265397Sray				b <<= 1;
252265397Sray			o = line + (c * bpp);
253265397Sray			cc = b & 0x80 ? fgc : bgc;
254265397Sray
255265397Sray			switch(bpp) {
256265397Sray			case 1:
257265397Sray				info->wr1(info, o, cc);
258265397Sray				break;
259265397Sray			case 2:
260265397Sray				info->wr2(info, o, cc);
261265397Sray				break;
262265397Sray			case 3:
263265397Sray				/* Packed mode, so unaligned. Byte access. */
264265397Sray				info->wr1(info, o, (cc >> 16) & 0xff);
265265397Sray				info->wr1(info, o + 1, (cc >> 8) & 0xff);
266265397Sray				info->wr1(info, o + 2, cc & 0xff);
267265397Sray				break;
268265397Sray			case 4:
269265397Sray				info->wr4(info, o, cc);
270265397Sray				break;
271265397Sray			default:
272265397Sray				/* panic? */
273265397Sray				break;
274265397Sray			}
275265397Sray		}
276265397Sray		line += info->fb_stride;
277265397Sray		src += bpl;
278265397Sray	}
279265397Sray}
280265397Sray
281265397Srayvoid
282265397Srayvt_fb_maskbitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
283265397Sray    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
284265397Sray    unsigned int height, term_color_t fg, term_color_t bg)
285265397Sray{
286265397Sray	struct fb_info *info;
287265397Sray	uint32_t fgc, bgc, cc, o;
288265397Sray	int c, l, bpp;
289265397Sray	u_long line;
290257988Sray	uint8_t b, m;
291257988Sray	const uint8_t *ch;
292256904Sray
293256904Sray	info = vd->vd_softc;
294256904Sray	bpp = FBTYPE_GET_BYTESPP(info);
295256904Sray	fgc = info->fb_cmap[fg];
296256904Sray	bgc = info->fb_cmap[bg];
297258781Snwhitehorn	b = m = 0;
298257988Sray	if (bpl == 0)
299257988Sray		bpl = (width + 7) >> 3; /* Bytes per sorce line. */
300256904Sray
301257988Sray	/* Don't try to put off screen pixels */
302257988Sray	if (((left + width) > info->fb_width) || ((top + height) >
303257988Sray	    info->fb_height))
304257988Sray		return;
305257988Sray
306256904Sray	line = (info->fb_stride * top) + (left * bpp);
307256904Sray	for (l = 0; l < height; l++) {
308257988Sray		ch = src;
309256904Sray		for (c = 0; c < width; c++) {
310256904Sray			if (c % 8 == 0)
311257988Sray				b = *ch++;
312256904Sray			else
313256904Sray				b <<= 1;
314257988Sray			if (mask != NULL) {
315257988Sray				if (c % 8 == 0)
316257988Sray					m = *mask++;
317257988Sray				else
318257988Sray					m <<= 1;
319257988Sray				/* Skip pixel write, if mask has no bit set. */
320257988Sray				if ((m & 0x80) == 0)
321257988Sray					continue;
322257988Sray			}
323256904Sray			o = line + (c * bpp);
324256904Sray			cc = b & 0x80 ? fgc : bgc;
325256904Sray
326256904Sray			switch(bpp) {
327256904Sray			case 1:
328256904Sray				info->wr1(info, o, cc);
329256904Sray				break;
330256904Sray			case 2:
331256904Sray				info->wr2(info, o, cc);
332256904Sray				break;
333256904Sray			case 3:
334256904Sray				/* Packed mode, so unaligned. Byte access. */
335256904Sray				info->wr1(info, o, (cc >> 16) & 0xff);
336256904Sray				info->wr1(info, o + 1, (cc >> 8) & 0xff);
337256904Sray				info->wr1(info, o + 2, cc & 0xff);
338256904Sray				break;
339256904Sray			case 4:
340256904Sray				info->wr4(info, o, cc);
341256904Sray				break;
342256904Sray			default:
343256904Sray				/* panic? */
344256904Sray				break;
345256904Sray			}
346256904Sray		}
347256904Sray		line += info->fb_stride;
348257988Sray		src += bpl;
349256904Sray	}
350256904Sray}
351256904Sray
352257725Srayvoid
353256904Srayvt_fb_postswitch(struct vt_device *vd)
354256904Sray{
355256904Sray	struct fb_info *info;
356256904Sray
357256904Sray	info = vd->vd_softc;
358256904Sray
359256904Sray	if (info->enter != NULL)
360256904Sray		info->enter(info->fb_priv);
361256904Sray}
362256904Sray
363256904Sraystatic int
364256904Srayvt_fb_init_cmap(uint32_t *cmap, int depth)
365256904Sray{
366256904Sray
367256904Sray	switch (depth) {
368256904Sray	case 8:
369256904Sray		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
370256904Sray		    0x7, 5, 0x7, 2, 0x3, 0));
371256904Sray	case 15:
372256904Sray		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
373256904Sray		    0x1f, 10, 0x1f, 5, 0x1f, 0));
374256904Sray	case 16:
375256904Sray		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
376256904Sray		    0x1f, 11, 0x3f, 5, 0x1f, 0));
377256904Sray	case 24:
378256904Sray	case 32: /* Ignore alpha. */
379256904Sray		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
380256904Sray		    0xff, 0, 0xff, 8, 0xff, 16));
381256904Sray	default:
382256904Sray		return (1);
383256904Sray	}
384256904Sray}
385256904Sray
386257725Srayint
387256904Srayvt_fb_init(struct vt_device *vd)
388256904Sray{
389256904Sray	struct fb_info *info;
390256904Sray	int err;
391256904Sray
392256904Sray	info = vd->vd_softc;
393256904Sray	vd->vd_height = info->fb_height;
394256904Sray	vd->vd_width = info->fb_width;
395256904Sray
396256904Sray	if (info->fb_cmsize <= 0) {
397256904Sray		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
398256904Sray		if (err)
399256904Sray			return (CN_DEAD);
400256904Sray		info->fb_cmsize = 16;
401256904Sray	}
402256904Sray
403256904Sray	/* Clear the screen. */
404269437Snwhitehorn	vd->vd_driver->vd_blank(vd, TC_BLACK);
405256904Sray
406256904Sray	/* Wakeup screen. KMS need this. */
407256904Sray	vt_fb_postswitch(vd);
408256904Sray
409256904Sray	return (CN_INTERNAL);
410256904Sray}
411256904Sray
412256904Srayint
413256904Srayvt_fb_attach(struct fb_info *info)
414256904Sray{
415256904Sray
416256904Sray	vt_allocate(&vt_fb_driver, info);
417257725Sray
418256904Sray	return (0);
419256904Sray}
420257815Sray
421257815Srayvoid
422257815Srayvt_fb_resume(void)
423257815Sray{
424257815Sray
425257815Sray	vt_resume();
426257815Sray}
427257815Sray
428257815Srayvoid
429257815Srayvt_fb_suspend(void)
430257815Sray{
431257815Sray
432257815Sray	vt_suspend();
433257815Sray}
434