bcm2835_fb.c revision 253006
1203288Srnoland/*-
2203288Srnoland * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3203288Srnoland * All rights reserved.
4203288Srnoland *
5203288Srnoland * Redistribution and use in source and binary forms, with or without
6203288Srnoland * modification, are permitted provided that the following conditions
7203288Srnoland * are met:
8203288Srnoland * 1. Redistributions of source code must retain the above copyright
9203288Srnoland *    notice, this list of conditions and the following disclaimer.
10203288Srnoland * 2. Redistributions in binary form must reproduce the above copyright
11203288Srnoland *    notice, this list of conditions and the following disclaimer in the
12203288Srnoland *    documentation and/or other materials provided with the distribution.
13203288Srnoland *
14203288Srnoland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15203288Srnoland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16203288Srnoland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17203288Srnoland * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18203288Srnoland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19203288Srnoland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20203288Srnoland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21203288Srnoland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22203288Srnoland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23203288Srnoland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24203288Srnoland * SUCH DAMAGE.
25203288Srnoland *
26203288Srnoland */
27203288Srnoland#include <sys/cdefs.h>
28203288Srnoland__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c 253006 2013-07-07 21:23:58Z rpaulo $");
29203288Srnoland
30203288Srnoland#include <sys/param.h>
31203288Srnoland#include <sys/systm.h>
32203288Srnoland#include <sys/bio.h>
33203288Srnoland#include <sys/bus.h>
34203288Srnoland#include <sys/conf.h>
35203288Srnoland#include <sys/endian.h>
36203288Srnoland#include <sys/kernel.h>
37203288Srnoland#include <sys/kthread.h>
38203288Srnoland#include <sys/lock.h>
39203288Srnoland#include <sys/malloc.h>
40203288Srnoland#include <sys/module.h>
41203288Srnoland#include <sys/mutex.h>
42203288Srnoland#include <sys/queue.h>
43203288Srnoland#include <sys/resource.h>
44203288Srnoland#include <sys/rman.h>
45203288Srnoland#include <sys/time.h>
46203288Srnoland#include <sys/timetc.h>
47203288Srnoland#include <sys/fbio.h>
48203288Srnoland#include <sys/consio.h>
49203288Srnoland
50203288Srnoland#include <sys/kdb.h>
51203288Srnoland
52203288Srnoland#include <machine/bus.h>
53203288Srnoland#include <machine/cpu.h>
54203288Srnoland#include <machine/cpufunc.h>
55203288Srnoland#include <machine/resource.h>
56203288Srnoland#include <machine/frame.h>
57203288Srnoland#include <machine/intr.h>
58203288Srnoland
59203288Srnoland#include <dev/fdt/fdt_common.h>
60203288Srnoland#include <dev/ofw/ofw_bus.h>
61203288Srnoland#include <dev/ofw/ofw_bus_subr.h>
62203288Srnoland
63203288Srnoland#include <dev/fb/fbreg.h>
64203288Srnoland#include <dev/syscons/syscons.h>
65203288Srnoland
66203288Srnoland#include <arm/broadcom/bcm2835/bcm2835_mbox.h>
67203288Srnoland#include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
68203288Srnoland
69203288Srnoland#include "mbox_if.h"
70203288Srnoland
71203288Srnoland#define	BCMFB_FONT_HEIGHT	16
72203288Srnoland
73203288Srnolandstruct argb {
74203288Srnoland	uint8_t		a;
75203288Srnoland	uint8_t		r;
76203288Srnoland	uint8_t		g;
77203288Srnoland	uint8_t		b;
78203288Srnoland};
79203288Srnoland
80203288Srnolandstatic struct argb bcmfb_palette[16] = {
81203288Srnoland	{0x00, 0x00, 0x00, 0x00},
82203288Srnoland	{0x00, 0x00, 0x00, 0xaa},
83203288Srnoland	{0x00, 0x00, 0xaa, 0x00},
84203288Srnoland	{0x00, 0x00, 0xaa, 0xaa},
85203288Srnoland	{0x00, 0xaa, 0x00, 0x00},
86203288Srnoland	{0x00, 0xaa, 0x00, 0xaa},
87203288Srnoland	{0x00, 0xaa, 0x55, 0x00},
88203288Srnoland	{0x00, 0xaa, 0xaa, 0xaa},
89203288Srnoland	{0x00, 0x55, 0x55, 0x55},
90203288Srnoland	{0x00, 0x55, 0x55, 0xff},
91203288Srnoland	{0x00, 0x55, 0xff, 0x55},
92203288Srnoland	{0x00, 0x55, 0xff, 0xff},
93203288Srnoland	{0x00, 0xff, 0x55, 0x55},
94203288Srnoland	{0x00, 0xff, 0x55, 0xff},
95203288Srnoland	{0x00, 0xff, 0xff, 0x55},
96203288Srnoland	{0x00, 0xff, 0xff, 0xff}
97203288Srnoland};
98203288Srnoland
99203288Srnoland/* mouse pointer from dev/syscons/scgfbrndr.c */
100203288Srnolandstatic u_char mouse_pointer[16] = {
101203288Srnoland        0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
102203288Srnoland        0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
103203288Srnoland};
104203288Srnoland
105203288Srnoland#define FB_WIDTH		640
106203288Srnoland#define FB_HEIGHT		480
107203288Srnoland#define FB_DEPTH		24
108203288Srnoland
109203288Srnolandstruct bcm_fb_config {
110203288Srnoland	uint32_t	xres;
111203288Srnoland	uint32_t	yres;
112203288Srnoland	uint32_t	vxres;
113203288Srnoland	uint32_t	vyres;
114203288Srnoland	uint32_t	pitch;
115203288Srnoland	uint32_t	bpp;
116203288Srnoland	uint32_t	xoffset;
117203288Srnoland	uint32_t	yoffset;
118203288Srnoland	/* Filled by videocore */
119203288Srnoland	uint32_t	base;
120203288Srnoland	uint32_t	screen_size;
121203288Srnoland};
122203288Srnoland
123203288Srnolandstruct bcmsc_softc {
124203288Srnoland	device_t		dev;
125203288Srnoland	struct cdev *		cdev;
126203288Srnoland	struct mtx		mtx;
127203288Srnoland	bus_dma_tag_t		dma_tag;
128203288Srnoland	bus_dmamap_t		dma_map;
129203288Srnoland	struct bcm_fb_config*	fb_config;
130203288Srnoland	bus_addr_t		fb_config_phys;
131203288Srnoland	struct intr_config_hook	init_hook;
132203288Srnoland
133203288Srnoland};
134203288Srnoland
135203288Srnolandstruct video_adapter_softc {
136203288Srnoland	/* Videoadpater part */
137203288Srnoland	video_adapter_t	va;
138203288Srnoland	int		console;
139203288Srnoland
140203288Srnoland	intptr_t	fb_addr;
141203288Srnoland	intptr_t	fb_paddr;
142203288Srnoland	unsigned int	fb_size;
143203288Srnoland
144203288Srnoland	unsigned int	height;
145203288Srnoland	unsigned int	width;
146203288Srnoland	unsigned int	depth;
147203288Srnoland	unsigned int	stride;
148203288Srnoland
149203288Srnoland	unsigned int	xmargin;
150203288Srnoland	unsigned int	ymargin;
151203288Srnoland
152203288Srnoland	unsigned char	*font;
153203288Srnoland	int		initialized;
154203288Srnoland};
155203288Srnoland
156203288Srnolandstatic struct bcmsc_softc *bcmsc_softc;
157203288Srnolandstatic struct video_adapter_softc va_softc;
158203288Srnoland
159203288Srnoland#define	bcm_fb_lock(_sc)	mtx_lock(&(_sc)->mtx)
160203288Srnoland#define	bcm_fb_unlock(_sc)	mtx_unlock(&(_sc)->mtx)
161203288Srnoland#define	bcm_fb_lock_assert(sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
162203288Srnoland
163203288Srnolandstatic int bcm_fb_probe(device_t);
164203288Srnolandstatic int bcm_fb_attach(device_t);
165203288Srnolandstatic void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err);
166203288Srnolandstatic void bcmfb_update_margins(video_adapter_t *adp);
167203288Srnolandstatic int bcmfb_configure(int);
168203288Srnoland
169203288Srnolandstatic void
170203288Srnolandbcm_fb_init(void *arg)
171203288Srnoland{
172203288Srnoland	struct bcmsc_softc *sc = arg;
173203288Srnoland	struct video_adapter_softc *va_sc = &va_softc;
174203288Srnoland	int err;
175203288Srnoland	volatile struct bcm_fb_config*	fb_config = sc->fb_config;
176203288Srnoland	phandle_t node;
177203288Srnoland	pcell_t cell;
178203288Srnoland	device_t mbox;
179203288Srnoland
180203288Srnoland	node = ofw_bus_get_node(sc->dev);
181203288Srnoland
182203288Srnoland	fb_config->xres = 0;
183203288Srnoland	fb_config->yres = 0;
184203288Srnoland	fb_config->bpp = 0;
185203288Srnoland
186203288Srnoland	if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0)
187203288Srnoland		fb_config->xres = (int)fdt32_to_cpu(cell);
188203288Srnoland	if (fb_config->xres == 0)
189203288Srnoland		fb_config->xres = FB_WIDTH;
190203288Srnoland
191203288Srnoland	if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0)
192203288Srnoland		fb_config->yres = (uint32_t)fdt32_to_cpu(cell);
193203288Srnoland	if (fb_config->yres == 0)
194203288Srnoland		fb_config->yres = FB_HEIGHT;
195203288Srnoland
196203288Srnoland	if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0)
197203288Srnoland		fb_config->bpp = (uint32_t)fdt32_to_cpu(cell);
198203288Srnoland	if (fb_config->bpp == 0)
199203288Srnoland		fb_config->bpp = FB_DEPTH;
200203288Srnoland
201203288Srnoland	fb_config->vxres = 0;
202203288Srnoland	fb_config->vyres = 0;
203203288Srnoland	fb_config->xoffset = 0;
204203288Srnoland	fb_config->yoffset = 0;
205203288Srnoland	fb_config->base = 0;
206203288Srnoland	fb_config->pitch = 0;
207203288Srnoland	fb_config->screen_size = 0;
208203288Srnoland
209203288Srnoland	bus_dmamap_sync(sc->dma_tag, sc->dma_map,
210203288Srnoland		BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
211203288Srnoland
212203288Srnoland	mbox = devclass_get_device(devclass_find("mbox"), 0);
213203288Srnoland	if (mbox) {
214203288Srnoland		MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys);
215203288Srnoland		MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err);
216203288Srnoland	}
217203288Srnoland	bus_dmamap_sync(sc->dma_tag, sc->dma_map,
218203288Srnoland		BUS_DMASYNC_POSTREAD);
219203288Srnoland
220203288Srnoland	if (fb_config->base != 0) {
221203288Srnoland		device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n",
222203288Srnoland			fb_config->xres, fb_config->yres,
223203288Srnoland			fb_config->vxres, fb_config->vyres,
224203288Srnoland			fb_config->xoffset, fb_config->yoffset,
225203288Srnoland			fb_config->bpp);
226203288Srnoland
227203288Srnoland
228203288Srnoland		device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n",
229203288Srnoland			fb_config->pitch, fb_config->base,
230203288Srnoland			fb_config->screen_size);
231203288Srnoland
232203288Srnoland		va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size);
233203288Srnoland		va_sc->fb_paddr = fb_config->base;
234203288Srnoland		va_sc->fb_size = fb_config->screen_size;
235203288Srnoland		va_sc->depth = fb_config->bpp;
236203288Srnoland		va_sc->stride = fb_config->pitch;
237203288Srnoland
238203288Srnoland		va_sc->width = fb_config->xres;
239203288Srnoland		va_sc->height = fb_config->yres;
240203288Srnoland		bcmfb_update_margins(&va_sc->va);
241203288Srnoland	}
242203288Srnoland	else {
243203288Srnoland		device_printf(sc->dev, "Failed to set framebuffer info\n");
244203288Srnoland		return;
245203288Srnoland	}
246203288Srnoland
247203288Srnoland	config_intrhook_disestablish(&sc->init_hook);
248203288Srnoland}
249203288Srnoland
250203288Srnolandstatic int
251203288Srnolandbcm_fb_probe(device_t dev)
252203288Srnoland{
253203288Srnoland	int error = 0;
254203288Srnoland
255203288Srnoland	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb"))
256203288Srnoland		return (ENXIO);
257203288Srnoland
258203288Srnoland	device_set_desc(dev, "BCM2835 framebuffer device");
259203288Srnoland
260203288Srnoland	error = sc_probe_unit(device_get_unit(dev),
261203288Srnoland	    device_get_flags(dev) | SC_AUTODETECT_KBD);
262203288Srnoland	if (error != 0)
263203288Srnoland		return (error);
264203288Srnoland
265203288Srnoland
266203288Srnoland	return (BUS_PROBE_DEFAULT);
267203288Srnoland}
268203288Srnoland
269203288Srnolandstatic int
270203288Srnolandbcm_fb_attach(device_t dev)
271203288Srnoland{
272203288Srnoland	struct bcmsc_softc *sc = device_get_softc(dev);
273203288Srnoland	int dma_size = sizeof(struct bcm_fb_config);
274203288Srnoland	int err;
275203288Srnoland
276203288Srnoland	if (bcmsc_softc)
277203288Srnoland		return (ENXIO);
278203288Srnoland
279203288Srnoland	bcmsc_softc = sc;
280203288Srnoland
281203288Srnoland	sc->dev = dev;
282203288Srnoland	mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF);
283203288Srnoland
284203288Srnoland	err = bus_dma_tag_create(
285203288Srnoland	    bus_get_dma_tag(sc->dev),
286203288Srnoland	    PAGE_SIZE, 0,		/* alignment, boundary */
287203288Srnoland	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
288203288Srnoland	    BUS_SPACE_MAXADDR,		/* highaddr */
289203288Srnoland	    NULL, NULL,			/* filter, filterarg */
290203288Srnoland	    dma_size, 1,		/* maxsize, nsegments */
291203288Srnoland	    dma_size, 0,		/* maxsegsize, flags */
292203288Srnoland	    NULL, NULL,			/* lockfunc, lockarg */
293203288Srnoland	    &sc->dma_tag);
294203288Srnoland
295203288Srnoland	err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config,
296203288Srnoland	    0, &sc->dma_map);
297203288Srnoland	if (err) {
298203288Srnoland		device_printf(dev, "cannot allocate framebuffer\n");
299203288Srnoland		goto fail;
300203288Srnoland	}
301203288Srnoland
302203288Srnoland	err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config,
303203288Srnoland	    dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT);
304203288Srnoland
305203288Srnoland	if (err) {
306203288Srnoland		device_printf(dev, "cannot load DMA map\n");
307203288Srnoland		goto fail;
308203288Srnoland	}
309203288Srnoland
310203288Srnoland	err = (sc_attach_unit(device_get_unit(dev),
311203288Srnoland	    device_get_flags(dev) | SC_AUTODETECT_KBD));
312203288Srnoland
313203288Srnoland	if (err) {
314203288Srnoland		device_printf(dev, "failed to attach syscons\n");
315203288Srnoland		goto fail;
316203288Srnoland	}
317203288Srnoland
318203288Srnoland	/*
319203288Srnoland	 * We have to wait until interrupts are enabled.
320203288Srnoland	 * Mailbox relies on it to get data from VideoCore
321203288Srnoland	 */
322203288Srnoland        sc->init_hook.ich_func = bcm_fb_init;
323203288Srnoland        sc->init_hook.ich_arg = sc;
324203288Srnoland
325203288Srnoland        if (config_intrhook_establish(&sc->init_hook) != 0) {
326203288Srnoland		device_printf(dev, "failed to establish intrhook\n");
327203288Srnoland                return (ENOMEM);
328203288Srnoland	}
329203288Srnoland
330203288Srnoland	return (0);
331203288Srnoland
332203288Srnolandfail:
333203288Srnoland	return (ENXIO);
334203288Srnoland}
335203288Srnoland
336203288Srnoland
337203288Srnolandstatic void
338203288Srnolandbcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
339203288Srnoland{
340203288Srnoland	bus_addr_t *addr;
341203288Srnoland
342203288Srnoland	if (err)
343203288Srnoland		return;
344203288Srnoland
345203288Srnoland	addr = (bus_addr_t*)arg;
346203288Srnoland	*addr = PHYS_TO_VCBUS(segs[0].ds_addr);
347203288Srnoland}
348203288Srnoland
349203288Srnolandstatic device_method_t bcm_fb_methods[] = {
350203288Srnoland	/* Device interface */
351203288Srnoland	DEVMETHOD(device_probe,		bcm_fb_probe),
352203288Srnoland	DEVMETHOD(device_attach,	bcm_fb_attach),
353203288Srnoland
354203288Srnoland	{ 0, 0 }
355203288Srnoland};
356203288Srnoland
357203288Srnolandstatic devclass_t bcm_fb_devclass;
358203288Srnoland
359203288Srnolandstatic driver_t bcm_fb_driver = {
360203288Srnoland	"fb",
361203288Srnoland	bcm_fb_methods,
362203288Srnoland	sizeof(struct bcmsc_softc),
363203288Srnoland};
364203288Srnoland
365203288SrnolandDRIVER_MODULE(bcm2835fb, fdtbus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
366203288Srnoland
367203288Srnoland/*
368203288Srnoland * Video driver routines and glue.
369203288Srnoland */
370203288Srnolandstatic vi_probe_t		bcmfb_probe;
371203288Srnolandstatic vi_init_t		bcmfb_init;
372203288Srnolandstatic vi_get_info_t		bcmfb_get_info;
373203288Srnolandstatic vi_query_mode_t		bcmfb_query_mode;
374203288Srnolandstatic vi_set_mode_t		bcmfb_set_mode;
375203288Srnolandstatic vi_save_font_t		bcmfb_save_font;
376203288Srnolandstatic vi_load_font_t		bcmfb_load_font;
377203288Srnolandstatic vi_show_font_t		bcmfb_show_font;
378203288Srnolandstatic vi_save_palette_t	bcmfb_save_palette;
379203288Srnolandstatic vi_load_palette_t	bcmfb_load_palette;
380203288Srnolandstatic vi_set_border_t		bcmfb_set_border;
381203288Srnolandstatic vi_save_state_t		bcmfb_save_state;
382203288Srnolandstatic vi_load_state_t		bcmfb_load_state;
383203288Srnolandstatic vi_set_win_org_t		bcmfb_set_win_org;
384203288Srnolandstatic vi_read_hw_cursor_t	bcmfb_read_hw_cursor;
385203288Srnolandstatic vi_set_hw_cursor_t	bcmfb_set_hw_cursor;
386203288Srnolandstatic vi_set_hw_cursor_shape_t	bcmfb_set_hw_cursor_shape;
387203288Srnolandstatic vi_blank_display_t	bcmfb_blank_display;
388203288Srnolandstatic vi_mmap_t		bcmfb_mmap;
389203288Srnolandstatic vi_ioctl_t		bcmfb_ioctl;
390203288Srnolandstatic vi_clear_t		bcmfb_clear;
391203288Srnolandstatic vi_fill_rect_t		bcmfb_fill_rect;
392203288Srnolandstatic vi_bitblt_t		bcmfb_bitblt;
393203288Srnolandstatic vi_diag_t		bcmfb_diag;
394203288Srnolandstatic vi_save_cursor_palette_t	bcmfb_save_cursor_palette;
395203288Srnolandstatic vi_load_cursor_palette_t	bcmfb_load_cursor_palette;
396203288Srnolandstatic vi_copy_t		bcmfb_copy;
397203288Srnolandstatic vi_putp_t		bcmfb_putp;
398203288Srnolandstatic vi_putc_t		bcmfb_putc;
399203288Srnolandstatic vi_puts_t		bcmfb_puts;
400203288Srnolandstatic vi_putm_t		bcmfb_putm;
401203288Srnoland
402203288Srnolandstatic video_switch_t bcmfbvidsw = {
403203288Srnoland	.probe			= bcmfb_probe,
404203288Srnoland	.init			= bcmfb_init,
405203288Srnoland	.get_info		= bcmfb_get_info,
406203288Srnoland	.query_mode		= bcmfb_query_mode,
407203288Srnoland	.set_mode		= bcmfb_set_mode,
408203288Srnoland	.save_font		= bcmfb_save_font,
409203288Srnoland	.load_font		= bcmfb_load_font,
410203288Srnoland	.show_font		= bcmfb_show_font,
411203288Srnoland	.save_palette		= bcmfb_save_palette,
412203288Srnoland	.load_palette		= bcmfb_load_palette,
413203288Srnoland	.set_border		= bcmfb_set_border,
414203288Srnoland	.save_state		= bcmfb_save_state,
415203288Srnoland	.load_state		= bcmfb_load_state,
416203288Srnoland	.set_win_org		= bcmfb_set_win_org,
417203288Srnoland	.read_hw_cursor		= bcmfb_read_hw_cursor,
418203288Srnoland	.set_hw_cursor		= bcmfb_set_hw_cursor,
419203288Srnoland	.set_hw_cursor_shape	= bcmfb_set_hw_cursor_shape,
420203288Srnoland	.blank_display		= bcmfb_blank_display,
421203288Srnoland	.mmap			= bcmfb_mmap,
422203288Srnoland	.ioctl			= bcmfb_ioctl,
423203288Srnoland	.clear			= bcmfb_clear,
424203288Srnoland	.fill_rect		= bcmfb_fill_rect,
425203288Srnoland	.bitblt			= bcmfb_bitblt,
426203288Srnoland	.diag			= bcmfb_diag,
427203288Srnoland	.save_cursor_palette	= bcmfb_save_cursor_palette,
428203288Srnoland	.load_cursor_palette	= bcmfb_load_cursor_palette,
429203288Srnoland	.copy			= bcmfb_copy,
430203288Srnoland	.putp			= bcmfb_putp,
431203288Srnoland	.putc			= bcmfb_putc,
432203288Srnoland	.puts			= bcmfb_puts,
433203288Srnoland	.putm			= bcmfb_putm,
434203288Srnoland};
435203288Srnoland
436203288SrnolandVIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
437203288Srnoland
438203288Srnolandstatic vr_init_t bcmrend_init;
439203288Srnolandstatic vr_clear_t bcmrend_clear;
440203288Srnolandstatic vr_draw_border_t bcmrend_draw_border;
441203288Srnolandstatic vr_draw_t bcmrend_draw;
442203288Srnolandstatic vr_set_cursor_t bcmrend_set_cursor;
443203288Srnolandstatic vr_draw_cursor_t bcmrend_draw_cursor;
444203288Srnolandstatic vr_blink_cursor_t bcmrend_blink_cursor;
445203288Srnolandstatic vr_set_mouse_t bcmrend_set_mouse;
446203288Srnolandstatic vr_draw_mouse_t bcmrend_draw_mouse;
447203288Srnoland
448203288Srnoland/*
449203288Srnoland * We use our own renderer; this is because we must emulate a hardware
450203288Srnoland * cursor.
451203288Srnoland */
452203288Srnolandstatic sc_rndr_sw_t bcmrend = {
453203288Srnoland	bcmrend_init,
454203288Srnoland	bcmrend_clear,
455203288Srnoland	bcmrend_draw_border,
456203288Srnoland	bcmrend_draw,
457203288Srnoland	bcmrend_set_cursor,
458203288Srnoland	bcmrend_draw_cursor,
459203288Srnoland	bcmrend_blink_cursor,
460203288Srnoland	bcmrend_set_mouse,
461203288Srnoland	bcmrend_draw_mouse
462203288Srnoland};
463203288Srnoland
464203288SrnolandRENDERER(bcmfb, 0, bcmrend, gfb_set);
465203288SrnolandRENDERER_MODULE(bcmfb, gfb_set);
466203288Srnoland
467203288Srnolandstatic void
468203288Srnolandbcmrend_init(scr_stat* scp)
469203288Srnoland{
470203288Srnoland}
471203288Srnoland
472203288Srnolandstatic void
473203288Srnolandbcmrend_clear(scr_stat* scp, int c, int attr)
474203288Srnoland{
475203288Srnoland}
476203288Srnoland
477203288Srnolandstatic void
478203288Srnolandbcmrend_draw_border(scr_stat* scp, int color)
479203288Srnoland{
480203288Srnoland}
481203288Srnoland
482203288Srnolandstatic void
483203288Srnolandbcmrend_draw(scr_stat* scp, int from, int count, int flip)
484203288Srnoland{
485203288Srnoland	video_adapter_t* adp = scp->sc->adp;
486203288Srnoland	int i, c, a;
487203288Srnoland
488203288Srnoland	if (!flip) {
489203288Srnoland		/* Normal printing */
490203288Srnoland		vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
491203288Srnoland	} else {
492203288Srnoland		/* This is for selections and such: invert the color attribute */
493203288Srnoland		for (i = count; i-- > 0; ++from) {
494203288Srnoland			c = sc_vtb_getc(&scp->vtb, from);
495203288Srnoland			a = sc_vtb_geta(&scp->vtb, from) >> 8;
496203288Srnoland			vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
497203288Srnoland		}
498203288Srnoland	}
499203288Srnoland}
500203288Srnoland
501203288Srnolandstatic void
502203288Srnolandbcmrend_set_cursor(scr_stat* scp, int base, int height, int blink)
503203288Srnoland{
504203288Srnoland}
505203288Srnoland
506203288Srnolandstatic void
507203288Srnolandbcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
508203288Srnoland{
509203288Srnoland	video_adapter_t* adp = scp->sc->adp;
510203288Srnoland	struct video_adapter_softc *sc;
511203288Srnoland	int row, col;
512203288Srnoland	uint8_t *addr;
513203288Srnoland	int i, j, bytes;
514203288Srnoland
515203288Srnoland	sc = (struct video_adapter_softc *)adp;
516203288Srnoland
517203288Srnoland	if (scp->curs_attr.height <= 0)
518203288Srnoland		return;
519203288Srnoland
520203288Srnoland	if (sc->fb_addr == 0)
521203288Srnoland		return;
522203288Srnoland
523203288Srnoland	if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
524203288Srnoland		return;
525203288Srnoland
526203288Srnoland	/* calculate the coordinates in the video buffer */
527203288Srnoland	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
528203288Srnoland	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
529203288Srnoland
530203288Srnoland	addr = (uint8_t *)sc->fb_addr
531203288Srnoland	    + (row + sc->ymargin)*(sc->stride)
532203288Srnoland	    + (sc->depth/8) * (col + sc->xmargin);
533203288Srnoland
534203288Srnoland	bytes = sc->depth/8;
535203288Srnoland
536203288Srnoland	/* our cursor consists of simply inverting the char under it */
537203288Srnoland	for (i = 0; i < adp->va_info.vi_cheight; i++) {
538203288Srnoland		for (j = 0; j < adp->va_info.vi_cwidth; j++) {
539203288Srnoland			switch (sc->depth) {
540203288Srnoland			case 32:
541203288Srnoland			case 24:
542203288Srnoland				addr[bytes*j + 2] ^= 0xff;
543203288Srnoland				/* FALLTHROUGH */
544203288Srnoland			case 16:
545203288Srnoland				addr[bytes*j + 1] ^= 0xff;
546203288Srnoland				addr[bytes*j] ^= 0xff;
547203288Srnoland				break;
548203288Srnoland			default:
549203288Srnoland				break;
550203288Srnoland			}
551203288Srnoland		}
552203288Srnoland
553203288Srnoland		addr += sc->stride;
554203288Srnoland	}
555203288Srnoland}
556203288Srnoland
557203288Srnolandstatic void
558203288Srnolandbcmrend_blink_cursor(scr_stat* scp, int at, int flip)
559203288Srnoland{
560203288Srnoland}
561203288Srnoland
562203288Srnolandstatic void
563203288Srnolandbcmrend_set_mouse(scr_stat* scp)
564203288Srnoland{
565203288Srnoland}
566203288Srnoland
567203288Srnolandstatic void
568203288Srnolandbcmrend_draw_mouse(scr_stat* scp, int x, int y, int on)
569203288Srnoland{
570203288Srnoland	vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
571203288Srnoland}
572203288Srnoland
573203288Srnolandstatic uint16_t bcmfb_static_window[ROW*COL];
574203288Srnolandextern u_char dflt_font_16[];
575203288Srnoland
576203288Srnoland/*
577203288Srnoland * Update videoadapter settings after changing resolution
578203288Srnoland */
579203288Srnolandstatic void
580203288Srnolandbcmfb_update_margins(video_adapter_t *adp)
581203288Srnoland{
582203288Srnoland	struct video_adapter_softc *sc;
583203288Srnoland	video_info_t *vi;
584203288Srnoland
585203288Srnoland	sc = (struct video_adapter_softc *)adp;
586203288Srnoland	vi = &adp->va_info;
587203288Srnoland
588203288Srnoland	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
589203288Srnoland	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
590203288Srnoland}
591203288Srnoland
592203288Srnolandstatic int
593203288Srnolandbcmfb_configure(int flags)
594203288Srnoland{
595203288Srnoland	struct video_adapter_softc *va_sc;
596203288Srnoland
597203288Srnoland	va_sc = &va_softc;
598203288Srnoland	phandle_t display, root;
599203288Srnoland	pcell_t cell;
600203288Srnoland
601203288Srnoland	if (va_sc->initialized)
602203288Srnoland		return (0);
603203288Srnoland
604203288Srnoland	va_sc->width = 0;
605203288Srnoland	va_sc->height = 0;
606203288Srnoland
607203288Srnoland	/*
608203288Srnoland	 * It seems there is no way to let syscons framework know
609203288Srnoland	 * that framebuffer resolution has changed. So just try
610203288Srnoland	 * to fetch data from FDT and go with defaults if failed
611203288Srnoland	 */
612203288Srnoland	root = OF_finddevice("/");
613203288Srnoland	if ((root != 0) &&
614203288Srnoland	    (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
615203288Srnoland		if ((OF_getprop(display, "broadcom,width",
616203288Srnoland		    &cell, sizeof(cell))) > 0)
617203288Srnoland			va_sc->width = (int)fdt32_to_cpu(cell);
618203288Srnoland
619203288Srnoland		if ((OF_getprop(display, "broadcom,height",
620203288Srnoland		    &cell, sizeof(cell))) > 0)
621203288Srnoland			va_sc->height = (int)fdt32_to_cpu(cell);
622203288Srnoland	}
623203288Srnoland
624203288Srnoland	if (va_sc->width == 0)
625203288Srnoland		va_sc->width = FB_WIDTH;
626203288Srnoland	if (va_sc->height == 0)
627203288Srnoland		va_sc->height = FB_HEIGHT;
628203288Srnoland
629203288Srnoland	bcmfb_init(0, &va_sc->va, 0);
630203288Srnoland
631203288Srnoland	va_sc->initialized = 1;
632203288Srnoland
633203288Srnoland	return (0);
634203288Srnoland}
635203288Srnoland
636203288Srnolandstatic int
637203288Srnolandbcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
638203288Srnoland{
639203288Srnoland
640203288Srnoland	return (0);
641203288Srnoland}
642203288Srnoland
643203288Srnolandstatic int
644203288Srnolandbcmfb_init(int unit, video_adapter_t *adp, int flags)
645203288Srnoland{
646203288Srnoland	struct video_adapter_softc *sc;
647203288Srnoland	video_info_t *vi;
648203288Srnoland
649203288Srnoland	sc = (struct video_adapter_softc *)adp;
650203288Srnoland	vi = &adp->va_info;
651203288Srnoland
652203288Srnoland	vid_init_struct(adp, "bcmfb", -1, unit);
653203288Srnoland
654203288Srnoland	sc->font = dflt_font_16;
655203288Srnoland	vi->vi_cheight = BCMFB_FONT_HEIGHT;
656203288Srnoland	vi->vi_cwidth = 8;
657203288Srnoland
658203288Srnoland	vi->vi_width = sc->width/8;
659203288Srnoland	vi->vi_height = sc->height/vi->vi_cheight;
660203288Srnoland
661203288Srnoland	/*
662203288Srnoland	 * Clamp width/height to syscons maximums
663203288Srnoland	 */
664203288Srnoland	if (vi->vi_width > COL)
665203288Srnoland		vi->vi_width = COL;
666203288Srnoland	if (vi->vi_height > ROW)
667203288Srnoland		vi->vi_height = ROW;
668203288Srnoland
669203288Srnoland	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
670203288Srnoland	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
671203288Srnoland
672203288Srnoland
673203288Srnoland	adp->va_window = (vm_offset_t) bcmfb_static_window;
674203288Srnoland	adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
675203288Srnoland
676203288Srnoland	vid_register(&sc->va);
677203288Srnoland
678203288Srnoland	return (0);
679203288Srnoland}
680203288Srnoland
681203288Srnolandstatic int
682203288Srnolandbcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
683203288Srnoland{
684203288Srnoland	bcopy(&adp->va_info, info, sizeof(*info));
685203288Srnoland	return (0);
686203288Srnoland}
687203288Srnoland
688203288Srnolandstatic int
689203288Srnolandbcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
690203288Srnoland{
691203288Srnoland	return (0);
692203288Srnoland}
693203288Srnoland
694203288Srnolandstatic int
695203288Srnolandbcmfb_set_mode(video_adapter_t *adp, int mode)
696203288Srnoland{
697203288Srnoland	return (0);
698203288Srnoland}
699203288Srnoland
700203288Srnolandstatic int
701203288Srnolandbcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
702203288Srnoland    u_char *data, int c, int count)
703203288Srnoland{
704203288Srnoland	return (0);
705203288Srnoland}
706203288Srnoland
707203288Srnolandstatic int
708203288Srnolandbcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
709203288Srnoland    u_char *data, int c, int count)
710203288Srnoland{
711203288Srnoland	struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
712203288Srnoland
713203288Srnoland	sc->font = data;
714203288Srnoland
715203288Srnoland	return (0);
716203288Srnoland}
717203288Srnoland
718203288Srnolandstatic int
719203288Srnolandbcmfb_show_font(video_adapter_t *adp, int page)
720203288Srnoland{
721203288Srnoland	return (0);
722203288Srnoland}
723203288Srnoland
724203288Srnolandstatic int
725203288Srnolandbcmfb_save_palette(video_adapter_t *adp, u_char *palette)
726203288Srnoland{
727203288Srnoland	return (0);
728203288Srnoland}
729203288Srnoland
730203288Srnolandstatic int
731203288Srnolandbcmfb_load_palette(video_adapter_t *adp, u_char *palette)
732203288Srnoland{
733203288Srnoland	return (0);
734203288Srnoland}
735203288Srnoland
736203288Srnolandstatic int
737203288Srnolandbcmfb_set_border(video_adapter_t *adp, int border)
738203288Srnoland{
739203288Srnoland	return (bcmfb_blank_display(adp, border));
740203288Srnoland}
741203288Srnoland
742203288Srnolandstatic int
743203288Srnolandbcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
744203288Srnoland{
745203288Srnoland	return (0);
746203288Srnoland}
747203288Srnoland
748203288Srnolandstatic int
749203288Srnolandbcmfb_load_state(video_adapter_t *adp, void *p)
750203288Srnoland{
751203288Srnoland	return (0);
752203288Srnoland}
753203288Srnoland
754203288Srnolandstatic int
755203288Srnolandbcmfb_set_win_org(video_adapter_t *adp, off_t offset)
756203288Srnoland{
757203288Srnoland	return (0);
758203288Srnoland}
759203288Srnoland
760203288Srnolandstatic int
761203288Srnolandbcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
762203288Srnoland{
763203288Srnoland	*col = *row = 0;
764203288Srnoland
765203288Srnoland	return (0);
766203288Srnoland}
767203288Srnoland
768203288Srnolandstatic int
769203288Srnolandbcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
770203288Srnoland{
771203288Srnoland	return (0);
772203288Srnoland}
773203288Srnoland
774203288Srnolandstatic int
775203288Srnolandbcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
776203288Srnoland    int celsize, int blink)
777203288Srnoland{
778203288Srnoland	return (0);
779203288Srnoland}
780203288Srnoland
781203288Srnolandstatic int
782203288Srnolandbcmfb_blank_display(video_adapter_t *adp, int mode)
783203288Srnoland{
784203288Srnoland
785203288Srnoland	struct video_adapter_softc *sc;
786203288Srnoland
787203288Srnoland	sc = (struct video_adapter_softc *)adp;
788203288Srnoland	if (sc && sc->fb_addr)
789203288Srnoland		memset((void*)sc->fb_addr, 0, sc->fb_size);
790203288Srnoland
791203288Srnoland	return (0);
792203288Srnoland}
793203288Srnoland
794203288Srnolandstatic int
795203288Srnolandbcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
796203288Srnoland    int prot, vm_memattr_t *memattr)
797203288Srnoland{
798203288Srnoland	struct video_adapter_softc *sc;
799203288Srnoland
800203288Srnoland	sc = (struct video_adapter_softc *)adp;
801203288Srnoland
802203288Srnoland	/*
803203288Srnoland	 * This might be a legacy VGA mem request: if so, just point it at the
804203288Srnoland	 * framebuffer, since it shouldn't be touched
805203288Srnoland	 */
806203288Srnoland	if (offset < sc->stride*sc->height) {
807203288Srnoland		*paddr = sc->fb_paddr + offset;
808203288Srnoland		return (0);
809203288Srnoland	}
810203288Srnoland
811203288Srnoland	return (EINVAL);
812203288Srnoland}
813203288Srnoland
814203288Srnolandstatic int
815203288Srnolandbcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
816203288Srnoland{
817203288Srnoland	struct video_adapter_softc *sc;
818203288Srnoland	struct fbtype *fb;
819203288Srnoland
820203288Srnoland	sc = (struct video_adapter_softc *)adp;
821203288Srnoland
822203288Srnoland	switch (cmd) {
823203288Srnoland	case FBIOGTYPE:
824203288Srnoland		fb = (struct fbtype *)data;
825203288Srnoland		fb->fb_type = FBTYPE_PCIMISC;
826203288Srnoland		fb->fb_height = sc->height;
827203288Srnoland		fb->fb_width = sc->width;
828203288Srnoland		fb->fb_depth = sc->depth;
829203288Srnoland		if (sc->depth <= 1 || sc->depth > 8)
830203288Srnoland			fb->fb_cmsize = 0;
831203288Srnoland		else
832203288Srnoland			fb->fb_cmsize = 1 << sc->depth;
833203288Srnoland		fb->fb_size = sc->fb_size;
834203288Srnoland		break;
835203288Srnoland	default:
836203288Srnoland		return (fb_commonioctl(adp, cmd, data));
837203288Srnoland	}
838203288Srnoland
839203288Srnoland	return (0);
840203288Srnoland}
841203288Srnoland
842203288Srnolandstatic int
843203288Srnolandbcmfb_clear(video_adapter_t *adp)
844203288Srnoland{
845203288Srnoland
846203288Srnoland	return (bcmfb_blank_display(adp, 0));
847203288Srnoland}
848203288Srnoland
849203288Srnolandstatic int
850203288Srnolandbcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
851203288Srnoland{
852203288Srnoland
853203288Srnoland	return (0);
854203288Srnoland}
855203288Srnoland
856203288Srnolandstatic int
857203288Srnolandbcmfb_bitblt(video_adapter_t *adp, ...)
858203288Srnoland{
859203288Srnoland
860203288Srnoland	return (0);
861203288Srnoland}
862203288Srnoland
863203288Srnolandstatic int
864203288Srnolandbcmfb_diag(video_adapter_t *adp, int level)
865203288Srnoland{
866203288Srnoland
867203288Srnoland	return (0);
868203288Srnoland}
869203288Srnoland
870203288Srnolandstatic int
871203288Srnolandbcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
872203288Srnoland{
873203288Srnoland
874203288Srnoland	return (0);
875203288Srnoland}
876203288Srnoland
877203288Srnolandstatic int
878203288Srnolandbcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
879203288Srnoland{
880203288Srnoland
881203288Srnoland	return (0);
882203288Srnoland}
883203288Srnoland
884203288Srnolandstatic int
885203288Srnolandbcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
886203288Srnoland{
887203288Srnoland
888203288Srnoland	return (0);
889203288Srnoland}
890203288Srnoland
891203288Srnolandstatic int
892203288Srnolandbcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
893203288Srnoland    int size, int bpp, int bit_ltor, int byte_ltor)
894203288Srnoland{
895203288Srnoland
896203288Srnoland	return (0);
897203288Srnoland}
898203288Srnoland
899203288Srnolandstatic int
900203288Srnolandbcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
901203288Srnoland{
902203288Srnoland	struct video_adapter_softc *sc;
903203288Srnoland	int row;
904203288Srnoland	int col;
905203288Srnoland	int i, j, k;
906203288Srnoland	uint8_t *addr;
907203288Srnoland	u_char *p;
908203288Srnoland	uint8_t fg, bg, color;
909203288Srnoland	uint16_t rgb;
910203288Srnoland
911203288Srnoland	sc = (struct video_adapter_softc *)adp;
912203288Srnoland
913203288Srnoland	if (sc->fb_addr == 0)
914203288Srnoland		return (0);
915203288Srnoland
916203288Srnoland	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
917203288Srnoland	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
918203288Srnoland	p = sc->font + c*BCMFB_FONT_HEIGHT;
919203288Srnoland	addr = (uint8_t *)sc->fb_addr
920203288Srnoland	    + (row + sc->ymargin)*(sc->stride)
921203288Srnoland	    + (sc->depth/8) * (col + sc->xmargin);
922203288Srnoland
923203288Srnoland	fg = a & 0xf ;
924203288Srnoland	bg = (a >> 4) & 0xf;
925203288Srnoland
926203288Srnoland	for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
927203288Srnoland		for (j = 0, k = 7; j < 8; j++, k--) {
928203288Srnoland			if ((p[i] & (1 << k)) == 0)
929203288Srnoland				color = bg;
930203288Srnoland			else
931203288Srnoland				color = fg;
932203288Srnoland
933203288Srnoland			switch (sc->depth) {
934203288Srnoland			case 32:
935203288Srnoland				addr[4*j+0] = bcmfb_palette[color].r;
936203288Srnoland				addr[4*j+1] = bcmfb_palette[color].g;
937203288Srnoland				addr[4*j+2] = bcmfb_palette[color].b;
938203288Srnoland				addr[4*j+3] = bcmfb_palette[color].a;
939203288Srnoland				break;
940203288Srnoland			case 24:
941203288Srnoland				addr[3*j] = bcmfb_palette[color].r;
942203288Srnoland				addr[3*j+1] = bcmfb_palette[color].g;
943203288Srnoland				addr[3*j+2] = bcmfb_palette[color].b;
944203288Srnoland				break;
945203288Srnoland			case 16:
946203288Srnoland				rgb = (bcmfb_palette[color].r >> 3) << 11;
947203288Srnoland				rgb |= (bcmfb_palette[color].g >> 2) << 5;
948203288Srnoland				rgb |= (bcmfb_palette[color].b >> 3);
949203288Srnoland				addr[2*j] = rgb & 0xff;
950203288Srnoland				addr[2*j + 1] = (rgb >> 8) & 0xff;
951203288Srnoland			default:
952203288Srnoland				/* Not supported yet */
953203288Srnoland				break;
954203288Srnoland			}
955203288Srnoland		}
956203288Srnoland
957203288Srnoland		addr += (sc->stride);
958203288Srnoland	}
959203288Srnoland
960203288Srnoland        return (0);
961203288Srnoland}
962203288Srnoland
963203288Srnolandstatic int
964203288Srnolandbcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
965203288Srnoland{
966203288Srnoland	int i;
967203288Srnoland
968203288Srnoland	for (i = 0; i < len; i++)
969203288Srnoland		bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
970203288Srnoland
971203288Srnoland	return (0);
972203288Srnoland}
973203288Srnoland
974203288Srnolandstatic int
975203288Srnolandbcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
976203288Srnoland    uint32_t pixel_mask, int size, int width)
977203288Srnoland{
978203288Srnoland
979203288Srnoland	return (0);
980203288Srnoland}
981203288Srnoland
982203288Srnoland/*
983203288Srnoland * Define a stub keyboard driver in case one hasn't been
984203288Srnoland * compiled into the kernel
985203288Srnoland */
986203288Srnoland#include <sys/kbio.h>
987203288Srnoland#include <dev/kbd/kbdreg.h>
988203288Srnoland
989203288Srnolandstatic int dummy_kbd_configure(int flags);
990203288Srnoland
991203288Srnolandkeyboard_switch_t bcmdummysw;
992203288Srnoland
993203288Srnolandstatic int
994203288Srnolanddummy_kbd_configure(int flags)
995203288Srnoland{
996203288Srnoland
997203288Srnoland	return (0);
998203288Srnoland}
999203288SrnolandKEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure);
1000203288Srnoland