1239922Sgonzo/*-
2239922Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3239922Sgonzo * All rights reserved.
4239922Sgonzo *
5239922Sgonzo * Redistribution and use in source and binary forms, with or without
6239922Sgonzo * modification, are permitted provided that the following conditions
7239922Sgonzo * are met:
8239922Sgonzo * 1. Redistributions of source code must retain the above copyright
9239922Sgonzo *    notice, this list of conditions and the following disclaimer.
10239922Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11239922Sgonzo *    notice, this list of conditions and the following disclaimer in the
12239922Sgonzo *    documentation and/or other materials provided with the distribution.
13239922Sgonzo *
14239922Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15239922Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16239922Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17239922Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18239922Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19239922Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20239922Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21239922Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22239922Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239922Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239922Sgonzo * SUCH DAMAGE.
25239922Sgonzo *
26239922Sgonzo */
27239922Sgonzo#include <sys/cdefs.h>
28239922Sgonzo__FBSDID("$FreeBSD: stable/11/sys/arm/broadcom/bcm2835/bcm2835_fb.c 356110 2019-12-27 03:00:18Z kevans $");
29239922Sgonzo
30239922Sgonzo#include <sys/param.h>
31239922Sgonzo#include <sys/systm.h>
32239922Sgonzo#include <sys/bus.h>
33282358Sloos#include <sys/consio.h>
34282358Sloos#include <sys/fbio.h>
35282358Sloos#include <sys/kdb.h>
36239922Sgonzo#include <sys/kernel.h>
37239922Sgonzo#include <sys/malloc.h>
38239922Sgonzo#include <sys/module.h>
39239922Sgonzo
40282358Sloos#include <vm/vm.h>
41282358Sloos#include <vm/pmap.h>
42239922Sgonzo
43282358Sloos#include <dev/fb/fbreg.h>
44239922Sgonzo#include <dev/fdt/fdt_common.h>
45239922Sgonzo#include <dev/ofw/ofw_bus.h>
46239922Sgonzo#include <dev/ofw/ofw_bus_subr.h>
47239922Sgonzo#include <dev/syscons/syscons.h>
48239922Sgonzo
49282358Sloos#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
50239922Sgonzo
51253006Srpaulo#include "mbox_if.h"
52253006Srpaulo
53243423Sgonzostruct argb {
54243423Sgonzo	uint8_t		a;
55243423Sgonzo	uint8_t		r;
56243423Sgonzo	uint8_t		g;
57243423Sgonzo	uint8_t		b;
58243423Sgonzo};
59243423Sgonzo
60243423Sgonzostatic struct argb bcmfb_palette[16] = {
61243423Sgonzo	{0x00, 0x00, 0x00, 0x00},
62243423Sgonzo	{0x00, 0x00, 0x00, 0xaa},
63243423Sgonzo	{0x00, 0x00, 0xaa, 0x00},
64243423Sgonzo	{0x00, 0x00, 0xaa, 0xaa},
65243423Sgonzo	{0x00, 0xaa, 0x00, 0x00},
66243423Sgonzo	{0x00, 0xaa, 0x00, 0xaa},
67243423Sgonzo	{0x00, 0xaa, 0x55, 0x00},
68243423Sgonzo	{0x00, 0xaa, 0xaa, 0xaa},
69243423Sgonzo	{0x00, 0x55, 0x55, 0x55},
70243423Sgonzo	{0x00, 0x55, 0x55, 0xff},
71243423Sgonzo	{0x00, 0x55, 0xff, 0x55},
72243423Sgonzo	{0x00, 0x55, 0xff, 0xff},
73243423Sgonzo	{0x00, 0xff, 0x55, 0x55},
74243423Sgonzo	{0x00, 0xff, 0x55, 0xff},
75243423Sgonzo	{0x00, 0xff, 0xff, 0x55},
76243423Sgonzo	{0x00, 0xff, 0xff, 0xff}
77243423Sgonzo};
78243423Sgonzo
79244762Sgonzo/* mouse pointer from dev/syscons/scgfbrndr.c */
80244762Sgonzostatic u_char mouse_pointer[16] = {
81244762Sgonzo        0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
82244762Sgonzo        0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
83244762Sgonzo};
84244762Sgonzo
85282358Sloos#define	BCMFB_FONT_HEIGHT	16
86282358Sloos#define	BCMFB_FONT_WIDTH	8
87282358Sloos#define	FB_WIDTH		640
88282358Sloos#define	FB_HEIGHT		480
89282358Sloos#define	FB_DEPTH		24
90239922Sgonzo
91239922Sgonzostruct bcmsc_softc {
92239922Sgonzo	/* Videoadpater part */
93239922Sgonzo	video_adapter_t	va;
94239922Sgonzo
95239922Sgonzo	intptr_t	fb_addr;
96245389Sray	intptr_t	fb_paddr;
97239922Sgonzo	unsigned int	fb_size;
98239922Sgonzo
99239922Sgonzo	unsigned int	height;
100239922Sgonzo	unsigned int	width;
101243423Sgonzo	unsigned int	depth;
102239922Sgonzo	unsigned int	stride;
103239922Sgonzo
104239922Sgonzo	unsigned int	xmargin;
105239922Sgonzo	unsigned int	ymargin;
106239922Sgonzo
107239922Sgonzo	unsigned char	*font;
108282358Sloos	int		fbswap;
109239922Sgonzo	int		initialized;
110239922Sgonzo};
111239922Sgonzo
112282358Sloosstatic struct bcmsc_softc bcmsc;
113239922Sgonzo
114307575Sgonzostatic struct ofw_compat_data compat_data[] = {
115307575Sgonzo	{"broadcom,bcm2835-fb",		1},
116307575Sgonzo	{"brcm,bcm2708-fb",		1},
117307575Sgonzo	{NULL,				0}
118307575Sgonzo};
119307575Sgonzo
120239922Sgonzostatic int bcm_fb_probe(device_t);
121239922Sgonzostatic int bcm_fb_attach(device_t);
122243423Sgonzostatic void bcmfb_update_margins(video_adapter_t *adp);
123243423Sgonzostatic int bcmfb_configure(int);
124239922Sgonzo
125239922Sgonzostatic int
126239922Sgonzobcm_fb_probe(device_t dev)
127239922Sgonzo{
128282358Sloos	int error;
129239922Sgonzo
130307575Sgonzo	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
131239922Sgonzo		return (ENXIO);
132307575Sgonzo
133239922Sgonzo	device_set_desc(dev, "BCM2835 framebuffer device");
134239922Sgonzo	error = sc_probe_unit(device_get_unit(dev),
135239922Sgonzo	    device_get_flags(dev) | SC_AUTODETECT_KBD);
136239922Sgonzo	if (error != 0)
137239922Sgonzo		return (error);
138239922Sgonzo
139239922Sgonzo	return (BUS_PROBE_DEFAULT);
140239922Sgonzo}
141239922Sgonzo
142239922Sgonzostatic int
143239922Sgonzobcm_fb_attach(device_t dev)
144239922Sgonzo{
145282358Sloos	struct bcm2835_fb_config fb;
146282358Sloos	struct bcmsc_softc *sc;
147239922Sgonzo
148282358Sloos	sc = (struct bcmsc_softc *)vid_get_adapter(vid_find_adapter(
149282358Sloos	    "bcmfb", 0));
150282358Sloos	if (sc != NULL)
151282358Sloos		device_set_softc(dev, sc);
152282358Sloos	else
153282358Sloos		sc = device_get_softc(dev);
154282358Sloos
155282358Sloos	memset(&fb, 0, sizeof(fb));
156298305Sgonzo	if (bcm2835_mbox_fb_get_w_h(&fb) != 0)
157239922Sgonzo		return (ENXIO);
158282358Sloos	fb.bpp = FB_DEPTH;
159298383Sgonzo	fb.vxres = fb.xres;
160298383Sgonzo	fb.vyres = fb.yres;
161298383Sgonzo	fb.xoffset = fb.yoffset = 0;
162298305Sgonzo	if (bcm2835_mbox_fb_init(&fb) != 0)
163282358Sloos		return (ENXIO);
164239922Sgonzo
165282358Sloos	sc->fb_addr = (intptr_t)pmap_mapdev(fb.base, fb.size);
166282358Sloos	sc->fb_paddr = fb.base;
167282358Sloos	sc->fb_size = fb.size;
168282358Sloos	sc->depth = fb.bpp;
169282358Sloos	sc->stride = fb.pitch;
170282358Sloos	sc->width = fb.xres;
171282358Sloos	sc->height = fb.yres;
172282358Sloos	bcmfb_update_margins(&sc->va);
173239922Sgonzo
174282358Sloos	if (sc_attach_unit(device_get_unit(dev),
175282358Sloos	    device_get_flags(dev) | SC_AUTODETECT_KBD) != 0) {
176239922Sgonzo		device_printf(dev, "failed to attach syscons\n");
177282358Sloos		return (ENXIO);
178239922Sgonzo	}
179239922Sgonzo
180282358Sloos	device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
181282358Sloos	    fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
182282358Sloos	device_printf(dev,
183282358Sloos	    "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
184282358Sloos	    sc->fbswap, fb.pitch, fb.base, fb.size);
185239922Sgonzo
186239922Sgonzo	return (0);
187239922Sgonzo}
188239922Sgonzo
189239922Sgonzostatic device_method_t bcm_fb_methods[] = {
190239922Sgonzo	/* Device interface */
191239922Sgonzo	DEVMETHOD(device_probe,		bcm_fb_probe),
192239922Sgonzo	DEVMETHOD(device_attach,	bcm_fb_attach),
193239922Sgonzo
194239922Sgonzo	{ 0, 0 }
195239922Sgonzo};
196239922Sgonzo
197239922Sgonzostatic devclass_t bcm_fb_devclass;
198239922Sgonzo
199239922Sgonzostatic driver_t bcm_fb_driver = {
200239922Sgonzo	"fb",
201239922Sgonzo	bcm_fb_methods,
202239922Sgonzo	sizeof(struct bcmsc_softc),
203239922Sgonzo};
204239922Sgonzo
205261513SnwhitehornDRIVER_MODULE(bcm2835fb, ofwbus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
206307575SgonzoDRIVER_MODULE(bcm2835fb, simplebus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
207239922Sgonzo
208239922Sgonzo/*
209239922Sgonzo * Video driver routines and glue.
210239922Sgonzo */
211239922Sgonzostatic vi_probe_t		bcmfb_probe;
212239922Sgonzostatic vi_init_t		bcmfb_init;
213239922Sgonzostatic vi_get_info_t		bcmfb_get_info;
214239922Sgonzostatic vi_query_mode_t		bcmfb_query_mode;
215239922Sgonzostatic vi_set_mode_t		bcmfb_set_mode;
216239922Sgonzostatic vi_save_font_t		bcmfb_save_font;
217239922Sgonzostatic vi_load_font_t		bcmfb_load_font;
218239922Sgonzostatic vi_show_font_t		bcmfb_show_font;
219239922Sgonzostatic vi_save_palette_t	bcmfb_save_palette;
220239922Sgonzostatic vi_load_palette_t	bcmfb_load_palette;
221239922Sgonzostatic vi_set_border_t		bcmfb_set_border;
222239922Sgonzostatic vi_save_state_t		bcmfb_save_state;
223239922Sgonzostatic vi_load_state_t		bcmfb_load_state;
224239922Sgonzostatic vi_set_win_org_t		bcmfb_set_win_org;
225239922Sgonzostatic vi_read_hw_cursor_t	bcmfb_read_hw_cursor;
226239922Sgonzostatic vi_set_hw_cursor_t	bcmfb_set_hw_cursor;
227239922Sgonzostatic vi_set_hw_cursor_shape_t	bcmfb_set_hw_cursor_shape;
228239922Sgonzostatic vi_blank_display_t	bcmfb_blank_display;
229239922Sgonzostatic vi_mmap_t		bcmfb_mmap;
230239922Sgonzostatic vi_ioctl_t		bcmfb_ioctl;
231239922Sgonzostatic vi_clear_t		bcmfb_clear;
232239922Sgonzostatic vi_fill_rect_t		bcmfb_fill_rect;
233239922Sgonzostatic vi_bitblt_t		bcmfb_bitblt;
234239922Sgonzostatic vi_diag_t		bcmfb_diag;
235239922Sgonzostatic vi_save_cursor_palette_t	bcmfb_save_cursor_palette;
236239922Sgonzostatic vi_load_cursor_palette_t	bcmfb_load_cursor_palette;
237239922Sgonzostatic vi_copy_t		bcmfb_copy;
238239922Sgonzostatic vi_putp_t		bcmfb_putp;
239239922Sgonzostatic vi_putc_t		bcmfb_putc;
240239922Sgonzostatic vi_puts_t		bcmfb_puts;
241239922Sgonzostatic vi_putm_t		bcmfb_putm;
242239922Sgonzo
243239922Sgonzostatic video_switch_t bcmfbvidsw = {
244239922Sgonzo	.probe			= bcmfb_probe,
245239922Sgonzo	.init			= bcmfb_init,
246239922Sgonzo	.get_info		= bcmfb_get_info,
247239922Sgonzo	.query_mode		= bcmfb_query_mode,
248239922Sgonzo	.set_mode		= bcmfb_set_mode,
249239922Sgonzo	.save_font		= bcmfb_save_font,
250239922Sgonzo	.load_font		= bcmfb_load_font,
251239922Sgonzo	.show_font		= bcmfb_show_font,
252239922Sgonzo	.save_palette		= bcmfb_save_palette,
253239922Sgonzo	.load_palette		= bcmfb_load_palette,
254239922Sgonzo	.set_border		= bcmfb_set_border,
255239922Sgonzo	.save_state		= bcmfb_save_state,
256239922Sgonzo	.load_state		= bcmfb_load_state,
257239922Sgonzo	.set_win_org		= bcmfb_set_win_org,
258239922Sgonzo	.read_hw_cursor		= bcmfb_read_hw_cursor,
259239922Sgonzo	.set_hw_cursor		= bcmfb_set_hw_cursor,
260239922Sgonzo	.set_hw_cursor_shape	= bcmfb_set_hw_cursor_shape,
261239922Sgonzo	.blank_display		= bcmfb_blank_display,
262239922Sgonzo	.mmap			= bcmfb_mmap,
263239922Sgonzo	.ioctl			= bcmfb_ioctl,
264239922Sgonzo	.clear			= bcmfb_clear,
265239922Sgonzo	.fill_rect		= bcmfb_fill_rect,
266239922Sgonzo	.bitblt			= bcmfb_bitblt,
267239922Sgonzo	.diag			= bcmfb_diag,
268239922Sgonzo	.save_cursor_palette	= bcmfb_save_cursor_palette,
269239922Sgonzo	.load_cursor_palette	= bcmfb_load_cursor_palette,
270239922Sgonzo	.copy			= bcmfb_copy,
271239922Sgonzo	.putp			= bcmfb_putp,
272239922Sgonzo	.putc			= bcmfb_putc,
273239922Sgonzo	.puts			= bcmfb_puts,
274239922Sgonzo	.putm			= bcmfb_putm,
275239922Sgonzo};
276239922Sgonzo
277239922SgonzoVIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
278239922Sgonzo
279244762Sgonzostatic vr_init_t bcmrend_init;
280244762Sgonzostatic vr_clear_t bcmrend_clear;
281244762Sgonzostatic vr_draw_border_t bcmrend_draw_border;
282244762Sgonzostatic vr_draw_t bcmrend_draw;
283244762Sgonzostatic vr_set_cursor_t bcmrend_set_cursor;
284244762Sgonzostatic vr_draw_cursor_t bcmrend_draw_cursor;
285244762Sgonzostatic vr_blink_cursor_t bcmrend_blink_cursor;
286244762Sgonzostatic vr_set_mouse_t bcmrend_set_mouse;
287244762Sgonzostatic vr_draw_mouse_t bcmrend_draw_mouse;
288244762Sgonzo
289244762Sgonzo/*
290244762Sgonzo * We use our own renderer; this is because we must emulate a hardware
291244762Sgonzo * cursor.
292244762Sgonzo */
293244762Sgonzostatic sc_rndr_sw_t bcmrend = {
294244762Sgonzo	bcmrend_init,
295244762Sgonzo	bcmrend_clear,
296244762Sgonzo	bcmrend_draw_border,
297244762Sgonzo	bcmrend_draw,
298244762Sgonzo	bcmrend_set_cursor,
299244762Sgonzo	bcmrend_draw_cursor,
300244762Sgonzo	bcmrend_blink_cursor,
301244762Sgonzo	bcmrend_set_mouse,
302244762Sgonzo	bcmrend_draw_mouse
303244762Sgonzo};
304244762Sgonzo
305244762SgonzoRENDERER(bcmfb, 0, bcmrend, gfb_set);
306239922SgonzoRENDERER_MODULE(bcmfb, gfb_set);
307239922Sgonzo
308244762Sgonzostatic void
309244762Sgonzobcmrend_init(scr_stat* scp)
310244762Sgonzo{
311244762Sgonzo}
312244762Sgonzo
313244762Sgonzostatic void
314244762Sgonzobcmrend_clear(scr_stat* scp, int c, int attr)
315244762Sgonzo{
316244762Sgonzo}
317244762Sgonzo
318244762Sgonzostatic void
319244762Sgonzobcmrend_draw_border(scr_stat* scp, int color)
320244762Sgonzo{
321244762Sgonzo}
322244762Sgonzo
323244762Sgonzostatic void
324244762Sgonzobcmrend_draw(scr_stat* scp, int from, int count, int flip)
325244762Sgonzo{
326244762Sgonzo	video_adapter_t* adp = scp->sc->adp;
327244762Sgonzo	int i, c, a;
328244762Sgonzo
329244762Sgonzo	if (!flip) {
330244762Sgonzo		/* Normal printing */
331244762Sgonzo		vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
332244762Sgonzo	} else {
333244762Sgonzo		/* This is for selections and such: invert the color attribute */
334244762Sgonzo		for (i = count; i-- > 0; ++from) {
335244762Sgonzo			c = sc_vtb_getc(&scp->vtb, from);
336244762Sgonzo			a = sc_vtb_geta(&scp->vtb, from) >> 8;
337244762Sgonzo			vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
338244762Sgonzo		}
339244762Sgonzo	}
340244762Sgonzo}
341244762Sgonzo
342244762Sgonzostatic void
343244762Sgonzobcmrend_set_cursor(scr_stat* scp, int base, int height, int blink)
344244762Sgonzo{
345244762Sgonzo}
346244762Sgonzo
347244762Sgonzostatic void
348244762Sgonzobcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
349244762Sgonzo{
350282358Sloos	int bytes, col, i, j, row;
351282358Sloos	struct bcmsc_softc *sc;
352244762Sgonzo	uint8_t *addr;
353282358Sloos	video_adapter_t *adp;
354244762Sgonzo
355282358Sloos	adp = scp->sc->adp;
356282358Sloos	sc = (struct bcmsc_softc *)adp;
357244762Sgonzo
358244762Sgonzo	if (scp->curs_attr.height <= 0)
359244762Sgonzo		return;
360244762Sgonzo
361244762Sgonzo	if (sc->fb_addr == 0)
362244762Sgonzo		return;
363244762Sgonzo
364244762Sgonzo	if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
365244762Sgonzo		return;
366244762Sgonzo
367244762Sgonzo	/* calculate the coordinates in the video buffer */
368244762Sgonzo	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
369244762Sgonzo	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
370244762Sgonzo
371244762Sgonzo	addr = (uint8_t *)sc->fb_addr
372244762Sgonzo	    + (row + sc->ymargin)*(sc->stride)
373244762Sgonzo	    + (sc->depth/8) * (col + sc->xmargin);
374244762Sgonzo
375282358Sloos	bytes = sc->depth / 8;
376244762Sgonzo	/* our cursor consists of simply inverting the char under it */
377244762Sgonzo	for (i = 0; i < adp->va_info.vi_cheight; i++) {
378244762Sgonzo		for (j = 0; j < adp->va_info.vi_cwidth; j++) {
379244762Sgonzo			switch (sc->depth) {
380244762Sgonzo			case 32:
381244762Sgonzo			case 24:
382244762Sgonzo				addr[bytes*j + 2] ^= 0xff;
383244762Sgonzo				/* FALLTHROUGH */
384244762Sgonzo			case 16:
385244762Sgonzo				addr[bytes*j + 1] ^= 0xff;
386244762Sgonzo				addr[bytes*j] ^= 0xff;
387244762Sgonzo				break;
388244762Sgonzo			default:
389244762Sgonzo				break;
390244762Sgonzo			}
391244762Sgonzo		}
392244762Sgonzo
393244762Sgonzo		addr += sc->stride;
394244762Sgonzo	}
395244762Sgonzo}
396244762Sgonzo
397244762Sgonzostatic void
398244762Sgonzobcmrend_blink_cursor(scr_stat* scp, int at, int flip)
399244762Sgonzo{
400244762Sgonzo}
401244762Sgonzo
402244762Sgonzostatic void
403244762Sgonzobcmrend_set_mouse(scr_stat* scp)
404244762Sgonzo{
405244762Sgonzo}
406244762Sgonzo
407244762Sgonzostatic void
408244762Sgonzobcmrend_draw_mouse(scr_stat* scp, int x, int y, int on)
409244762Sgonzo{
410244762Sgonzo	vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
411244762Sgonzo}
412244762Sgonzo
413239922Sgonzostatic uint16_t bcmfb_static_window[ROW*COL];
414239922Sgonzoextern u_char dflt_font_16[];
415239922Sgonzo
416243423Sgonzo/*
417243423Sgonzo * Update videoadapter settings after changing resolution
418243423Sgonzo */
419243423Sgonzostatic void
420243423Sgonzobcmfb_update_margins(video_adapter_t *adp)
421243423Sgonzo{
422282358Sloos	struct bcmsc_softc *sc;
423243423Sgonzo	video_info_t *vi;
424243423Sgonzo
425282358Sloos	sc = (struct bcmsc_softc *)adp;
426243423Sgonzo	vi = &adp->va_info;
427243423Sgonzo
428243423Sgonzo	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
429282358Sloos	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
430243423Sgonzo}
431243423Sgonzo
432239922Sgonzostatic int
433239922Sgonzobcmfb_configure(int flags)
434239922Sgonzo{
435282358Sloos	char bootargs[2048], *n, *p, *v;
436243423Sgonzo	pcell_t cell;
437282358Sloos	phandle_t chosen, display, root;
438282358Sloos	struct bcmsc_softc *sc;
439239922Sgonzo
440282358Sloos	sc = &bcmsc;
441282358Sloos	if (sc->initialized)
442243423Sgonzo		return (0);
443239922Sgonzo
444282358Sloos	sc->width = 0;
445282358Sloos	sc->height = 0;
446239922Sgonzo
447243423Sgonzo	/*
448243423Sgonzo	 * It seems there is no way to let syscons framework know
449243423Sgonzo	 * that framebuffer resolution has changed. So just try
450282358Sloos	 * to fetch data from FDT bootargs, FDT display data and
451282358Sloos	 * finally go with defaults if everything else has failed.
452243423Sgonzo	 */
453282358Sloos	chosen = OF_finddevice("/chosen");
454282358Sloos	if (chosen != 0 &&
455282358Sloos	    OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) {
456282358Sloos		p = bootargs;
457282358Sloos		while ((v = strsep(&p, " ")) != NULL) {
458282358Sloos			if (*v == '\0')
459282358Sloos				continue;
460282358Sloos			n = strsep(&v, "=");
461282358Sloos			if (strcmp(n, "bcm2708_fb.fbwidth") == 0 && v != NULL)
462282358Sloos				sc->width = (unsigned int)strtol(v, NULL, 0);
463282358Sloos			else if (strcmp(n, "bcm2708_fb.fbheight") == 0 &&
464282358Sloos			    v != NULL)
465282358Sloos				sc->height = (unsigned int)strtol(v, NULL, 0);
466282358Sloos			else if (strcmp(n, "bcm2708_fb.fbswap") == 0 &&
467282358Sloos			    v != NULL)
468282358Sloos				if (*v == '1')
469282358Sloos					sc->fbswap = 1;
470282358Sloos		}
471282358Sloos	}
472282358Sloos
473243423Sgonzo	root = OF_finddevice("/");
474243423Sgonzo	if ((root != 0) &&
475243423Sgonzo	    (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
476282358Sloos		if (sc->width == 0) {
477314503Sian			if ((OF_getencprop(display, "broadcom,width",
478282358Sloos			    &cell, sizeof(cell))) > 0)
479314503Sian				sc->width = cell;
480282358Sloos		}
481239922Sgonzo
482282358Sloos		if (sc->height == 0) {
483282358Sloos			if ((OF_getprop(display, "broadcom,height",
484282358Sloos			    &cell, sizeof(cell))) > 0)
485314503Sian				sc->height = cell;
486282358Sloos		}
487243423Sgonzo	}
488239922Sgonzo
489282358Sloos	if (sc->width == 0)
490282358Sloos		sc->width = FB_WIDTH;
491282358Sloos	if (sc->height == 0)
492282358Sloos		sc->height = FB_HEIGHT;
493243423Sgonzo
494282358Sloos	bcmfb_init(0, &sc->va, 0);
495282358Sloos	sc->initialized = 1;
496243423Sgonzo
497239922Sgonzo	return (0);
498239922Sgonzo}
499239922Sgonzo
500239922Sgonzostatic int
501239922Sgonzobcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
502239922Sgonzo{
503239922Sgonzo
504239922Sgonzo	return (0);
505239922Sgonzo}
506239922Sgonzo
507239922Sgonzostatic int
508239922Sgonzobcmfb_init(int unit, video_adapter_t *adp, int flags)
509239922Sgonzo{
510282358Sloos	struct bcmsc_softc *sc;
511239922Sgonzo	video_info_t *vi;
512239922Sgonzo
513282358Sloos	sc = (struct bcmsc_softc *)adp;
514239922Sgonzo	vi = &adp->va_info;
515239922Sgonzo
516239922Sgonzo	vid_init_struct(adp, "bcmfb", -1, unit);
517239922Sgonzo
518239922Sgonzo	sc->font = dflt_font_16;
519239922Sgonzo	vi->vi_cheight = BCMFB_FONT_HEIGHT;
520282358Sloos	vi->vi_cwidth = BCMFB_FONT_WIDTH;
521282358Sloos	vi->vi_width = sc->width / vi->vi_cwidth;
522282358Sloos	vi->vi_height = sc->height / vi->vi_cheight;
523243423Sgonzo
524239922Sgonzo	/*
525239922Sgonzo	 * Clamp width/height to syscons maximums
526239922Sgonzo	 */
527239922Sgonzo	if (vi->vi_width > COL)
528239922Sgonzo		vi->vi_width = COL;
529239922Sgonzo	if (vi->vi_height > ROW)
530239922Sgonzo		vi->vi_height = ROW;
531239922Sgonzo
532239922Sgonzo	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
533282358Sloos	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
534239922Sgonzo
535239922Sgonzo	adp->va_window = (vm_offset_t) bcmfb_static_window;
536239922Sgonzo	adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
537239922Sgonzo
538239922Sgonzo	vid_register(&sc->va);
539239922Sgonzo
540239922Sgonzo	return (0);
541239922Sgonzo}
542239922Sgonzo
543239922Sgonzostatic int
544239922Sgonzobcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
545239922Sgonzo{
546239922Sgonzo	bcopy(&adp->va_info, info, sizeof(*info));
547239922Sgonzo	return (0);
548239922Sgonzo}
549239922Sgonzo
550239922Sgonzostatic int
551239922Sgonzobcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
552239922Sgonzo{
553239922Sgonzo	return (0);
554239922Sgonzo}
555239922Sgonzo
556239922Sgonzostatic int
557239922Sgonzobcmfb_set_mode(video_adapter_t *adp, int mode)
558239922Sgonzo{
559239922Sgonzo	return (0);
560239922Sgonzo}
561239922Sgonzo
562239922Sgonzostatic int
563239922Sgonzobcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
564239922Sgonzo    u_char *data, int c, int count)
565239922Sgonzo{
566239922Sgonzo	return (0);
567239922Sgonzo}
568239922Sgonzo
569239922Sgonzostatic int
570239922Sgonzobcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
571239922Sgonzo    u_char *data, int c, int count)
572239922Sgonzo{
573282358Sloos	struct bcmsc_softc *sc;
574239922Sgonzo
575282358Sloos	sc = (struct bcmsc_softc *)adp;
576239922Sgonzo	sc->font = data;
577239922Sgonzo
578239922Sgonzo	return (0);
579239922Sgonzo}
580239922Sgonzo
581239922Sgonzostatic int
582239922Sgonzobcmfb_show_font(video_adapter_t *adp, int page)
583239922Sgonzo{
584239922Sgonzo	return (0);
585239922Sgonzo}
586239922Sgonzo
587239922Sgonzostatic int
588239922Sgonzobcmfb_save_palette(video_adapter_t *adp, u_char *palette)
589239922Sgonzo{
590239922Sgonzo	return (0);
591239922Sgonzo}
592239922Sgonzo
593239922Sgonzostatic int
594239922Sgonzobcmfb_load_palette(video_adapter_t *adp, u_char *palette)
595239922Sgonzo{
596239922Sgonzo	return (0);
597239922Sgonzo}
598239922Sgonzo
599239922Sgonzostatic int
600239922Sgonzobcmfb_set_border(video_adapter_t *adp, int border)
601239922Sgonzo{
602239922Sgonzo	return (bcmfb_blank_display(adp, border));
603239922Sgonzo}
604239922Sgonzo
605239922Sgonzostatic int
606239922Sgonzobcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
607239922Sgonzo{
608239922Sgonzo	return (0);
609239922Sgonzo}
610239922Sgonzo
611239922Sgonzostatic int
612239922Sgonzobcmfb_load_state(video_adapter_t *adp, void *p)
613239922Sgonzo{
614239922Sgonzo	return (0);
615239922Sgonzo}
616239922Sgonzo
617239922Sgonzostatic int
618239922Sgonzobcmfb_set_win_org(video_adapter_t *adp, off_t offset)
619239922Sgonzo{
620239922Sgonzo	return (0);
621239922Sgonzo}
622239922Sgonzo
623239922Sgonzostatic int
624239922Sgonzobcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
625239922Sgonzo{
626239922Sgonzo	*col = *row = 0;
627239922Sgonzo
628239922Sgonzo	return (0);
629239922Sgonzo}
630239922Sgonzo
631239922Sgonzostatic int
632239922Sgonzobcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
633239922Sgonzo{
634239922Sgonzo	return (0);
635239922Sgonzo}
636239922Sgonzo
637239922Sgonzostatic int
638239922Sgonzobcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
639239922Sgonzo    int celsize, int blink)
640239922Sgonzo{
641239922Sgonzo	return (0);
642239922Sgonzo}
643239922Sgonzo
644239922Sgonzostatic int
645239922Sgonzobcmfb_blank_display(video_adapter_t *adp, int mode)
646239922Sgonzo{
647239922Sgonzo
648282358Sloos	struct bcmsc_softc *sc;
649243423Sgonzo
650282358Sloos	sc = (struct bcmsc_softc *)adp;
651243423Sgonzo	if (sc && sc->fb_addr)
652243423Sgonzo		memset((void*)sc->fb_addr, 0, sc->fb_size);
653243423Sgonzo
654239922Sgonzo	return (0);
655239922Sgonzo}
656239922Sgonzo
657239922Sgonzostatic int
658239922Sgonzobcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
659239922Sgonzo    int prot, vm_memattr_t *memattr)
660239922Sgonzo{
661282358Sloos	struct bcmsc_softc *sc;
662239922Sgonzo
663282358Sloos	sc = (struct bcmsc_softc *)adp;
664239922Sgonzo
665239922Sgonzo	/*
666239922Sgonzo	 * This might be a legacy VGA mem request: if so, just point it at the
667239922Sgonzo	 * framebuffer, since it shouldn't be touched
668239922Sgonzo	 */
669239922Sgonzo	if (offset < sc->stride*sc->height) {
670245389Sray		*paddr = sc->fb_paddr + offset;
671239922Sgonzo		return (0);
672239922Sgonzo	}
673239922Sgonzo
674239922Sgonzo	return (EINVAL);
675239922Sgonzo}
676239922Sgonzo
677239922Sgonzostatic int
678239922Sgonzobcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
679239922Sgonzo{
680282358Sloos	struct bcmsc_softc *sc;
681245389Sray	struct fbtype *fb;
682239922Sgonzo
683282358Sloos	sc = (struct bcmsc_softc *)adp;
684245389Sray
685245389Sray	switch (cmd) {
686245389Sray	case FBIOGTYPE:
687245389Sray		fb = (struct fbtype *)data;
688245389Sray		fb->fb_type = FBTYPE_PCIMISC;
689245389Sray		fb->fb_height = sc->height;
690245389Sray		fb->fb_width = sc->width;
691245389Sray		fb->fb_depth = sc->depth;
692245389Sray		if (sc->depth <= 1 || sc->depth > 8)
693245389Sray			fb->fb_cmsize = 0;
694245389Sray		else
695245389Sray			fb->fb_cmsize = 1 << sc->depth;
696245389Sray		fb->fb_size = sc->fb_size;
697245389Sray		break;
698245389Sray	default:
699245389Sray		return (fb_commonioctl(adp, cmd, data));
700245389Sray	}
701245389Sray
702239922Sgonzo	return (0);
703239922Sgonzo}
704239922Sgonzo
705239922Sgonzostatic int
706239922Sgonzobcmfb_clear(video_adapter_t *adp)
707239922Sgonzo{
708239922Sgonzo
709239922Sgonzo	return (bcmfb_blank_display(adp, 0));
710239922Sgonzo}
711239922Sgonzo
712239922Sgonzostatic int
713239922Sgonzobcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
714239922Sgonzo{
715239922Sgonzo
716239922Sgonzo	return (0);
717239922Sgonzo}
718239922Sgonzo
719239922Sgonzostatic int
720239922Sgonzobcmfb_bitblt(video_adapter_t *adp, ...)
721239922Sgonzo{
722239922Sgonzo
723239922Sgonzo	return (0);
724239922Sgonzo}
725239922Sgonzo
726239922Sgonzostatic int
727239922Sgonzobcmfb_diag(video_adapter_t *adp, int level)
728239922Sgonzo{
729239922Sgonzo
730239922Sgonzo	return (0);
731239922Sgonzo}
732239922Sgonzo
733239922Sgonzostatic int
734239922Sgonzobcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
735239922Sgonzo{
736239922Sgonzo
737239922Sgonzo	return (0);
738239922Sgonzo}
739239922Sgonzo
740239922Sgonzostatic int
741239922Sgonzobcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
742239922Sgonzo{
743239922Sgonzo
744239922Sgonzo	return (0);
745239922Sgonzo}
746239922Sgonzo
747239922Sgonzostatic int
748239922Sgonzobcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
749239922Sgonzo{
750239922Sgonzo
751239922Sgonzo	return (0);
752239922Sgonzo}
753239922Sgonzo
754239922Sgonzostatic int
755239922Sgonzobcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
756239922Sgonzo    int size, int bpp, int bit_ltor, int byte_ltor)
757239922Sgonzo{
758239922Sgonzo
759239922Sgonzo	return (0);
760239922Sgonzo}
761239922Sgonzo
762239922Sgonzostatic int
763239922Sgonzobcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
764239922Sgonzo{
765282358Sloos	int bytes, col, i, j, k, row;
766282358Sloos	struct bcmsc_softc *sc;
767239922Sgonzo	u_char *p;
768282358Sloos	uint8_t *addr, fg, bg, color;
769243423Sgonzo	uint16_t rgb;
770239922Sgonzo
771282358Sloos	sc = (struct bcmsc_softc *)adp;
772239922Sgonzo
773239922Sgonzo	if (sc->fb_addr == 0)
774239922Sgonzo		return (0);
775239922Sgonzo
776239922Sgonzo	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
777239922Sgonzo	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
778239922Sgonzo	p = sc->font + c*BCMFB_FONT_HEIGHT;
779239922Sgonzo	addr = (uint8_t *)sc->fb_addr
780239922Sgonzo	    + (row + sc->ymargin)*(sc->stride)
781243666Sgonzo	    + (sc->depth/8) * (col + sc->xmargin);
782239922Sgonzo
783243423Sgonzo	fg = a & 0xf ;
784245071Sgonzo	bg = (a >> 4) & 0xf;
785239922Sgonzo
786282358Sloos	bytes = sc->depth / 8;
787239922Sgonzo	for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
788239922Sgonzo		for (j = 0, k = 7; j < 8; j++, k--) {
789239922Sgonzo			if ((p[i] & (1 << k)) == 0)
790239922Sgonzo				color = bg;
791239922Sgonzo			else
792239922Sgonzo				color = fg;
793239922Sgonzo
794243423Sgonzo			switch (sc->depth) {
795243423Sgonzo			case 32:
796243423Sgonzo			case 24:
797282358Sloos				if (sc->fbswap) {
798282358Sloos					addr[bytes * j + 0] =
799282358Sloos					    bcmfb_palette[color].b;
800282358Sloos					addr[bytes * j + 1] =
801282358Sloos					    bcmfb_palette[color].g;
802282358Sloos					addr[bytes * j + 2] =
803282358Sloos					    bcmfb_palette[color].r;
804282358Sloos				} else {
805282358Sloos					addr[bytes * j + 0] =
806282358Sloos					    bcmfb_palette[color].r;
807282358Sloos					addr[bytes * j + 1] =
808282358Sloos					    bcmfb_palette[color].g;
809282358Sloos					addr[bytes * j + 2] =
810282358Sloos					    bcmfb_palette[color].b;
811282358Sloos				}
812282358Sloos				if (sc->depth == 32)
813282358Sloos					addr[bytes * j + 3] =
814282358Sloos					    bcmfb_palette[color].a;
815243423Sgonzo				break;
816243423Sgonzo			case 16:
817243687Sgonzo				rgb = (bcmfb_palette[color].r >> 3) << 11;
818243687Sgonzo				rgb |= (bcmfb_palette[color].g >> 2) << 5;
819243423Sgonzo				rgb |= (bcmfb_palette[color].b >> 3);
820282358Sloos				addr[bytes * j] = rgb & 0xff;
821282358Sloos				addr[bytes * j + 1] = (rgb >> 8) & 0xff;
822243423Sgonzo			default:
823243423Sgonzo				/* Not supported yet */
824243423Sgonzo				break;
825243423Sgonzo			}
826239922Sgonzo		}
827239922Sgonzo
828239922Sgonzo		addr += (sc->stride);
829239922Sgonzo	}
830239922Sgonzo
831239922Sgonzo        return (0);
832239922Sgonzo}
833239922Sgonzo
834239922Sgonzostatic int
835239922Sgonzobcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
836239922Sgonzo{
837239922Sgonzo	int i;
838239922Sgonzo
839239922Sgonzo	for (i = 0; i < len; i++)
840239922Sgonzo		bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
841239922Sgonzo
842239922Sgonzo	return (0);
843239922Sgonzo}
844239922Sgonzo
845239922Sgonzostatic int
846239922Sgonzobcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
847239922Sgonzo    uint32_t pixel_mask, int size, int width)
848239922Sgonzo{
849239922Sgonzo
850239922Sgonzo	return (0);
851239922Sgonzo}
852