1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/consio.h>
36#include <sys/fbio.h>
37#include <sys/kdb.h>
38#include <sys/kernel.h>
39#include <sys/malloc.h>
40#include <sys/module.h>
41
42#include <vm/vm.h>
43#include <vm/pmap.h>
44
45#include <dev/fb/fbreg.h>
46#include <dev/ofw/ofw_bus.h>
47#include <dev/ofw/ofw_bus_subr.h>
48#include <dev/syscons/syscons.h>
49
50#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
51
52#include "mbox_if.h"
53
54struct argb {
55	uint8_t		a;
56	uint8_t		r;
57	uint8_t		g;
58	uint8_t		b;
59};
60
61static struct argb bcmfb_palette[16] = {
62	{0x00, 0x00, 0x00, 0x00},
63	{0x00, 0x00, 0x00, 0xaa},
64	{0x00, 0x00, 0xaa, 0x00},
65	{0x00, 0x00, 0xaa, 0xaa},
66	{0x00, 0xaa, 0x00, 0x00},
67	{0x00, 0xaa, 0x00, 0xaa},
68	{0x00, 0xaa, 0x55, 0x00},
69	{0x00, 0xaa, 0xaa, 0xaa},
70	{0x00, 0x55, 0x55, 0x55},
71	{0x00, 0x55, 0x55, 0xff},
72	{0x00, 0x55, 0xff, 0x55},
73	{0x00, 0x55, 0xff, 0xff},
74	{0x00, 0xff, 0x55, 0x55},
75	{0x00, 0xff, 0x55, 0xff},
76	{0x00, 0xff, 0xff, 0x55},
77	{0x00, 0xff, 0xff, 0xff}
78};
79
80/* mouse pointer from dev/syscons/scgfbrndr.c */
81static u_char mouse_pointer[16] = {
82        0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
83        0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
84};
85
86#define	BCMFB_FONT_HEIGHT	16
87#define	BCMFB_FONT_WIDTH	8
88#define	FB_WIDTH		640
89#define	FB_HEIGHT		480
90#define	FB_DEPTH		24
91
92struct bcmsc_softc {
93	/* Videoadpater part */
94	video_adapter_t	va;
95
96	intptr_t	fb_addr;
97	intptr_t	fb_paddr;
98	unsigned int	fb_size;
99
100	unsigned int	height;
101	unsigned int	width;
102	unsigned int	depth;
103	unsigned int	stride;
104
105	unsigned int	xmargin;
106	unsigned int	ymargin;
107
108	unsigned char	*font;
109	int		fbswap;
110	int		initialized;
111};
112
113static struct bcmsc_softc bcmsc;
114
115static struct ofw_compat_data compat_data[] = {
116	{"broadcom,bcm2835-fb",		1},
117	{"brcm,bcm2708-fb",		1},
118	{NULL,				0}
119};
120
121static int bcm_fb_probe(device_t);
122static int bcm_fb_attach(device_t);
123static void bcmfb_update_margins(video_adapter_t *adp);
124static int bcmfb_configure(int);
125
126static int
127bcm_fb_probe(device_t dev)
128{
129	int error;
130
131	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
132		return (ENXIO);
133
134	device_set_desc(dev, "BCM2835 framebuffer device");
135	error = sc_probe_unit(device_get_unit(dev),
136	    device_get_flags(dev) | SC_AUTODETECT_KBD);
137	if (error != 0)
138		return (error);
139
140	return (BUS_PROBE_DEFAULT);
141}
142
143static int
144bcm_fb_attach(device_t dev)
145{
146	struct bcm2835_fb_config fb;
147	struct bcmsc_softc *sc;
148
149	sc = (struct bcmsc_softc *)vid_get_adapter(vid_find_adapter(
150	    "bcmfb", 0));
151	if (sc != NULL)
152		device_set_softc(dev, sc);
153	else
154		sc = device_get_softc(dev);
155
156	memset(&fb, 0, sizeof(fb));
157	if (bcm2835_mbox_fb_get_w_h(&fb) != 0)
158		return (ENXIO);
159	fb.bpp = FB_DEPTH;
160	fb.vxres = fb.xres;
161	fb.vyres = fb.yres;
162	fb.xoffset = fb.yoffset = 0;
163	if (bcm2835_mbox_fb_init(&fb) != 0)
164		return (ENXIO);
165
166	sc->fb_addr = (intptr_t)pmap_mapdev(fb.base, fb.size);
167	sc->fb_paddr = fb.base;
168	sc->fb_size = fb.size;
169	sc->depth = fb.bpp;
170	sc->stride = fb.pitch;
171	sc->width = fb.xres;
172	sc->height = fb.yres;
173	bcmfb_update_margins(&sc->va);
174
175	if (sc_attach_unit(device_get_unit(dev),
176	    device_get_flags(dev) | SC_AUTODETECT_KBD) != 0) {
177		device_printf(dev, "failed to attach syscons\n");
178		return (ENXIO);
179	}
180
181	device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
182	    fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
183	device_printf(dev,
184	    "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
185	    sc->fbswap, fb.pitch, fb.base, fb.size);
186
187	return (0);
188}
189
190static device_method_t bcm_fb_methods[] = {
191	/* Device interface */
192	DEVMETHOD(device_probe,		bcm_fb_probe),
193	DEVMETHOD(device_attach,	bcm_fb_attach),
194
195	{ 0, 0 }
196};
197
198static devclass_t bcm_fb_devclass;
199
200static driver_t bcm_fb_driver = {
201	"fb",
202	bcm_fb_methods,
203	sizeof(struct bcmsc_softc),
204};
205
206DRIVER_MODULE(bcm2835fb, ofwbus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
207DRIVER_MODULE(bcm2835fb, simplebus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
208
209/*
210 * Video driver routines and glue.
211 */
212static vi_probe_t		bcmfb_probe;
213static vi_init_t		bcmfb_init;
214static vi_get_info_t		bcmfb_get_info;
215static vi_query_mode_t		bcmfb_query_mode;
216static vi_set_mode_t		bcmfb_set_mode;
217static vi_save_font_t		bcmfb_save_font;
218static vi_load_font_t		bcmfb_load_font;
219static vi_show_font_t		bcmfb_show_font;
220static vi_save_palette_t	bcmfb_save_palette;
221static vi_load_palette_t	bcmfb_load_palette;
222static vi_set_border_t		bcmfb_set_border;
223static vi_save_state_t		bcmfb_save_state;
224static vi_load_state_t		bcmfb_load_state;
225static vi_set_win_org_t		bcmfb_set_win_org;
226static vi_read_hw_cursor_t	bcmfb_read_hw_cursor;
227static vi_set_hw_cursor_t	bcmfb_set_hw_cursor;
228static vi_set_hw_cursor_shape_t	bcmfb_set_hw_cursor_shape;
229static vi_blank_display_t	bcmfb_blank_display;
230static vi_mmap_t		bcmfb_mmap;
231static vi_ioctl_t		bcmfb_ioctl;
232static vi_clear_t		bcmfb_clear;
233static vi_fill_rect_t		bcmfb_fill_rect;
234static vi_bitblt_t		bcmfb_bitblt;
235static vi_diag_t		bcmfb_diag;
236static vi_save_cursor_palette_t	bcmfb_save_cursor_palette;
237static vi_load_cursor_palette_t	bcmfb_load_cursor_palette;
238static vi_copy_t		bcmfb_copy;
239static vi_putp_t		bcmfb_putp;
240static vi_putc_t		bcmfb_putc;
241static vi_puts_t		bcmfb_puts;
242static vi_putm_t		bcmfb_putm;
243
244static video_switch_t bcmfbvidsw = {
245	.probe			= bcmfb_probe,
246	.init			= bcmfb_init,
247	.get_info		= bcmfb_get_info,
248	.query_mode		= bcmfb_query_mode,
249	.set_mode		= bcmfb_set_mode,
250	.save_font		= bcmfb_save_font,
251	.load_font		= bcmfb_load_font,
252	.show_font		= bcmfb_show_font,
253	.save_palette		= bcmfb_save_palette,
254	.load_palette		= bcmfb_load_palette,
255	.set_border		= bcmfb_set_border,
256	.save_state		= bcmfb_save_state,
257	.load_state		= bcmfb_load_state,
258	.set_win_org		= bcmfb_set_win_org,
259	.read_hw_cursor		= bcmfb_read_hw_cursor,
260	.set_hw_cursor		= bcmfb_set_hw_cursor,
261	.set_hw_cursor_shape	= bcmfb_set_hw_cursor_shape,
262	.blank_display		= bcmfb_blank_display,
263	.mmap			= bcmfb_mmap,
264	.ioctl			= bcmfb_ioctl,
265	.clear			= bcmfb_clear,
266	.fill_rect		= bcmfb_fill_rect,
267	.bitblt			= bcmfb_bitblt,
268	.diag			= bcmfb_diag,
269	.save_cursor_palette	= bcmfb_save_cursor_palette,
270	.load_cursor_palette	= bcmfb_load_cursor_palette,
271	.copy			= bcmfb_copy,
272	.putp			= bcmfb_putp,
273	.putc			= bcmfb_putc,
274	.puts			= bcmfb_puts,
275	.putm			= bcmfb_putm,
276};
277
278VIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
279
280static vr_init_t bcmrend_init;
281static vr_clear_t bcmrend_clear;
282static vr_draw_border_t bcmrend_draw_border;
283static vr_draw_t bcmrend_draw;
284static vr_set_cursor_t bcmrend_set_cursor;
285static vr_draw_cursor_t bcmrend_draw_cursor;
286static vr_blink_cursor_t bcmrend_blink_cursor;
287static vr_set_mouse_t bcmrend_set_mouse;
288static vr_draw_mouse_t bcmrend_draw_mouse;
289
290/*
291 * We use our own renderer; this is because we must emulate a hardware
292 * cursor.
293 */
294static sc_rndr_sw_t bcmrend = {
295	bcmrend_init,
296	bcmrend_clear,
297	bcmrend_draw_border,
298	bcmrend_draw,
299	bcmrend_set_cursor,
300	bcmrend_draw_cursor,
301	bcmrend_blink_cursor,
302	bcmrend_set_mouse,
303	bcmrend_draw_mouse
304};
305
306RENDERER(bcmfb, 0, bcmrend, gfb_set);
307RENDERER_MODULE(bcmfb, gfb_set);
308
309static void
310bcmrend_init(scr_stat* scp)
311{
312}
313
314static void
315bcmrend_clear(scr_stat* scp, int c, int attr)
316{
317}
318
319static void
320bcmrend_draw_border(scr_stat* scp, int color)
321{
322}
323
324static void
325bcmrend_draw(scr_stat* scp, int from, int count, int flip)
326{
327	video_adapter_t* adp = scp->sc->adp;
328	int i, c, a;
329
330	if (!flip) {
331		/* Normal printing */
332		vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
333	} else {
334		/* This is for selections and such: invert the color attribute */
335		for (i = count; i-- > 0; ++from) {
336			c = sc_vtb_getc(&scp->vtb, from);
337			a = sc_vtb_geta(&scp->vtb, from) >> 8;
338			vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
339		}
340	}
341}
342
343static void
344bcmrend_set_cursor(scr_stat* scp, int base, int height, int blink)
345{
346}
347
348static void
349bcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
350{
351	int bytes, col, i, j, row;
352	struct bcmsc_softc *sc;
353	uint8_t *addr;
354	video_adapter_t *adp;
355
356	adp = scp->sc->adp;
357	sc = (struct bcmsc_softc *)adp;
358
359	if (scp->curs_attr.height <= 0)
360		return;
361
362	if (sc->fb_addr == 0)
363		return;
364
365	if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
366		return;
367
368	/* calculate the coordinates in the video buffer */
369	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
370	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
371
372	addr = (uint8_t *)sc->fb_addr
373	    + (row + sc->ymargin)*(sc->stride)
374	    + (sc->depth/8) * (col + sc->xmargin);
375
376	bytes = sc->depth / 8;
377	/* our cursor consists of simply inverting the char under it */
378	for (i = 0; i < adp->va_info.vi_cheight; i++) {
379		for (j = 0; j < adp->va_info.vi_cwidth; j++) {
380			switch (sc->depth) {
381			case 32:
382			case 24:
383				addr[bytes*j + 2] ^= 0xff;
384				/* FALLTHROUGH */
385			case 16:
386				addr[bytes*j + 1] ^= 0xff;
387				addr[bytes*j] ^= 0xff;
388				break;
389			default:
390				break;
391			}
392		}
393
394		addr += sc->stride;
395	}
396}
397
398static void
399bcmrend_blink_cursor(scr_stat* scp, int at, int flip)
400{
401}
402
403static void
404bcmrend_set_mouse(scr_stat* scp)
405{
406}
407
408static void
409bcmrend_draw_mouse(scr_stat* scp, int x, int y, int on)
410{
411	vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
412}
413
414static uint16_t bcmfb_static_window[ROW*COL];
415extern u_char dflt_font_16[];
416
417/*
418 * Update videoadapter settings after changing resolution
419 */
420static void
421bcmfb_update_margins(video_adapter_t *adp)
422{
423	struct bcmsc_softc *sc;
424	video_info_t *vi;
425
426	sc = (struct bcmsc_softc *)adp;
427	vi = &adp->va_info;
428
429	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
430	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
431}
432
433static int
434bcmfb_configure(int flags)
435{
436	char bootargs[2048], *n, *p, *v;
437	pcell_t cell;
438	phandle_t chosen, display, root;
439	struct bcmsc_softc *sc;
440
441	sc = &bcmsc;
442	if (sc->initialized)
443		return (0);
444
445	sc->width = 0;
446	sc->height = 0;
447
448	/*
449	 * It seems there is no way to let syscons framework know
450	 * that framebuffer resolution has changed. So just try
451	 * to fetch data from FDT bootargs, FDT display data and
452	 * finally go with defaults if everything else has failed.
453	 */
454	chosen = OF_finddevice("/chosen");
455	if (chosen != -1 &&
456	    OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) {
457		p = bootargs;
458		while ((v = strsep(&p, " ")) != NULL) {
459			if (*v == '\0')
460				continue;
461			n = strsep(&v, "=");
462			if (strcmp(n, "bcm2708_fb.fbwidth") == 0 && v != NULL)
463				sc->width = (unsigned int)strtol(v, NULL, 0);
464			else if (strcmp(n, "bcm2708_fb.fbheight") == 0 &&
465			    v != NULL)
466				sc->height = (unsigned int)strtol(v, NULL, 0);
467			else if (strcmp(n, "bcm2708_fb.fbswap") == 0 &&
468			    v != NULL)
469				if (*v == '1')
470					sc->fbswap = 1;
471		}
472	}
473
474	root = OF_finddevice("/");
475	if ((root != -1) &&
476	    (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
477		if (sc->width == 0) {
478			if ((OF_getencprop(display, "broadcom,width",
479			    &cell, sizeof(cell))) > 0)
480				sc->width = cell;
481		}
482
483		if (sc->height == 0) {
484			if ((OF_getencprop(display, "broadcom,height",
485			    &cell, sizeof(cell))) > 0)
486				sc->height = cell;
487		}
488	}
489
490	if (sc->width == 0)
491		sc->width = FB_WIDTH;
492	if (sc->height == 0)
493		sc->height = FB_HEIGHT;
494
495	bcmfb_init(0, &sc->va, 0);
496	sc->initialized = 1;
497
498	return (0);
499}
500
501static int
502bcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
503{
504
505	return (0);
506}
507
508static int
509bcmfb_init(int unit, video_adapter_t *adp, int flags)
510{
511	struct bcmsc_softc *sc;
512	video_info_t *vi;
513
514	sc = (struct bcmsc_softc *)adp;
515	vi = &adp->va_info;
516
517	vid_init_struct(adp, "bcmfb", -1, unit);
518
519	sc->font = dflt_font_16;
520	vi->vi_cheight = BCMFB_FONT_HEIGHT;
521	vi->vi_cwidth = BCMFB_FONT_WIDTH;
522	vi->vi_width = sc->width / vi->vi_cwidth;
523	vi->vi_height = sc->height / vi->vi_cheight;
524
525	/*
526	 * Clamp width/height to syscons maximums
527	 */
528	if (vi->vi_width > COL)
529		vi->vi_width = COL;
530	if (vi->vi_height > ROW)
531		vi->vi_height = ROW;
532
533	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
534	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
535
536	adp->va_window = (vm_offset_t) bcmfb_static_window;
537	adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
538
539	vid_register(&sc->va);
540
541	return (0);
542}
543
544static int
545bcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
546{
547	bcopy(&adp->va_info, info, sizeof(*info));
548	return (0);
549}
550
551static int
552bcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
553{
554	return (0);
555}
556
557static int
558bcmfb_set_mode(video_adapter_t *adp, int mode)
559{
560	return (0);
561}
562
563static int
564bcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
565    u_char *data, int c, int count)
566{
567	return (0);
568}
569
570static int
571bcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
572    u_char *data, int c, int count)
573{
574	struct bcmsc_softc *sc;
575
576	sc = (struct bcmsc_softc *)adp;
577	sc->font = data;
578
579	return (0);
580}
581
582static int
583bcmfb_show_font(video_adapter_t *adp, int page)
584{
585	return (0);
586}
587
588static int
589bcmfb_save_palette(video_adapter_t *adp, u_char *palette)
590{
591	return (0);
592}
593
594static int
595bcmfb_load_palette(video_adapter_t *adp, u_char *palette)
596{
597	return (0);
598}
599
600static int
601bcmfb_set_border(video_adapter_t *adp, int border)
602{
603	return (bcmfb_blank_display(adp, border));
604}
605
606static int
607bcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
608{
609	return (0);
610}
611
612static int
613bcmfb_load_state(video_adapter_t *adp, void *p)
614{
615	return (0);
616}
617
618static int
619bcmfb_set_win_org(video_adapter_t *adp, off_t offset)
620{
621	return (0);
622}
623
624static int
625bcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
626{
627	*col = *row = 0;
628
629	return (0);
630}
631
632static int
633bcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
634{
635	return (0);
636}
637
638static int
639bcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
640    int celsize, int blink)
641{
642	return (0);
643}
644
645static int
646bcmfb_blank_display(video_adapter_t *adp, int mode)
647{
648
649	struct bcmsc_softc *sc;
650
651	sc = (struct bcmsc_softc *)adp;
652	if (sc && sc->fb_addr)
653		memset((void*)sc->fb_addr, 0, sc->fb_size);
654
655	return (0);
656}
657
658static int
659bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
660    int prot, vm_memattr_t *memattr)
661{
662	struct bcmsc_softc *sc;
663
664	sc = (struct bcmsc_softc *)adp;
665
666	/*
667	 * This might be a legacy VGA mem request: if so, just point it at the
668	 * framebuffer, since it shouldn't be touched
669	 */
670	if (offset < sc->stride*sc->height) {
671		*paddr = sc->fb_paddr + offset;
672		return (0);
673	}
674
675	return (EINVAL);
676}
677
678static int
679bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
680{
681	struct bcmsc_softc *sc;
682	struct fbtype *fb;
683
684	sc = (struct bcmsc_softc *)adp;
685
686	switch (cmd) {
687	case FBIOGTYPE:
688		fb = (struct fbtype *)data;
689		fb->fb_type = FBTYPE_PCIMISC;
690		fb->fb_height = sc->height;
691		fb->fb_width = sc->width;
692		fb->fb_depth = sc->depth;
693		if (sc->depth <= 1 || sc->depth > 8)
694			fb->fb_cmsize = 0;
695		else
696			fb->fb_cmsize = 1 << sc->depth;
697		fb->fb_size = sc->fb_size;
698		break;
699	default:
700		return (fb_commonioctl(adp, cmd, data));
701	}
702
703	return (0);
704}
705
706static int
707bcmfb_clear(video_adapter_t *adp)
708{
709
710	return (bcmfb_blank_display(adp, 0));
711}
712
713static int
714bcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
715{
716
717	return (0);
718}
719
720static int
721bcmfb_bitblt(video_adapter_t *adp, ...)
722{
723
724	return (0);
725}
726
727static int
728bcmfb_diag(video_adapter_t *adp, int level)
729{
730
731	return (0);
732}
733
734static int
735bcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
736{
737
738	return (0);
739}
740
741static int
742bcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
743{
744
745	return (0);
746}
747
748static int
749bcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
750{
751
752	return (0);
753}
754
755static int
756bcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
757    int size, int bpp, int bit_ltor, int byte_ltor)
758{
759
760	return (0);
761}
762
763static int
764bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
765{
766	int bytes, col, i, j, k, row;
767	struct bcmsc_softc *sc;
768	u_char *p;
769	uint8_t *addr, fg, bg, color;
770	uint16_t rgb;
771
772	sc = (struct bcmsc_softc *)adp;
773
774	if (sc->fb_addr == 0)
775		return (0);
776
777	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
778	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
779	p = sc->font + c*BCMFB_FONT_HEIGHT;
780	addr = (uint8_t *)sc->fb_addr
781	    + (row + sc->ymargin)*(sc->stride)
782	    + (sc->depth/8) * (col + sc->xmargin);
783
784	fg = a & 0xf ;
785	bg = (a >> 4) & 0xf;
786
787	bytes = sc->depth / 8;
788	for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
789		for (j = 0, k = 7; j < 8; j++, k--) {
790			if ((p[i] & (1 << k)) == 0)
791				color = bg;
792			else
793				color = fg;
794
795			switch (sc->depth) {
796			case 32:
797			case 24:
798				if (sc->fbswap) {
799					addr[bytes * j + 0] =
800					    bcmfb_palette[color].b;
801					addr[bytes * j + 1] =
802					    bcmfb_palette[color].g;
803					addr[bytes * j + 2] =
804					    bcmfb_palette[color].r;
805				} else {
806					addr[bytes * j + 0] =
807					    bcmfb_palette[color].r;
808					addr[bytes * j + 1] =
809					    bcmfb_palette[color].g;
810					addr[bytes * j + 2] =
811					    bcmfb_palette[color].b;
812				}
813				if (sc->depth == 32)
814					addr[bytes * j + 3] =
815					    bcmfb_palette[color].a;
816				break;
817			case 16:
818				rgb = (bcmfb_palette[color].r >> 3) << 11;
819				rgb |= (bcmfb_palette[color].g >> 2) << 5;
820				rgb |= (bcmfb_palette[color].b >> 3);
821				addr[bytes * j] = rgb & 0xff;
822				addr[bytes * j + 1] = (rgb >> 8) & 0xff;
823			default:
824				/* Not supported yet */
825				break;
826			}
827		}
828
829		addr += (sc->stride);
830	}
831
832        return (0);
833}
834
835static int
836bcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
837{
838	int i;
839
840	for (i = 0; i < len; i++)
841		bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
842
843	return (0);
844}
845
846static int
847bcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
848    uint32_t pixel_mask, int size, int width)
849{
850
851	return (0);
852}
853