bcm2835_fbd.c revision 243666
11592Srgrimes/*-
21592Srgrimes * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
31592Srgrimes * All rights reserved.
41592Srgrimes *
51592Srgrimes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
71592Srgrimes * are met:
81592Srgrimes * 1. Redistributions of source code must retain the above copyright
91592Srgrimes *    notice, this list of conditions and the following disclaimer.
101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111592Srgrimes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
131592Srgrimes *
141592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241592Srgrimes * SUCH DAMAGE.
251592Srgrimes *
261592Srgrimes */
271592Srgrimes#include <sys/cdefs.h>
281592Srgrimes__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c 243666 2012-11-29 05:46:46Z gonzo $");
291592Srgrimes
301592Srgrimes#include <sys/param.h>
311592Srgrimes#include <sys/systm.h>
321592Srgrimes#include <sys/bio.h>
331592Srgrimes#include <sys/bus.h>
341592Srgrimes#include <sys/conf.h>
351592Srgrimes#include <sys/endian.h>
361592Srgrimes#include <sys/kernel.h>
371592Srgrimes#include <sys/kthread.h>
381592Srgrimes#include <sys/lock.h>
391592Srgrimes#include <sys/malloc.h>
401592Srgrimes#include <sys/module.h>
411592Srgrimes#include <sys/mutex.h>
421592Srgrimes#include <sys/queue.h>
431592Srgrimes#include <sys/resource.h>
441592Srgrimes#include <sys/rman.h>
451592Srgrimes#include <sys/time.h>
461592Srgrimes#include <sys/timetc.h>
471592Srgrimes#include <sys/fbio.h>
481592Srgrimes#include <sys/consio.h>
491592Srgrimes
501592Srgrimes#include <sys/kdb.h>
511592Srgrimes
521592Srgrimes#include <machine/bus.h>
531592Srgrimes#include <machine/cpu.h>
541592Srgrimes#include <machine/cpufunc.h>
551592Srgrimes#include <machine/resource.h>
561592Srgrimes#include <machine/frame.h>
571592Srgrimes#include <machine/intr.h>
581592Srgrimes
591592Srgrimes#include <dev/fdt/fdt_common.h>
601592Srgrimes#include <dev/ofw/ofw_bus.h>
611592Srgrimes#include <dev/ofw/ofw_bus_subr.h>
621592Srgrimes
631592Srgrimes#include <dev/fb/fbreg.h>
641592Srgrimes#include <dev/syscons/syscons.h>
651592Srgrimes
661592Srgrimes#include <arm/broadcom/bcm2835/bcm2835_mbox.h>
671592Srgrimes#include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
681592Srgrimes
691592Srgrimes#define	BCMFB_FONT_HEIGHT	16
701592Srgrimes
711592Srgrimesstruct argb {
721592Srgrimes	uint8_t		a;
731592Srgrimes	uint8_t		r;
741592Srgrimes	uint8_t		g;
751592Srgrimes	uint8_t		b;
761592Srgrimes};
771592Srgrimes
781592Srgrimesstatic struct argb bcmfb_palette[16] = {
791592Srgrimes	{0x00, 0x00, 0x00, 0x00},
801592Srgrimes	{0x00, 0x00, 0x00, 0xaa},
811592Srgrimes	{0x00, 0x00, 0xaa, 0x00},
821592Srgrimes	{0x00, 0x00, 0xaa, 0xaa},
831592Srgrimes	{0x00, 0xaa, 0x00, 0x00},
841592Srgrimes	{0x00, 0xaa, 0x00, 0xaa},
851592Srgrimes	{0x00, 0xaa, 0x55, 0x00},
861592Srgrimes	{0x00, 0xaa, 0xaa, 0xaa},
871592Srgrimes	{0x00, 0x55, 0x55, 0x55},
881592Srgrimes	{0x00, 0x55, 0x55, 0xff},
891592Srgrimes	{0x00, 0x55, 0xff, 0x55},
901592Srgrimes	{0x00, 0x55, 0xff, 0xff},
911592Srgrimes	{0x00, 0xff, 0x55, 0x55},
921592Srgrimes	{0x00, 0xff, 0x55, 0xff},
931592Srgrimes	{0x00, 0xff, 0xff, 0x55},
941592Srgrimes	{0x00, 0xff, 0xff, 0xff}
951592Srgrimes};
961592Srgrimes
971592Srgrimes#define FB_WIDTH		640
981592Srgrimes#define FB_HEIGHT		480
991592Srgrimes#define FB_DEPTH		24
1001592Srgrimes
1011592Srgrimesstruct bcm_fb_config {
1021592Srgrimes	uint32_t	xres;
1031592Srgrimes	uint32_t	yres;
1041592Srgrimes	uint32_t	vxres;
1051592Srgrimes	uint32_t	vyres;
1061592Srgrimes	uint32_t	pitch;
1071592Srgrimes	uint32_t	bpp;
1081592Srgrimes	uint32_t	xoffset;
1091592Srgrimes	uint32_t	yoffset;
1101592Srgrimes	/* Filled by videocore */
1111592Srgrimes	uint32_t	base;
1121592Srgrimes	uint32_t	screen_size;
1131592Srgrimes};
1141592Srgrimes
1151592Srgrimesstruct bcmsc_softc {
1161592Srgrimes	device_t		dev;
1171592Srgrimes	struct cdev *		cdev;
1181592Srgrimes	struct mtx		mtx;
1191592Srgrimes	bus_dma_tag_t		dma_tag;
1201592Srgrimes	bus_dmamap_t		dma_map;
1211592Srgrimes	struct bcm_fb_config*	fb_config;
1221592Srgrimes	bus_addr_t		fb_config_phys;
1231592Srgrimes	struct intr_config_hook	init_hook;
1241592Srgrimes
1251592Srgrimes};
1261592Srgrimes
1271592Srgrimesstruct video_adapter_softc {
1281592Srgrimes	/* Videoadpater part */
1291592Srgrimes	video_adapter_t	va;
1301592Srgrimes	int		console;
1311592Srgrimes
1321592Srgrimes	intptr_t	fb_addr;
1331592Srgrimes	unsigned int	fb_size;
1341592Srgrimes
1351592Srgrimes	unsigned int	height;
1361592Srgrimes	unsigned int	width;
1371592Srgrimes	unsigned int	depth;
1381592Srgrimes	unsigned int	stride;
1391592Srgrimes
1401592Srgrimes	unsigned int	xmargin;
1411592Srgrimes	unsigned int	ymargin;
1421592Srgrimes
1431592Srgrimes	unsigned char	*font;
1441592Srgrimes	int		initialized;
1451592Srgrimes};
1461592Srgrimes
1471592Srgrimesstatic struct bcmsc_softc *bcmsc_softc;
1481592Srgrimesstatic struct video_adapter_softc va_softc;
1491592Srgrimes
1501592Srgrimes#define	bcm_fb_lock(_sc)	mtx_lock(&(_sc)->mtx)
1511592Srgrimes#define	bcm_fb_unlock(_sc)	mtx_unlock(&(_sc)->mtx)
1521592Srgrimes#define	bcm_fb_lock_assert(sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
1531592Srgrimes
1541592Srgrimesstatic int bcm_fb_probe(device_t);
1551592Srgrimesstatic int bcm_fb_attach(device_t);
1561592Srgrimesstatic void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err);
1571592Srgrimesstatic void bcmfb_update_margins(video_adapter_t *adp);
1581592Srgrimesstatic int bcmfb_configure(int);
1591592Srgrimes
1601592Srgrimesstatic void
1611592Srgrimesbcm_fb_init(void *arg)
1621592Srgrimes{
1631592Srgrimes	struct bcmsc_softc *sc = arg;
1641592Srgrimes	struct video_adapter_softc *va_sc = &va_softc;
1651592Srgrimes	int err;
1661592Srgrimes	volatile struct bcm_fb_config*	fb_config = sc->fb_config;
1671592Srgrimes	phandle_t node;
1681592Srgrimes	pcell_t cell;
1691592Srgrimes
1701592Srgrimes	node = ofw_bus_get_node(sc->dev);
1711592Srgrimes
1721592Srgrimes	fb_config->xres = 0;
1731592Srgrimes	fb_config->yres = 0;
1741592Srgrimes	fb_config->bpp = 0;
1751592Srgrimes
1761592Srgrimes	if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0)
1771592Srgrimes		fb_config->xres = (int)fdt32_to_cpu(cell);
1781592Srgrimes	if (fb_config->xres == 0)
1791592Srgrimes		fb_config->xres = FB_WIDTH;
1801592Srgrimes
1811592Srgrimes	if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0)
1821592Srgrimes		fb_config->yres = (uint32_t)fdt32_to_cpu(cell);
1831592Srgrimes	if (fb_config->yres == 0)
1841592Srgrimes		fb_config->yres = FB_HEIGHT;
1851592Srgrimes
1861592Srgrimes	if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0)
1871592Srgrimes		fb_config->bpp = (uint32_t)fdt32_to_cpu(cell);
1881592Srgrimes	if (fb_config->bpp == 0)
1891592Srgrimes		fb_config->bpp = FB_DEPTH;
1901592Srgrimes
1911592Srgrimes	fb_config->vxres = 0;
1921592Srgrimes	fb_config->vyres = 0;
1931592Srgrimes	fb_config->xoffset = 0;
1941592Srgrimes	fb_config->yoffset = 0;
1951592Srgrimes	fb_config->base = 0;
1961592Srgrimes	fb_config->pitch = 0;
1971592Srgrimes	fb_config->screen_size = 0;
1981592Srgrimes
1991592Srgrimes	bus_dmamap_sync(sc->dma_tag, sc->dma_map,
2001592Srgrimes		BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
2011592Srgrimes	bcm_mbox_write(BCM2835_MBOX_CHAN_FB, sc->fb_config_phys);
2021592Srgrimes	bcm_mbox_read(BCM2835_MBOX_CHAN_FB, &err);
2031592Srgrimes	bus_dmamap_sync(sc->dma_tag, sc->dma_map,
2041592Srgrimes		BUS_DMASYNC_POSTREAD);
2051592Srgrimes
2061592Srgrimes	if (fb_config->base != 0) {
2071592Srgrimes		device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n",
2081592Srgrimes			fb_config->xres, fb_config->yres,
2091592Srgrimes			fb_config->vxres, fb_config->vyres,
2101592Srgrimes			fb_config->xoffset, fb_config->yoffset,
2111592Srgrimes			fb_config->bpp);
2121592Srgrimes
2131592Srgrimes
2141592Srgrimes		device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n",
2151592Srgrimes			fb_config->pitch, fb_config->base,
2161592Srgrimes			fb_config->screen_size);
2171592Srgrimes
2181592Srgrimes		va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size);
2191592Srgrimes		va_sc->fb_size = fb_config->screen_size;
2201592Srgrimes		va_sc->depth = fb_config->bpp;
2211592Srgrimes		va_sc->stride = fb_config->pitch;
2221592Srgrimes
2231592Srgrimes		va_sc->width = fb_config->xres;
2241592Srgrimes		va_sc->height = fb_config->yres;
2251592Srgrimes		bcmfb_update_margins(&va_sc->va);
2261592Srgrimes	}
2271592Srgrimes	else {
2281592Srgrimes		device_printf(sc->dev, "Failed to set framebuffer info\n");
2291592Srgrimes		return;
2301592Srgrimes	}
2311592Srgrimes
2321592Srgrimes	config_intrhook_disestablish(&sc->init_hook);
2331592Srgrimes}
2341592Srgrimes
2351592Srgrimesstatic int
2361592Srgrimesbcm_fb_probe(device_t dev)
2371592Srgrimes{
2381592Srgrimes	int error = 0;
2391592Srgrimes
2401592Srgrimes	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb"))
2411592Srgrimes		return (ENXIO);
2421592Srgrimes
2431592Srgrimes	device_set_desc(dev, "BCM2835 framebuffer device");
2441592Srgrimes
2451592Srgrimes	error = sc_probe_unit(device_get_unit(dev),
2461592Srgrimes	    device_get_flags(dev) | SC_AUTODETECT_KBD);
2471592Srgrimes	if (error != 0)
2481592Srgrimes		return (error);
2491592Srgrimes
2501592Srgrimes
2511592Srgrimes	return (BUS_PROBE_DEFAULT);
2521592Srgrimes}
2531592Srgrimes
2541592Srgrimesstatic int
2551592Srgrimesbcm_fb_attach(device_t dev)
2561592Srgrimes{
2571592Srgrimes	struct bcmsc_softc *sc = device_get_softc(dev);
2581592Srgrimes	int dma_size = sizeof(struct bcm_fb_config);
2591592Srgrimes	int err;
2601592Srgrimes
2611592Srgrimes	if (bcmsc_softc)
2621592Srgrimes		return (ENXIO);
2631592Srgrimes
2641592Srgrimes	bcmsc_softc = sc;
2651592Srgrimes
2661592Srgrimes	sc->dev = dev;
2671592Srgrimes	mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF);
2681592Srgrimes
2691592Srgrimes	err = bus_dma_tag_create(
2701592Srgrimes	    bus_get_dma_tag(sc->dev),
2711592Srgrimes	    PAGE_SIZE, 0,		/* alignment, boundary */
2721592Srgrimes	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
2731592Srgrimes	    BUS_SPACE_MAXADDR,		/* highaddr */
2741592Srgrimes	    NULL, NULL,			/* filter, filterarg */
2751592Srgrimes	    dma_size, 1,		/* maxsize, nsegments */
2761592Srgrimes	    dma_size, 0,		/* maxsegsize, flags */
2771592Srgrimes	    NULL, NULL,			/* lockfunc, lockarg */
2781592Srgrimes	    &sc->dma_tag);
2791592Srgrimes
2801592Srgrimes	err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config,
2811592Srgrimes	    0, &sc->dma_map);
2821592Srgrimes	if (err) {
2831592Srgrimes		device_printf(dev, "cannot allocate framebuffer\n");
2841592Srgrimes		goto fail;
2851592Srgrimes	}
2861592Srgrimes
2871592Srgrimes	err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config,
2881592Srgrimes	    dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT);
2891592Srgrimes
2901592Srgrimes	if (err) {
2911592Srgrimes		device_printf(dev, "cannot load DMA map\n");
2921592Srgrimes		goto fail;
2931592Srgrimes	}
2941592Srgrimes
2951592Srgrimes	err = (sc_attach_unit(device_get_unit(dev),
2961592Srgrimes	    device_get_flags(dev) | SC_AUTODETECT_KBD));
2971592Srgrimes
2981592Srgrimes	if (err) {
2991592Srgrimes		device_printf(dev, "failed to attach syscons\n");
3001592Srgrimes		goto fail;
3011592Srgrimes	}
3021592Srgrimes
3031592Srgrimes	/*
3041592Srgrimes	 * We have to wait until interrupts are enabled.
3051592Srgrimes	 * Mailbox relies on it to get data from VideoCore
3061592Srgrimes	 */
3071592Srgrimes        sc->init_hook.ich_func = bcm_fb_init;
3081592Srgrimes        sc->init_hook.ich_arg = sc;
3091592Srgrimes
3101592Srgrimes        if (config_intrhook_establish(&sc->init_hook) != 0) {
3111592Srgrimes		device_printf(dev, "failed to establish intrhook\n");
3121592Srgrimes                return (ENOMEM);
3131592Srgrimes	}
3141592Srgrimes
3151592Srgrimes	return (0);
3161592Srgrimes
3171592Srgrimesfail:
3181592Srgrimes	return (ENXIO);
3191592Srgrimes}
3201592Srgrimes
3211592Srgrimes
3221592Srgrimesstatic void
3231592Srgrimesbcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
3241592Srgrimes{
3251592Srgrimes	bus_addr_t *addr;
3261592Srgrimes
3271592Srgrimes	if (err)
3281592Srgrimes		return;
3291592Srgrimes
3301592Srgrimes	addr = (bus_addr_t*)arg;
3311592Srgrimes	*addr = PHYS_TO_VCBUS(segs[0].ds_addr);
3321592Srgrimes}
3331592Srgrimes
3341592Srgrimesstatic device_method_t bcm_fb_methods[] = {
3351592Srgrimes	/* Device interface */
3361592Srgrimes	DEVMETHOD(device_probe,		bcm_fb_probe),
3371592Srgrimes	DEVMETHOD(device_attach,	bcm_fb_attach),
3381592Srgrimes
3391592Srgrimes	{ 0, 0 }
3401592Srgrimes};
3411592Srgrimes
3421592Srgrimesstatic devclass_t bcm_fb_devclass;
3431592Srgrimes
3441592Srgrimesstatic driver_t bcm_fb_driver = {
3451592Srgrimes	"fb",
3461592Srgrimes	bcm_fb_methods,
3471592Srgrimes	sizeof(struct bcmsc_softc),
3481592Srgrimes};
3491592Srgrimes
3501592SrgrimesDRIVER_MODULE(bcm2835fb, fdtbus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
3511592Srgrimes
3521592Srgrimes/*
3531592Srgrimes * Video driver routines and glue.
3541592Srgrimes */
3551592Srgrimesstatic vi_probe_t		bcmfb_probe;
3561592Srgrimesstatic vi_init_t		bcmfb_init;
3571592Srgrimesstatic vi_get_info_t		bcmfb_get_info;
3581592Srgrimesstatic vi_query_mode_t		bcmfb_query_mode;
3591592Srgrimesstatic vi_set_mode_t		bcmfb_set_mode;
3601592Srgrimesstatic vi_save_font_t		bcmfb_save_font;
3611592Srgrimesstatic vi_load_font_t		bcmfb_load_font;
3621592Srgrimesstatic vi_show_font_t		bcmfb_show_font;
3631592Srgrimesstatic vi_save_palette_t	bcmfb_save_palette;
3641592Srgrimesstatic vi_load_palette_t	bcmfb_load_palette;
3651592Srgrimesstatic vi_set_border_t		bcmfb_set_border;
3661592Srgrimesstatic vi_save_state_t		bcmfb_save_state;
3671592Srgrimesstatic vi_load_state_t		bcmfb_load_state;
3681592Srgrimesstatic vi_set_win_org_t		bcmfb_set_win_org;
3691592Srgrimesstatic vi_read_hw_cursor_t	bcmfb_read_hw_cursor;
3701592Srgrimesstatic vi_set_hw_cursor_t	bcmfb_set_hw_cursor;
3711592Srgrimesstatic vi_set_hw_cursor_shape_t	bcmfb_set_hw_cursor_shape;
3721592Srgrimesstatic vi_blank_display_t	bcmfb_blank_display;
3731592Srgrimesstatic vi_mmap_t		bcmfb_mmap;
3741592Srgrimesstatic vi_ioctl_t		bcmfb_ioctl;
3751592Srgrimesstatic vi_clear_t		bcmfb_clear;
3761592Srgrimesstatic vi_fill_rect_t		bcmfb_fill_rect;
3771592Srgrimesstatic vi_bitblt_t		bcmfb_bitblt;
3781592Srgrimesstatic vi_diag_t		bcmfb_diag;
3791592Srgrimesstatic vi_save_cursor_palette_t	bcmfb_save_cursor_palette;
3801592Srgrimesstatic vi_load_cursor_palette_t	bcmfb_load_cursor_palette;
3811592Srgrimesstatic vi_copy_t		bcmfb_copy;
3821592Srgrimesstatic vi_putp_t		bcmfb_putp;
3831592Srgrimesstatic vi_putc_t		bcmfb_putc;
3841592Srgrimesstatic vi_puts_t		bcmfb_puts;
3851592Srgrimesstatic vi_putm_t		bcmfb_putm;
3861592Srgrimes
3871592Srgrimesstatic video_switch_t bcmfbvidsw = {
3881592Srgrimes	.probe			= bcmfb_probe,
3891592Srgrimes	.init			= bcmfb_init,
3901592Srgrimes	.get_info		= bcmfb_get_info,
3911592Srgrimes	.query_mode		= bcmfb_query_mode,
3921592Srgrimes	.set_mode		= bcmfb_set_mode,
3931592Srgrimes	.save_font		= bcmfb_save_font,
3941592Srgrimes	.load_font		= bcmfb_load_font,
3951592Srgrimes	.show_font		= bcmfb_show_font,
3961592Srgrimes	.save_palette		= bcmfb_save_palette,
3971592Srgrimes	.load_palette		= bcmfb_load_palette,
3981592Srgrimes	.set_border		= bcmfb_set_border,
3991592Srgrimes	.save_state		= bcmfb_save_state,
4001592Srgrimes	.load_state		= bcmfb_load_state,
4011592Srgrimes	.set_win_org		= bcmfb_set_win_org,
4021592Srgrimes	.read_hw_cursor		= bcmfb_read_hw_cursor,
4031592Srgrimes	.set_hw_cursor		= bcmfb_set_hw_cursor,
4041592Srgrimes	.set_hw_cursor_shape	= bcmfb_set_hw_cursor_shape,
4051592Srgrimes	.blank_display		= bcmfb_blank_display,
4061592Srgrimes	.mmap			= bcmfb_mmap,
4071592Srgrimes	.ioctl			= bcmfb_ioctl,
4081592Srgrimes	.clear			= bcmfb_clear,
4091592Srgrimes	.fill_rect		= bcmfb_fill_rect,
4101592Srgrimes	.bitblt			= bcmfb_bitblt,
4111592Srgrimes	.diag			= bcmfb_diag,
4121592Srgrimes	.save_cursor_palette	= bcmfb_save_cursor_palette,
4131592Srgrimes	.load_cursor_palette	= bcmfb_load_cursor_palette,
4141592Srgrimes	.copy			= bcmfb_copy,
4151592Srgrimes	.putp			= bcmfb_putp,
4161592Srgrimes	.putc			= bcmfb_putc,
4171592Srgrimes	.puts			= bcmfb_puts,
4181592Srgrimes	.putm			= bcmfb_putm,
4191592Srgrimes};
4201592Srgrimes
4211592SrgrimesVIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
4221592Srgrimes
4231592Srgrimesextern sc_rndr_sw_t txtrndrsw;
4241592SrgrimesRENDERER(bcmfb, 0, txtrndrsw, gfb_set);
4251592SrgrimesRENDERER_MODULE(bcmfb, gfb_set);
4261592Srgrimes
4271592Srgrimesstatic uint16_t bcmfb_static_window[ROW*COL];
4281592Srgrimesextern u_char dflt_font_16[];
4291592Srgrimes
4301592Srgrimes/*
4311592Srgrimes * Update videoadapter settings after changing resolution
4321592Srgrimes */
4331592Srgrimesstatic void
4341592Srgrimesbcmfb_update_margins(video_adapter_t *adp)
4351592Srgrimes{
4361592Srgrimes	struct video_adapter_softc *sc;
4371592Srgrimes	video_info_t *vi;
4381592Srgrimes
4391592Srgrimes	sc = (struct video_adapter_softc *)adp;
4401592Srgrimes	vi = &adp->va_info;
4411592Srgrimes
4421592Srgrimes	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
4431592Srgrimes	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
4441592Srgrimes}
4451592Srgrimes
4461592Srgrimesstatic int
4471592Srgrimesbcmfb_configure(int flags)
4481592Srgrimes{
4491592Srgrimes	struct video_adapter_softc *va_sc;
4501592Srgrimes
4511592Srgrimes	va_sc = &va_softc;
4521592Srgrimes	phandle_t display, root;
4531592Srgrimes	pcell_t cell;
4541592Srgrimes
4551592Srgrimes	if (va_sc->initialized)
4561592Srgrimes		return (0);
4571592Srgrimes
4581592Srgrimes	va_sc->width = 0;
4591592Srgrimes	va_sc->height = 0;
4601592Srgrimes
4611592Srgrimes	/*
4621592Srgrimes	 * It seems there is no way to let syscons framework know
4631592Srgrimes	 * that framebuffer resolution has changed. So just try
4641592Srgrimes	 * to fetch data from FDT and go with defaults if failed
4651592Srgrimes	 */
4661592Srgrimes	root = OF_finddevice("/");
4671592Srgrimes	if ((root != 0) &&
4681592Srgrimes	    (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
4691592Srgrimes		if ((OF_getprop(display, "broadcom,width",
4701592Srgrimes		    &cell, sizeof(cell))) > 0)
4711592Srgrimes			va_sc->width = (int)fdt32_to_cpu(cell);
4721592Srgrimes
4731592Srgrimes		if ((OF_getprop(display, "broadcom,height",
4741592Srgrimes		    &cell, sizeof(cell))) > 0)
4751592Srgrimes			va_sc->height = (int)fdt32_to_cpu(cell);
4761592Srgrimes	}
4771592Srgrimes
4781592Srgrimes	if (va_sc->width == 0)
4791592Srgrimes		va_sc->width = FB_WIDTH;
4801592Srgrimes	if (va_sc->height == 0)
4811592Srgrimes		va_sc->height = FB_HEIGHT;
4821592Srgrimes
4831592Srgrimes	bcmfb_init(0, &va_sc->va, 0);
4841592Srgrimes
4851592Srgrimes	va_sc->initialized = 1;
4861592Srgrimes
4871592Srgrimes	return (0);
4881592Srgrimes}
4891592Srgrimes
4901592Srgrimesstatic int
4911592Srgrimesbcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
4921592Srgrimes{
4931592Srgrimes
4941592Srgrimes	return (0);
4951592Srgrimes}
4961592Srgrimes
4971592Srgrimesstatic int
4981592Srgrimesbcmfb_init(int unit, video_adapter_t *adp, int flags)
4991592Srgrimes{
5001592Srgrimes	struct video_adapter_softc *sc;
5011592Srgrimes	video_info_t *vi;
5021592Srgrimes
5031592Srgrimes	sc = (struct video_adapter_softc *)adp;
5041592Srgrimes	vi = &adp->va_info;
5051592Srgrimes
5061592Srgrimes	vid_init_struct(adp, "bcmfb", -1, unit);
5071592Srgrimes
5081592Srgrimes	sc->font = dflt_font_16;
5091592Srgrimes	vi->vi_cheight = BCMFB_FONT_HEIGHT;
5101592Srgrimes	vi->vi_cwidth = 8;
5111592Srgrimes
5121592Srgrimes	vi->vi_width = sc->width/8;
5131592Srgrimes	vi->vi_height = sc->height/vi->vi_cheight;
5141592Srgrimes
5151592Srgrimes	/*
5161592Srgrimes	 * Clamp width/height to syscons maximums
5171592Srgrimes	 */
5181592Srgrimes	if (vi->vi_width > COL)
5191592Srgrimes		vi->vi_width = COL;
5201592Srgrimes	if (vi->vi_height > ROW)
5211592Srgrimes		vi->vi_height = ROW;
5221592Srgrimes
5231592Srgrimes	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
5241592Srgrimes	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
5251592Srgrimes
5261592Srgrimes
5271592Srgrimes	adp->va_window = (vm_offset_t) bcmfb_static_window;
5281592Srgrimes	adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
5291592Srgrimes
5301592Srgrimes	vid_register(&sc->va);
5311592Srgrimes
532	return (0);
533}
534
535static int
536bcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
537{
538	bcopy(&adp->va_info, info, sizeof(*info));
539	return (0);
540}
541
542static int
543bcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
544{
545	return (0);
546}
547
548static int
549bcmfb_set_mode(video_adapter_t *adp, int mode)
550{
551	return (0);
552}
553
554static int
555bcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
556    u_char *data, int c, int count)
557{
558	return (0);
559}
560
561static int
562bcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
563    u_char *data, int c, int count)
564{
565	struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
566
567	sc->font = data;
568
569	return (0);
570}
571
572static int
573bcmfb_show_font(video_adapter_t *adp, int page)
574{
575	return (0);
576}
577
578static int
579bcmfb_save_palette(video_adapter_t *adp, u_char *palette)
580{
581	return (0);
582}
583
584static int
585bcmfb_load_palette(video_adapter_t *adp, u_char *palette)
586{
587	return (0);
588}
589
590static int
591bcmfb_set_border(video_adapter_t *adp, int border)
592{
593	return (bcmfb_blank_display(adp, border));
594}
595
596static int
597bcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
598{
599	return (0);
600}
601
602static int
603bcmfb_load_state(video_adapter_t *adp, void *p)
604{
605	return (0);
606}
607
608static int
609bcmfb_set_win_org(video_adapter_t *adp, off_t offset)
610{
611	return (0);
612}
613
614static int
615bcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
616{
617	*col = *row = 0;
618
619	return (0);
620}
621
622static int
623bcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
624{
625	return (0);
626}
627
628static int
629bcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
630    int celsize, int blink)
631{
632	return (0);
633}
634
635static int
636bcmfb_blank_display(video_adapter_t *adp, int mode)
637{
638
639	struct video_adapter_softc *sc;
640
641	sc = (struct video_adapter_softc *)adp;
642	if (sc && sc->fb_addr)
643		memset((void*)sc->fb_addr, 0, sc->fb_size);
644
645	return (0);
646}
647
648static int
649bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
650    int prot, vm_memattr_t *memattr)
651{
652	struct video_adapter_softc *sc;
653
654	sc = (struct video_adapter_softc *)adp;
655
656	/*
657	 * This might be a legacy VGA mem request: if so, just point it at the
658	 * framebuffer, since it shouldn't be touched
659	 */
660	if (offset < sc->stride*sc->height) {
661		*paddr = sc->fb_addr + offset;
662		return (0);
663	}
664
665	return (EINVAL);
666}
667
668static int
669bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
670{
671
672	return (0);
673}
674
675static int
676bcmfb_clear(video_adapter_t *adp)
677{
678
679	return (bcmfb_blank_display(adp, 0));
680}
681
682static int
683bcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
684{
685
686	return (0);
687}
688
689static int
690bcmfb_bitblt(video_adapter_t *adp, ...)
691{
692
693	return (0);
694}
695
696static int
697bcmfb_diag(video_adapter_t *adp, int level)
698{
699
700	return (0);
701}
702
703static int
704bcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
705{
706
707	return (0);
708}
709
710static int
711bcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
712{
713
714	return (0);
715}
716
717static int
718bcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
719{
720
721	return (0);
722}
723
724static int
725bcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
726    int size, int bpp, int bit_ltor, int byte_ltor)
727{
728
729	return (0);
730}
731
732static int
733bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
734{
735	struct video_adapter_softc *sc;
736	int row;
737	int col;
738	int i, j, k;
739	uint8_t *addr;
740	u_char *p;
741	uint8_t fg, bg, color;
742	uint16_t rgb;
743
744	sc = (struct video_adapter_softc *)adp;
745
746	if (sc->fb_addr == 0)
747		return (0);
748
749	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
750	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
751	p = sc->font + c*BCMFB_FONT_HEIGHT;
752	addr = (uint8_t *)sc->fb_addr
753	    + (row + sc->ymargin)*(sc->stride)
754	    + (sc->depth/8) * (col + sc->xmargin);
755
756	fg = a & 0xf ;
757	bg = (a >> 8) & 0xf;
758
759	for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
760		for (j = 0, k = 7; j < 8; j++, k--) {
761			if ((p[i] & (1 << k)) == 0)
762				color = bg;
763			else
764				color = fg;
765
766			switch (sc->depth) {
767			case 32:
768				addr[4*j+0] = bcmfb_palette[color].r;
769				addr[4*j+1] = bcmfb_palette[color].g;
770				addr[4*j+2] = bcmfb_palette[color].b;
771				addr[4*j+3] = bcmfb_palette[color].a;
772				break;
773			case 24:
774				addr[3*j] = bcmfb_palette[color].r;
775				addr[3*j+1] = bcmfb_palette[color].g;
776				addr[3*j+2] = bcmfb_palette[color].b;
777				break;
778			case 16:
779				rgb = (bcmfb_palette[color].r >> 3) << 10;
780				rgb |= (bcmfb_palette[color].g >> 3) << 5;
781				rgb |= (bcmfb_palette[color].b >> 3);
782				addr[2*j] = (rgb >> 8) & 0xff;
783				addr[2*j + 1] = rgb & 0xff;
784			default:
785				/* Not supported yet */
786				break;
787			}
788		}
789
790		addr += (sc->stride);
791	}
792
793        return (0);
794}
795
796static int
797bcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
798{
799	int i;
800
801	for (i = 0; i < len; i++)
802		bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
803
804	return (0);
805}
806
807static int
808bcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
809    uint32_t pixel_mask, int size, int width)
810{
811
812	return (0);
813}
814
815/*
816 * Define a stub keyboard driver in case one hasn't been
817 * compiled into the kernel
818 */
819#include <sys/kbio.h>
820#include <dev/kbd/kbdreg.h>
821
822static int dummy_kbd_configure(int flags);
823
824keyboard_switch_t bcmdummysw;
825
826static int
827dummy_kbd_configure(int flags)
828{
829
830	return (0);
831}
832KEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure);
833