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