bcm2835_fbd.c revision 243666
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: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c 243666 2012-11-29 05:46:46Z gonzo $"); 29239922Sgonzo 30239922Sgonzo#include <sys/param.h> 31239922Sgonzo#include <sys/systm.h> 32239922Sgonzo#include <sys/bio.h> 33239922Sgonzo#include <sys/bus.h> 34239922Sgonzo#include <sys/conf.h> 35239922Sgonzo#include <sys/endian.h> 36239922Sgonzo#include <sys/kernel.h> 37239922Sgonzo#include <sys/kthread.h> 38239922Sgonzo#include <sys/lock.h> 39239922Sgonzo#include <sys/malloc.h> 40239922Sgonzo#include <sys/module.h> 41239922Sgonzo#include <sys/mutex.h> 42239922Sgonzo#include <sys/queue.h> 43239922Sgonzo#include <sys/resource.h> 44239922Sgonzo#include <sys/rman.h> 45239922Sgonzo#include <sys/time.h> 46239922Sgonzo#include <sys/timetc.h> 47239922Sgonzo#include <sys/fbio.h> 48239922Sgonzo#include <sys/consio.h> 49239922Sgonzo 50239922Sgonzo#include <sys/kdb.h> 51239922Sgonzo 52239922Sgonzo#include <machine/bus.h> 53239922Sgonzo#include <machine/cpu.h> 54239922Sgonzo#include <machine/cpufunc.h> 55239922Sgonzo#include <machine/resource.h> 56239922Sgonzo#include <machine/frame.h> 57239922Sgonzo#include <machine/intr.h> 58239922Sgonzo 59239922Sgonzo#include <dev/fdt/fdt_common.h> 60239922Sgonzo#include <dev/ofw/ofw_bus.h> 61239922Sgonzo#include <dev/ofw/ofw_bus_subr.h> 62239922Sgonzo 63239922Sgonzo#include <dev/fb/fbreg.h> 64239922Sgonzo#include <dev/syscons/syscons.h> 65239922Sgonzo 66239922Sgonzo#include <arm/broadcom/bcm2835/bcm2835_mbox.h> 67239922Sgonzo#include <arm/broadcom/bcm2835/bcm2835_vcbus.h> 68239922Sgonzo 69239922Sgonzo#define BCMFB_FONT_HEIGHT 16 70239922Sgonzo 71243423Sgonzostruct argb { 72243423Sgonzo uint8_t a; 73243423Sgonzo uint8_t r; 74243423Sgonzo uint8_t g; 75243423Sgonzo uint8_t b; 76243423Sgonzo}; 77243423Sgonzo 78243423Sgonzostatic struct argb bcmfb_palette[16] = { 79243423Sgonzo {0x00, 0x00, 0x00, 0x00}, 80243423Sgonzo {0x00, 0x00, 0x00, 0xaa}, 81243423Sgonzo {0x00, 0x00, 0xaa, 0x00}, 82243423Sgonzo {0x00, 0x00, 0xaa, 0xaa}, 83243423Sgonzo {0x00, 0xaa, 0x00, 0x00}, 84243423Sgonzo {0x00, 0xaa, 0x00, 0xaa}, 85243423Sgonzo {0x00, 0xaa, 0x55, 0x00}, 86243423Sgonzo {0x00, 0xaa, 0xaa, 0xaa}, 87243423Sgonzo {0x00, 0x55, 0x55, 0x55}, 88243423Sgonzo {0x00, 0x55, 0x55, 0xff}, 89243423Sgonzo {0x00, 0x55, 0xff, 0x55}, 90243423Sgonzo {0x00, 0x55, 0xff, 0xff}, 91243423Sgonzo {0x00, 0xff, 0x55, 0x55}, 92243423Sgonzo {0x00, 0xff, 0x55, 0xff}, 93243423Sgonzo {0x00, 0xff, 0xff, 0x55}, 94243423Sgonzo {0x00, 0xff, 0xff, 0xff} 95243423Sgonzo}; 96243423Sgonzo 97239922Sgonzo#define FB_WIDTH 640 98239922Sgonzo#define FB_HEIGHT 480 99243423Sgonzo#define FB_DEPTH 24 100239922Sgonzo 101239922Sgonzostruct bcm_fb_config { 102239922Sgonzo uint32_t xres; 103239922Sgonzo uint32_t yres; 104239922Sgonzo uint32_t vxres; 105239922Sgonzo uint32_t vyres; 106239922Sgonzo uint32_t pitch; 107239922Sgonzo uint32_t bpp; 108239922Sgonzo uint32_t xoffset; 109239922Sgonzo uint32_t yoffset; 110239922Sgonzo /* Filled by videocore */ 111239922Sgonzo uint32_t base; 112239922Sgonzo uint32_t screen_size; 113239922Sgonzo}; 114239922Sgonzo 115239922Sgonzostruct bcmsc_softc { 116239922Sgonzo device_t dev; 117239922Sgonzo struct cdev * cdev; 118239922Sgonzo struct mtx mtx; 119239922Sgonzo bus_dma_tag_t dma_tag; 120239922Sgonzo bus_dmamap_t dma_map; 121239922Sgonzo struct bcm_fb_config* fb_config; 122239922Sgonzo bus_addr_t fb_config_phys; 123239922Sgonzo struct intr_config_hook init_hook; 124239922Sgonzo 125239922Sgonzo}; 126239922Sgonzo 127239922Sgonzostruct video_adapter_softc { 128239922Sgonzo /* Videoadpater part */ 129239922Sgonzo video_adapter_t va; 130239922Sgonzo int console; 131239922Sgonzo 132239922Sgonzo intptr_t fb_addr; 133239922Sgonzo unsigned int fb_size; 134239922Sgonzo 135239922Sgonzo unsigned int height; 136239922Sgonzo unsigned int width; 137243423Sgonzo unsigned int depth; 138239922Sgonzo unsigned int stride; 139239922Sgonzo 140239922Sgonzo unsigned int xmargin; 141239922Sgonzo unsigned int ymargin; 142239922Sgonzo 143239922Sgonzo unsigned char *font; 144239922Sgonzo int initialized; 145239922Sgonzo}; 146239922Sgonzo 147239922Sgonzostatic struct bcmsc_softc *bcmsc_softc; 148239922Sgonzostatic struct video_adapter_softc va_softc; 149239922Sgonzo 150239922Sgonzo#define bcm_fb_lock(_sc) mtx_lock(&(_sc)->mtx) 151239922Sgonzo#define bcm_fb_unlock(_sc) mtx_unlock(&(_sc)->mtx) 152239922Sgonzo#define bcm_fb_lock_assert(sc) mtx_assert(&(_sc)->mtx, MA_OWNED) 153239922Sgonzo 154239922Sgonzostatic int bcm_fb_probe(device_t); 155239922Sgonzostatic int bcm_fb_attach(device_t); 156239922Sgonzostatic void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err); 157243423Sgonzostatic void bcmfb_update_margins(video_adapter_t *adp); 158243423Sgonzostatic int bcmfb_configure(int); 159239922Sgonzo 160239922Sgonzostatic void 161239922Sgonzobcm_fb_init(void *arg) 162239922Sgonzo{ 163239922Sgonzo struct bcmsc_softc *sc = arg; 164239922Sgonzo struct video_adapter_softc *va_sc = &va_softc; 165239922Sgonzo int err; 166239922Sgonzo volatile struct bcm_fb_config* fb_config = sc->fb_config; 167243423Sgonzo phandle_t node; 168243423Sgonzo pcell_t cell; 169239922Sgonzo 170243423Sgonzo node = ofw_bus_get_node(sc->dev); 171243423Sgonzo 172243423Sgonzo fb_config->xres = 0; 173243423Sgonzo fb_config->yres = 0; 174243423Sgonzo fb_config->bpp = 0; 175243423Sgonzo 176243423Sgonzo if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0) 177243423Sgonzo fb_config->xres = (int)fdt32_to_cpu(cell); 178243423Sgonzo if (fb_config->xres == 0) 179243423Sgonzo fb_config->xres = FB_WIDTH; 180243423Sgonzo 181243423Sgonzo if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0) 182243423Sgonzo fb_config->yres = (uint32_t)fdt32_to_cpu(cell); 183243423Sgonzo if (fb_config->yres == 0) 184243423Sgonzo fb_config->yres = FB_HEIGHT; 185243423Sgonzo 186243423Sgonzo if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0) 187243423Sgonzo fb_config->bpp = (uint32_t)fdt32_to_cpu(cell); 188243423Sgonzo if (fb_config->bpp == 0) 189243423Sgonzo fb_config->bpp = FB_DEPTH; 190243423Sgonzo 191239922Sgonzo fb_config->vxres = 0; 192239922Sgonzo fb_config->vyres = 0; 193239922Sgonzo fb_config->xoffset = 0; 194239922Sgonzo fb_config->yoffset = 0; 195239922Sgonzo fb_config->base = 0; 196239922Sgonzo fb_config->pitch = 0; 197239922Sgonzo fb_config->screen_size = 0; 198239922Sgonzo 199239922Sgonzo bus_dmamap_sync(sc->dma_tag, sc->dma_map, 200239922Sgonzo BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 201239922Sgonzo bcm_mbox_write(BCM2835_MBOX_CHAN_FB, sc->fb_config_phys); 202239922Sgonzo bcm_mbox_read(BCM2835_MBOX_CHAN_FB, &err); 203239922Sgonzo bus_dmamap_sync(sc->dma_tag, sc->dma_map, 204239922Sgonzo BUS_DMASYNC_POSTREAD); 205239922Sgonzo 206243423Sgonzo if (fb_config->base != 0) { 207239922Sgonzo device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", 208239922Sgonzo fb_config->xres, fb_config->yres, 209239922Sgonzo fb_config->vxres, fb_config->vyres, 210239922Sgonzo fb_config->xoffset, fb_config->yoffset, 211239922Sgonzo fb_config->bpp); 212239922Sgonzo 213239922Sgonzo 214239922Sgonzo device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n", 215239922Sgonzo fb_config->pitch, fb_config->base, 216239922Sgonzo fb_config->screen_size); 217239922Sgonzo 218243423Sgonzo va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size); 219243423Sgonzo va_sc->fb_size = fb_config->screen_size; 220243423Sgonzo va_sc->depth = fb_config->bpp; 221243423Sgonzo va_sc->stride = fb_config->pitch; 222243423Sgonzo 223243423Sgonzo va_sc->width = fb_config->xres; 224243423Sgonzo va_sc->height = fb_config->yres; 225243423Sgonzo bcmfb_update_margins(&va_sc->va); 226239922Sgonzo } 227243423Sgonzo else { 228239922Sgonzo device_printf(sc->dev, "Failed to set framebuffer info\n"); 229243423Sgonzo return; 230243423Sgonzo } 231239922Sgonzo 232239922Sgonzo config_intrhook_disestablish(&sc->init_hook); 233239922Sgonzo} 234239922Sgonzo 235239922Sgonzostatic int 236239922Sgonzobcm_fb_probe(device_t dev) 237239922Sgonzo{ 238243423Sgonzo int error = 0; 239239922Sgonzo 240239922Sgonzo if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb")) 241239922Sgonzo return (ENXIO); 242239922Sgonzo 243239922Sgonzo device_set_desc(dev, "BCM2835 framebuffer device"); 244239922Sgonzo 245239922Sgonzo error = sc_probe_unit(device_get_unit(dev), 246239922Sgonzo device_get_flags(dev) | SC_AUTODETECT_KBD); 247239922Sgonzo if (error != 0) 248239922Sgonzo return (error); 249239922Sgonzo 250243423Sgonzo 251239922Sgonzo return (BUS_PROBE_DEFAULT); 252239922Sgonzo} 253239922Sgonzo 254239922Sgonzostatic int 255239922Sgonzobcm_fb_attach(device_t dev) 256239922Sgonzo{ 257239922Sgonzo struct bcmsc_softc *sc = device_get_softc(dev); 258239922Sgonzo int dma_size = sizeof(struct bcm_fb_config); 259239922Sgonzo int err; 260239922Sgonzo 261239922Sgonzo if (bcmsc_softc) 262239922Sgonzo return (ENXIO); 263239922Sgonzo 264239922Sgonzo bcmsc_softc = sc; 265239922Sgonzo 266239922Sgonzo sc->dev = dev; 267239922Sgonzo mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF); 268239922Sgonzo 269239922Sgonzo err = bus_dma_tag_create( 270239922Sgonzo bus_get_dma_tag(sc->dev), 271239922Sgonzo PAGE_SIZE, 0, /* alignment, boundary */ 272239922Sgonzo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 273239922Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 274239922Sgonzo NULL, NULL, /* filter, filterarg */ 275239922Sgonzo dma_size, 1, /* maxsize, nsegments */ 276239922Sgonzo dma_size, 0, /* maxsegsize, flags */ 277239922Sgonzo NULL, NULL, /* lockfunc, lockarg */ 278239922Sgonzo &sc->dma_tag); 279239922Sgonzo 280239922Sgonzo err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config, 281239922Sgonzo 0, &sc->dma_map); 282239922Sgonzo if (err) { 283239922Sgonzo device_printf(dev, "cannot allocate framebuffer\n"); 284239922Sgonzo goto fail; 285239922Sgonzo } 286239922Sgonzo 287239922Sgonzo err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config, 288239922Sgonzo dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT); 289239922Sgonzo 290239922Sgonzo if (err) { 291239922Sgonzo device_printf(dev, "cannot load DMA map\n"); 292239922Sgonzo goto fail; 293239922Sgonzo } 294239922Sgonzo 295239922Sgonzo err = (sc_attach_unit(device_get_unit(dev), 296239922Sgonzo device_get_flags(dev) | SC_AUTODETECT_KBD)); 297239922Sgonzo 298239922Sgonzo if (err) { 299239922Sgonzo device_printf(dev, "failed to attach syscons\n"); 300239922Sgonzo goto fail; 301239922Sgonzo } 302239922Sgonzo 303239922Sgonzo /* 304239922Sgonzo * We have to wait until interrupts are enabled. 305239922Sgonzo * Mailbox relies on it to get data from VideoCore 306239922Sgonzo */ 307239922Sgonzo sc->init_hook.ich_func = bcm_fb_init; 308239922Sgonzo sc->init_hook.ich_arg = sc; 309239922Sgonzo 310239922Sgonzo if (config_intrhook_establish(&sc->init_hook) != 0) { 311239922Sgonzo device_printf(dev, "failed to establish intrhook\n"); 312239922Sgonzo return (ENOMEM); 313239922Sgonzo } 314239922Sgonzo 315239922Sgonzo return (0); 316239922Sgonzo 317239922Sgonzofail: 318239922Sgonzo return (ENXIO); 319239922Sgonzo} 320239922Sgonzo 321239922Sgonzo 322239922Sgonzostatic void 323239922Sgonzobcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 324239922Sgonzo{ 325239922Sgonzo bus_addr_t *addr; 326239922Sgonzo 327239922Sgonzo if (err) 328239922Sgonzo return; 329239922Sgonzo 330239922Sgonzo addr = (bus_addr_t*)arg; 331239922Sgonzo *addr = PHYS_TO_VCBUS(segs[0].ds_addr); 332239922Sgonzo} 333239922Sgonzo 334239922Sgonzostatic device_method_t bcm_fb_methods[] = { 335239922Sgonzo /* Device interface */ 336239922Sgonzo DEVMETHOD(device_probe, bcm_fb_probe), 337239922Sgonzo DEVMETHOD(device_attach, bcm_fb_attach), 338239922Sgonzo 339239922Sgonzo { 0, 0 } 340239922Sgonzo}; 341239922Sgonzo 342239922Sgonzostatic devclass_t bcm_fb_devclass; 343239922Sgonzo 344239922Sgonzostatic driver_t bcm_fb_driver = { 345239922Sgonzo "fb", 346239922Sgonzo bcm_fb_methods, 347239922Sgonzo sizeof(struct bcmsc_softc), 348239922Sgonzo}; 349239922Sgonzo 350243423SgonzoDRIVER_MODULE(bcm2835fb, fdtbus, bcm_fb_driver, bcm_fb_devclass, 0, 0); 351239922Sgonzo 352239922Sgonzo/* 353239922Sgonzo * Video driver routines and glue. 354239922Sgonzo */ 355239922Sgonzostatic vi_probe_t bcmfb_probe; 356239922Sgonzostatic vi_init_t bcmfb_init; 357239922Sgonzostatic vi_get_info_t bcmfb_get_info; 358239922Sgonzostatic vi_query_mode_t bcmfb_query_mode; 359239922Sgonzostatic vi_set_mode_t bcmfb_set_mode; 360239922Sgonzostatic vi_save_font_t bcmfb_save_font; 361239922Sgonzostatic vi_load_font_t bcmfb_load_font; 362239922Sgonzostatic vi_show_font_t bcmfb_show_font; 363239922Sgonzostatic vi_save_palette_t bcmfb_save_palette; 364239922Sgonzostatic vi_load_palette_t bcmfb_load_palette; 365239922Sgonzostatic vi_set_border_t bcmfb_set_border; 366239922Sgonzostatic vi_save_state_t bcmfb_save_state; 367239922Sgonzostatic vi_load_state_t bcmfb_load_state; 368239922Sgonzostatic vi_set_win_org_t bcmfb_set_win_org; 369239922Sgonzostatic vi_read_hw_cursor_t bcmfb_read_hw_cursor; 370239922Sgonzostatic vi_set_hw_cursor_t bcmfb_set_hw_cursor; 371239922Sgonzostatic vi_set_hw_cursor_shape_t bcmfb_set_hw_cursor_shape; 372239922Sgonzostatic vi_blank_display_t bcmfb_blank_display; 373239922Sgonzostatic vi_mmap_t bcmfb_mmap; 374239922Sgonzostatic vi_ioctl_t bcmfb_ioctl; 375239922Sgonzostatic vi_clear_t bcmfb_clear; 376239922Sgonzostatic vi_fill_rect_t bcmfb_fill_rect; 377239922Sgonzostatic vi_bitblt_t bcmfb_bitblt; 378239922Sgonzostatic vi_diag_t bcmfb_diag; 379239922Sgonzostatic vi_save_cursor_palette_t bcmfb_save_cursor_palette; 380239922Sgonzostatic vi_load_cursor_palette_t bcmfb_load_cursor_palette; 381239922Sgonzostatic vi_copy_t bcmfb_copy; 382239922Sgonzostatic vi_putp_t bcmfb_putp; 383239922Sgonzostatic vi_putc_t bcmfb_putc; 384239922Sgonzostatic vi_puts_t bcmfb_puts; 385239922Sgonzostatic vi_putm_t bcmfb_putm; 386239922Sgonzo 387239922Sgonzostatic video_switch_t bcmfbvidsw = { 388239922Sgonzo .probe = bcmfb_probe, 389239922Sgonzo .init = bcmfb_init, 390239922Sgonzo .get_info = bcmfb_get_info, 391239922Sgonzo .query_mode = bcmfb_query_mode, 392239922Sgonzo .set_mode = bcmfb_set_mode, 393239922Sgonzo .save_font = bcmfb_save_font, 394239922Sgonzo .load_font = bcmfb_load_font, 395239922Sgonzo .show_font = bcmfb_show_font, 396239922Sgonzo .save_palette = bcmfb_save_palette, 397239922Sgonzo .load_palette = bcmfb_load_palette, 398239922Sgonzo .set_border = bcmfb_set_border, 399239922Sgonzo .save_state = bcmfb_save_state, 400239922Sgonzo .load_state = bcmfb_load_state, 401239922Sgonzo .set_win_org = bcmfb_set_win_org, 402239922Sgonzo .read_hw_cursor = bcmfb_read_hw_cursor, 403239922Sgonzo .set_hw_cursor = bcmfb_set_hw_cursor, 404239922Sgonzo .set_hw_cursor_shape = bcmfb_set_hw_cursor_shape, 405239922Sgonzo .blank_display = bcmfb_blank_display, 406239922Sgonzo .mmap = bcmfb_mmap, 407239922Sgonzo .ioctl = bcmfb_ioctl, 408239922Sgonzo .clear = bcmfb_clear, 409239922Sgonzo .fill_rect = bcmfb_fill_rect, 410239922Sgonzo .bitblt = bcmfb_bitblt, 411239922Sgonzo .diag = bcmfb_diag, 412239922Sgonzo .save_cursor_palette = bcmfb_save_cursor_palette, 413239922Sgonzo .load_cursor_palette = bcmfb_load_cursor_palette, 414239922Sgonzo .copy = bcmfb_copy, 415239922Sgonzo .putp = bcmfb_putp, 416239922Sgonzo .putc = bcmfb_putc, 417239922Sgonzo .puts = bcmfb_puts, 418239922Sgonzo .putm = bcmfb_putm, 419239922Sgonzo}; 420239922Sgonzo 421239922SgonzoVIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure); 422239922Sgonzo 423239922Sgonzoextern sc_rndr_sw_t txtrndrsw; 424239922SgonzoRENDERER(bcmfb, 0, txtrndrsw, gfb_set); 425239922SgonzoRENDERER_MODULE(bcmfb, gfb_set); 426239922Sgonzo 427239922Sgonzostatic uint16_t bcmfb_static_window[ROW*COL]; 428239922Sgonzoextern u_char dflt_font_16[]; 429239922Sgonzo 430243423Sgonzo/* 431243423Sgonzo * Update videoadapter settings after changing resolution 432243423Sgonzo */ 433243423Sgonzostatic void 434243423Sgonzobcmfb_update_margins(video_adapter_t *adp) 435243423Sgonzo{ 436243423Sgonzo struct video_adapter_softc *sc; 437243423Sgonzo video_info_t *vi; 438243423Sgonzo 439243423Sgonzo sc = (struct video_adapter_softc *)adp; 440243423Sgonzo vi = &adp->va_info; 441243423Sgonzo 442243423Sgonzo sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 443243423Sgonzo sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 444243423Sgonzo} 445243423Sgonzo 446239922Sgonzostatic int 447239922Sgonzobcmfb_configure(int flags) 448239922Sgonzo{ 449243423Sgonzo struct video_adapter_softc *va_sc; 450239922Sgonzo 451243423Sgonzo va_sc = &va_softc; 452243423Sgonzo phandle_t display, root; 453243423Sgonzo pcell_t cell; 454239922Sgonzo 455243423Sgonzo if (va_sc->initialized) 456243423Sgonzo return (0); 457239922Sgonzo 458243423Sgonzo va_sc->width = 0; 459243423Sgonzo va_sc->height = 0; 460239922Sgonzo 461243423Sgonzo /* 462243423Sgonzo * It seems there is no way to let syscons framework know 463243423Sgonzo * that framebuffer resolution has changed. So just try 464243423Sgonzo * to fetch data from FDT and go with defaults if failed 465243423Sgonzo */ 466243423Sgonzo root = OF_finddevice("/"); 467243423Sgonzo if ((root != 0) && 468243423Sgonzo (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) { 469243423Sgonzo if ((OF_getprop(display, "broadcom,width", 470243423Sgonzo &cell, sizeof(cell))) > 0) 471243423Sgonzo va_sc->width = (int)fdt32_to_cpu(cell); 472239922Sgonzo 473243423Sgonzo if ((OF_getprop(display, "broadcom,height", 474243423Sgonzo &cell, sizeof(cell))) > 0) 475243423Sgonzo va_sc->height = (int)fdt32_to_cpu(cell); 476243423Sgonzo } 477239922Sgonzo 478243423Sgonzo if (va_sc->width == 0) 479243423Sgonzo va_sc->width = FB_WIDTH; 480243423Sgonzo if (va_sc->height == 0) 481243423Sgonzo va_sc->height = FB_HEIGHT; 482243423Sgonzo 483243423Sgonzo bcmfb_init(0, &va_sc->va, 0); 484243423Sgonzo 485243423Sgonzo va_sc->initialized = 1; 486243423Sgonzo 487239922Sgonzo return (0); 488239922Sgonzo} 489239922Sgonzo 490239922Sgonzostatic int 491239922Sgonzobcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags) 492239922Sgonzo{ 493239922Sgonzo 494239922Sgonzo return (0); 495239922Sgonzo} 496239922Sgonzo 497239922Sgonzostatic int 498239922Sgonzobcmfb_init(int unit, video_adapter_t *adp, int flags) 499239922Sgonzo{ 500239922Sgonzo struct video_adapter_softc *sc; 501239922Sgonzo video_info_t *vi; 502239922Sgonzo 503239922Sgonzo sc = (struct video_adapter_softc *)adp; 504239922Sgonzo vi = &adp->va_info; 505239922Sgonzo 506239922Sgonzo vid_init_struct(adp, "bcmfb", -1, unit); 507239922Sgonzo 508239922Sgonzo sc->font = dflt_font_16; 509239922Sgonzo vi->vi_cheight = BCMFB_FONT_HEIGHT; 510239922Sgonzo vi->vi_cwidth = 8; 511243423Sgonzo 512239922Sgonzo vi->vi_width = sc->width/8; 513239922Sgonzo vi->vi_height = sc->height/vi->vi_cheight; 514239922Sgonzo 515239922Sgonzo /* 516239922Sgonzo * Clamp width/height to syscons maximums 517239922Sgonzo */ 518239922Sgonzo if (vi->vi_width > COL) 519239922Sgonzo vi->vi_width = COL; 520239922Sgonzo if (vi->vi_height > ROW) 521239922Sgonzo vi->vi_height = ROW; 522239922Sgonzo 523239922Sgonzo sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 524239922Sgonzo sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 525239922Sgonzo 526243423Sgonzo 527239922Sgonzo adp->va_window = (vm_offset_t) bcmfb_static_window; 528239922Sgonzo adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; 529239922Sgonzo 530239922Sgonzo vid_register(&sc->va); 531239922Sgonzo 532239922Sgonzo return (0); 533239922Sgonzo} 534239922Sgonzo 535239922Sgonzostatic int 536239922Sgonzobcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info) 537239922Sgonzo{ 538239922Sgonzo bcopy(&adp->va_info, info, sizeof(*info)); 539239922Sgonzo return (0); 540239922Sgonzo} 541239922Sgonzo 542239922Sgonzostatic int 543239922Sgonzobcmfb_query_mode(video_adapter_t *adp, video_info_t *info) 544239922Sgonzo{ 545239922Sgonzo return (0); 546239922Sgonzo} 547239922Sgonzo 548239922Sgonzostatic int 549239922Sgonzobcmfb_set_mode(video_adapter_t *adp, int mode) 550239922Sgonzo{ 551239922Sgonzo return (0); 552239922Sgonzo} 553239922Sgonzo 554239922Sgonzostatic int 555239922Sgonzobcmfb_save_font(video_adapter_t *adp, int page, int size, int width, 556239922Sgonzo u_char *data, int c, int count) 557239922Sgonzo{ 558239922Sgonzo return (0); 559239922Sgonzo} 560239922Sgonzo 561239922Sgonzostatic int 562239922Sgonzobcmfb_load_font(video_adapter_t *adp, int page, int size, int width, 563239922Sgonzo u_char *data, int c, int count) 564239922Sgonzo{ 565239922Sgonzo struct video_adapter_softc *sc = (struct video_adapter_softc *)adp; 566239922Sgonzo 567239922Sgonzo sc->font = data; 568239922Sgonzo 569239922Sgonzo return (0); 570239922Sgonzo} 571239922Sgonzo 572239922Sgonzostatic int 573239922Sgonzobcmfb_show_font(video_adapter_t *adp, int page) 574239922Sgonzo{ 575239922Sgonzo return (0); 576239922Sgonzo} 577239922Sgonzo 578239922Sgonzostatic int 579239922Sgonzobcmfb_save_palette(video_adapter_t *adp, u_char *palette) 580239922Sgonzo{ 581239922Sgonzo return (0); 582239922Sgonzo} 583239922Sgonzo 584239922Sgonzostatic int 585239922Sgonzobcmfb_load_palette(video_adapter_t *adp, u_char *palette) 586239922Sgonzo{ 587239922Sgonzo return (0); 588239922Sgonzo} 589239922Sgonzo 590239922Sgonzostatic int 591239922Sgonzobcmfb_set_border(video_adapter_t *adp, int border) 592239922Sgonzo{ 593239922Sgonzo return (bcmfb_blank_display(adp, border)); 594239922Sgonzo} 595239922Sgonzo 596239922Sgonzostatic int 597239922Sgonzobcmfb_save_state(video_adapter_t *adp, void *p, size_t size) 598239922Sgonzo{ 599239922Sgonzo return (0); 600239922Sgonzo} 601239922Sgonzo 602239922Sgonzostatic int 603239922Sgonzobcmfb_load_state(video_adapter_t *adp, void *p) 604239922Sgonzo{ 605239922Sgonzo return (0); 606239922Sgonzo} 607239922Sgonzo 608239922Sgonzostatic int 609239922Sgonzobcmfb_set_win_org(video_adapter_t *adp, off_t offset) 610239922Sgonzo{ 611239922Sgonzo return (0); 612239922Sgonzo} 613239922Sgonzo 614239922Sgonzostatic int 615239922Sgonzobcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 616239922Sgonzo{ 617239922Sgonzo *col = *row = 0; 618239922Sgonzo 619239922Sgonzo return (0); 620239922Sgonzo} 621239922Sgonzo 622239922Sgonzostatic int 623239922Sgonzobcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row) 624239922Sgonzo{ 625239922Sgonzo return (0); 626239922Sgonzo} 627239922Sgonzo 628239922Sgonzostatic int 629239922Sgonzobcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 630239922Sgonzo int celsize, int blink) 631239922Sgonzo{ 632239922Sgonzo return (0); 633239922Sgonzo} 634239922Sgonzo 635239922Sgonzostatic int 636239922Sgonzobcmfb_blank_display(video_adapter_t *adp, int mode) 637239922Sgonzo{ 638239922Sgonzo 639243423Sgonzo struct video_adapter_softc *sc; 640243423Sgonzo 641243423Sgonzo sc = (struct video_adapter_softc *)adp; 642243423Sgonzo if (sc && sc->fb_addr) 643243423Sgonzo memset((void*)sc->fb_addr, 0, sc->fb_size); 644243423Sgonzo 645239922Sgonzo return (0); 646239922Sgonzo} 647239922Sgonzo 648239922Sgonzostatic int 649239922Sgonzobcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 650239922Sgonzo int prot, vm_memattr_t *memattr) 651239922Sgonzo{ 652239922Sgonzo struct video_adapter_softc *sc; 653239922Sgonzo 654239922Sgonzo sc = (struct video_adapter_softc *)adp; 655239922Sgonzo 656239922Sgonzo /* 657239922Sgonzo * This might be a legacy VGA mem request: if so, just point it at the 658239922Sgonzo * framebuffer, since it shouldn't be touched 659239922Sgonzo */ 660239922Sgonzo if (offset < sc->stride*sc->height) { 661239922Sgonzo *paddr = sc->fb_addr + offset; 662239922Sgonzo return (0); 663239922Sgonzo } 664239922Sgonzo 665239922Sgonzo return (EINVAL); 666239922Sgonzo} 667239922Sgonzo 668239922Sgonzostatic int 669239922Sgonzobcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) 670239922Sgonzo{ 671239922Sgonzo 672239922Sgonzo return (0); 673239922Sgonzo} 674239922Sgonzo 675239922Sgonzostatic int 676239922Sgonzobcmfb_clear(video_adapter_t *adp) 677239922Sgonzo{ 678239922Sgonzo 679239922Sgonzo return (bcmfb_blank_display(adp, 0)); 680239922Sgonzo} 681239922Sgonzo 682239922Sgonzostatic int 683239922Sgonzobcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 684239922Sgonzo{ 685239922Sgonzo 686239922Sgonzo return (0); 687239922Sgonzo} 688239922Sgonzo 689239922Sgonzostatic int 690239922Sgonzobcmfb_bitblt(video_adapter_t *adp, ...) 691239922Sgonzo{ 692239922Sgonzo 693239922Sgonzo return (0); 694239922Sgonzo} 695239922Sgonzo 696239922Sgonzostatic int 697239922Sgonzobcmfb_diag(video_adapter_t *adp, int level) 698239922Sgonzo{ 699239922Sgonzo 700239922Sgonzo return (0); 701239922Sgonzo} 702239922Sgonzo 703239922Sgonzostatic int 704239922Sgonzobcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette) 705239922Sgonzo{ 706239922Sgonzo 707239922Sgonzo return (0); 708239922Sgonzo} 709239922Sgonzo 710239922Sgonzostatic int 711239922Sgonzobcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette) 712239922Sgonzo{ 713239922Sgonzo 714239922Sgonzo return (0); 715239922Sgonzo} 716239922Sgonzo 717239922Sgonzostatic int 718239922Sgonzobcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) 719239922Sgonzo{ 720239922Sgonzo 721239922Sgonzo return (0); 722239922Sgonzo} 723239922Sgonzo 724239922Sgonzostatic int 725239922Sgonzobcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a, 726239922Sgonzo int size, int bpp, int bit_ltor, int byte_ltor) 727239922Sgonzo{ 728239922Sgonzo 729239922Sgonzo return (0); 730239922Sgonzo} 731239922Sgonzo 732239922Sgonzostatic int 733239922Sgonzobcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) 734239922Sgonzo{ 735239922Sgonzo struct video_adapter_softc *sc; 736239922Sgonzo int row; 737239922Sgonzo int col; 738239922Sgonzo int i, j, k; 739239922Sgonzo uint8_t *addr; 740239922Sgonzo u_char *p; 741239922Sgonzo uint8_t fg, bg, color; 742243423Sgonzo uint16_t rgb; 743239922Sgonzo 744239922Sgonzo sc = (struct video_adapter_softc *)adp; 745239922Sgonzo 746239922Sgonzo if (sc->fb_addr == 0) 747239922Sgonzo return (0); 748239922Sgonzo 749239922Sgonzo row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 750239922Sgonzo col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 751239922Sgonzo p = sc->font + c*BCMFB_FONT_HEIGHT; 752239922Sgonzo addr = (uint8_t *)sc->fb_addr 753239922Sgonzo + (row + sc->ymargin)*(sc->stride) 754243666Sgonzo + (sc->depth/8) * (col + sc->xmargin); 755239922Sgonzo 756243423Sgonzo fg = a & 0xf ; 757243423Sgonzo bg = (a >> 8) & 0xf; 758239922Sgonzo 759239922Sgonzo for (i = 0; i < BCMFB_FONT_HEIGHT; i++) { 760239922Sgonzo for (j = 0, k = 7; j < 8; j++, k--) { 761239922Sgonzo if ((p[i] & (1 << k)) == 0) 762239922Sgonzo color = bg; 763239922Sgonzo else 764239922Sgonzo color = fg; 765239922Sgonzo 766243423Sgonzo switch (sc->depth) { 767243423Sgonzo case 32: 768243423Sgonzo addr[4*j+0] = bcmfb_palette[color].r; 769243423Sgonzo addr[4*j+1] = bcmfb_palette[color].g; 770243423Sgonzo addr[4*j+2] = bcmfb_palette[color].b; 771243423Sgonzo addr[4*j+3] = bcmfb_palette[color].a; 772243423Sgonzo break; 773243423Sgonzo case 24: 774243423Sgonzo addr[3*j] = bcmfb_palette[color].r; 775243423Sgonzo addr[3*j+1] = bcmfb_palette[color].g; 776243423Sgonzo addr[3*j+2] = bcmfb_palette[color].b; 777243423Sgonzo break; 778243423Sgonzo case 16: 779243423Sgonzo rgb = (bcmfb_palette[color].r >> 3) << 10; 780243423Sgonzo rgb |= (bcmfb_palette[color].g >> 3) << 5; 781243423Sgonzo rgb |= (bcmfb_palette[color].b >> 3); 782243423Sgonzo addr[2*j] = (rgb >> 8) & 0xff; 783243423Sgonzo addr[2*j + 1] = rgb & 0xff; 784243423Sgonzo default: 785243423Sgonzo /* Not supported yet */ 786243423Sgonzo break; 787243423Sgonzo } 788239922Sgonzo } 789239922Sgonzo 790239922Sgonzo addr += (sc->stride); 791239922Sgonzo } 792239922Sgonzo 793239922Sgonzo return (0); 794239922Sgonzo} 795239922Sgonzo 796239922Sgonzostatic int 797239922Sgonzobcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) 798239922Sgonzo{ 799239922Sgonzo int i; 800239922Sgonzo 801239922Sgonzo for (i = 0; i < len; i++) 802239922Sgonzo bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); 803239922Sgonzo 804239922Sgonzo return (0); 805239922Sgonzo} 806239922Sgonzo 807239922Sgonzostatic int 808239922Sgonzobcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, 809239922Sgonzo uint32_t pixel_mask, int size, int width) 810239922Sgonzo{ 811239922Sgonzo 812239922Sgonzo return (0); 813239922Sgonzo} 814239922Sgonzo 815239922Sgonzo/* 816239922Sgonzo * Define a stub keyboard driver in case one hasn't been 817239922Sgonzo * compiled into the kernel 818239922Sgonzo */ 819239922Sgonzo#include <sys/kbio.h> 820239922Sgonzo#include <dev/kbd/kbdreg.h> 821239922Sgonzo 822239922Sgonzostatic int dummy_kbd_configure(int flags); 823239922Sgonzo 824239922Sgonzokeyboard_switch_t bcmdummysw; 825239922Sgonzo 826239922Sgonzostatic int 827239922Sgonzodummy_kbd_configure(int flags) 828239922Sgonzo{ 829239922Sgonzo 830239922Sgonzo return (0); 831239922Sgonzo} 832239922SgonzoKEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure); 833