From owner-svn-src-all@FreeBSD.ORG Sat May 2 22:40:42 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 2B153B26; Sat, 2 May 2015 22:40:42 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 187261023; Sat, 2 May 2015 22:40:42 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t42Megbs042620; Sat, 2 May 2015 22:40:42 GMT (envelope-from loos@FreeBSD.org) Received: (from loos@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t42MegcH042619; Sat, 2 May 2015 22:40:42 GMT (envelope-from loos@FreeBSD.org) Message-Id: <201505022240.t42MegcH042619@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: loos set sender to loos@FreeBSD.org using -f From: Luiz Otavio O Souza Date: Sat, 2 May 2015 22:40:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r282358 - head/sys/arm/broadcom/bcm2835 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 02 May 2015 22:40:42 -0000 Author: loos Date: Sat May 2 22:40:41 2015 New Revision: 282358 URL: https://svnweb.freebsd.org/changeset/base/282358 Log: Fix the sc(4) framebuffer driver on RPi 2. Use the BCM2835_MBOX_CHAN_PROP mbox channel to setup the framebuffer, remove unused code and unnecessary includes. Adjust the color palette when bcm2708_fb.fbswap is set on /chosen/bootargs node of DTB. The firmware used on RPi 2 uses this mode. Tested on: RPi-B and RPi 2 with 16, 24 and 32bpp Modified: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c Modified: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c ============================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_fb.c Sat May 2 22:24:33 2015 (r282357) +++ head/sys/arm/broadcom/bcm2835/bcm2835_fb.c Sat May 2 22:40:41 2015 (r282358) @@ -29,46 +29,27 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include -#include -#include +#include +#include +#include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include +#include +#include +#include #include #include #include - -#include #include -#include -#include +#include #include "mbox_if.h" -#define BCMFB_FONT_HEIGHT 16 - struct argb { uint8_t a; uint8_t r; @@ -101,40 +82,15 @@ static u_char mouse_pointer[16] = { 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 }; -#define FB_WIDTH 640 -#define FB_HEIGHT 480 -#define FB_DEPTH 24 - -struct bcm_fb_config { - uint32_t xres; - uint32_t yres; - uint32_t vxres; - uint32_t vyres; - uint32_t pitch; - uint32_t bpp; - uint32_t xoffset; - uint32_t yoffset; - /* Filled by videocore */ - uint32_t base; - uint32_t screen_size; -}; +#define BCMFB_FONT_HEIGHT 16 +#define BCMFB_FONT_WIDTH 8 +#define FB_WIDTH 640 +#define FB_HEIGHT 480 +#define FB_DEPTH 24 struct bcmsc_softc { - device_t dev; - struct cdev * cdev; - struct mtx mtx; - bus_dma_tag_t dma_tag; - bus_dmamap_t dma_map; - struct bcm_fb_config* fb_config; - bus_addr_t fb_config_phys; - struct intr_config_hook init_hook; - -}; - -struct video_adapter_softc { /* Videoadpater part */ video_adapter_t va; - int console; intptr_t fb_addr; intptr_t fb_paddr; @@ -149,199 +105,75 @@ struct video_adapter_softc { unsigned int ymargin; unsigned char *font; + int fbswap; int initialized; }; -static struct bcmsc_softc *bcmsc_softc; -static struct video_adapter_softc va_softc; - -#define bcm_fb_lock(_sc) mtx_lock(&(_sc)->mtx) -#define bcm_fb_unlock(_sc) mtx_unlock(&(_sc)->mtx) -#define bcm_fb_lock_assert(sc) mtx_assert(&(_sc)->mtx, MA_OWNED) +static struct bcmsc_softc bcmsc; static int bcm_fb_probe(device_t); static int bcm_fb_attach(device_t); -static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err); static void bcmfb_update_margins(video_adapter_t *adp); static int bcmfb_configure(int); -static void -bcm_fb_init(void *arg) -{ - struct bcmsc_softc *sc = arg; - struct video_adapter_softc *va_sc = &va_softc; - int err; - volatile struct bcm_fb_config* fb_config = sc->fb_config; - phandle_t node; - pcell_t cell; - device_t mbox; - - node = ofw_bus_get_node(sc->dev); - - fb_config->xres = 0; - fb_config->yres = 0; - fb_config->bpp = 0; - - if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0) - fb_config->xres = (int)fdt32_to_cpu(cell); - if (fb_config->xres == 0) - fb_config->xres = FB_WIDTH; - - if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0) - fb_config->yres = (uint32_t)fdt32_to_cpu(cell); - if (fb_config->yres == 0) - fb_config->yres = FB_HEIGHT; - - if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0) - fb_config->bpp = (uint32_t)fdt32_to_cpu(cell); - if (fb_config->bpp == 0) - fb_config->bpp = FB_DEPTH; - - fb_config->vxres = 0; - fb_config->vyres = 0; - fb_config->xoffset = 0; - fb_config->yoffset = 0; - fb_config->base = 0; - fb_config->pitch = 0; - fb_config->screen_size = 0; - - bus_dmamap_sync(sc->dma_tag, sc->dma_map, - BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); - - mbox = devclass_get_device(devclass_find("mbox"), 0); - if (mbox) { - MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys); - MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err); - } - bus_dmamap_sync(sc->dma_tag, sc->dma_map, - BUS_DMASYNC_POSTREAD); - - if (fb_config->base != 0) { - device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", - fb_config->xres, fb_config->yres, - fb_config->vxres, fb_config->vyres, - fb_config->xoffset, fb_config->yoffset, - fb_config->bpp); - - - device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n", - fb_config->pitch, fb_config->base, - fb_config->screen_size); - - va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size); - va_sc->fb_paddr = fb_config->base; - va_sc->fb_size = fb_config->screen_size; - va_sc->depth = fb_config->bpp; - va_sc->stride = fb_config->pitch; - - va_sc->width = fb_config->xres; - va_sc->height = fb_config->yres; - bcmfb_update_margins(&va_sc->va); - } - else { - device_printf(sc->dev, "Failed to set framebuffer info\n"); - } - - config_intrhook_disestablish(&sc->init_hook); -} - static int bcm_fb_probe(device_t dev) { - int error = 0; + int error; if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb")) return (ENXIO); - device_set_desc(dev, "BCM2835 framebuffer device"); - error = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (error != 0) return (error); - return (BUS_PROBE_DEFAULT); } static int bcm_fb_attach(device_t dev) { - struct bcmsc_softc *sc = device_get_softc(dev); - int dma_size = sizeof(struct bcm_fb_config); - int err; - - if (bcmsc_softc) - return (ENXIO); + struct bcm2835_fb_config fb; + struct bcmsc_softc *sc; - bcmsc_softc = sc; + sc = (struct bcmsc_softc *)vid_get_adapter(vid_find_adapter( + "bcmfb", 0)); + if (sc != NULL) + device_set_softc(dev, sc); + else + sc = device_get_softc(dev); - sc->dev = dev; - mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF); - - err = bus_dma_tag_create( - bus_get_dma_tag(sc->dev), - PAGE_SIZE, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - dma_size, 1, /* maxsize, nsegments */ - dma_size, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->dma_tag); - - err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config, - 0, &sc->dma_map); - if (err) { - device_printf(dev, "cannot allocate framebuffer\n"); - goto fail; - } - - err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config, - dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT); - - if (err) { - device_printf(dev, "cannot load DMA map\n"); - goto fail; - } + memset(&fb, 0, sizeof(fb)); + if (bcm2835_mbox_fb_get_w_h(dev, &fb) != 0) + return (ENXIO); + fb.bpp = FB_DEPTH; + if (bcm2835_mbox_fb_init(dev, &fb) != 0) + return (ENXIO); - err = (sc_attach_unit(device_get_unit(dev), - device_get_flags(dev) | SC_AUTODETECT_KBD)); + sc->fb_addr = (intptr_t)pmap_mapdev(fb.base, fb.size); + sc->fb_paddr = fb.base; + sc->fb_size = fb.size; + sc->depth = fb.bpp; + sc->stride = fb.pitch; + sc->width = fb.xres; + sc->height = fb.yres; + bcmfb_update_margins(&sc->va); - if (err) { + if (sc_attach_unit(device_get_unit(dev), + device_get_flags(dev) | SC_AUTODETECT_KBD) != 0) { device_printf(dev, "failed to attach syscons\n"); - goto fail; + return (ENXIO); } - /* - * We have to wait until interrupts are enabled. - * Mailbox relies on it to get data from VideoCore - */ - sc->init_hook.ich_func = bcm_fb_init; - sc->init_hook.ich_arg = sc; - - if (config_intrhook_establish(&sc->init_hook) != 0) { - device_printf(dev, "failed to establish intrhook\n"); - return (ENOMEM); - } + device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres, + fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp); + device_printf(dev, + "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n", + sc->fbswap, fb.pitch, fb.base, fb.size); return (0); - -fail: - return (ENXIO); -} - - -static void -bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) -{ - bus_addr_t *addr; - - if (err) - return; - - addr = (bus_addr_t*)arg; - *addr = PHYS_TO_VCBUS(segs[0].ds_addr); } static device_method_t bcm_fb_methods[] = { @@ -504,13 +336,13 @@ bcmrend_set_cursor(scr_stat* scp, int ba static void bcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip) { - video_adapter_t* adp = scp->sc->adp; - struct video_adapter_softc *sc; - int row, col; + int bytes, col, i, j, row; + struct bcmsc_softc *sc; uint8_t *addr; - int i, j, bytes; + video_adapter_t *adp; - sc = (struct video_adapter_softc *)adp; + adp = scp->sc->adp; + sc = (struct bcmsc_softc *)adp; if (scp->curs_attr.height <= 0) return; @@ -529,8 +361,7 @@ bcmrend_draw_cursor(scr_stat* scp, int o + (row + sc->ymargin)*(sc->stride) + (sc->depth/8) * (col + sc->xmargin); - bytes = sc->depth/8; - + bytes = sc->depth / 8; /* our cursor consists of simply inverting the char under it */ for (i = 0; i < adp->va_info.vi_cheight; i++) { for (j = 0; j < adp->va_info.vi_cwidth; j++) { @@ -577,56 +408,80 @@ extern u_char dflt_font_16[]; static void bcmfb_update_margins(video_adapter_t *adp) { - struct video_adapter_softc *sc; + struct bcmsc_softc *sc; video_info_t *vi; - sc = (struct video_adapter_softc *)adp; + sc = (struct bcmsc_softc *)adp; vi = &adp->va_info; sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; - sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; + sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2; } static int bcmfb_configure(int flags) { - struct video_adapter_softc *va_sc; - - va_sc = &va_softc; - phandle_t display, root; + char bootargs[2048], *n, *p, *v; pcell_t cell; + phandle_t chosen, display, root; + struct bcmsc_softc *sc; - if (va_sc->initialized) + sc = &bcmsc; + if (sc->initialized) return (0); - va_sc->width = 0; - va_sc->height = 0; + sc->width = 0; + sc->height = 0; /* * It seems there is no way to let syscons framework know * that framebuffer resolution has changed. So just try - * to fetch data from FDT and go with defaults if failed + * to fetch data from FDT bootargs, FDT display data and + * finally go with defaults if everything else has failed. */ + chosen = OF_finddevice("/chosen"); + if (chosen != 0 && + OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) { + p = bootargs; + while ((v = strsep(&p, " ")) != NULL) { + if (*v == '\0') + continue; + n = strsep(&v, "="); + if (strcmp(n, "bcm2708_fb.fbwidth") == 0 && v != NULL) + sc->width = (unsigned int)strtol(v, NULL, 0); + else if (strcmp(n, "bcm2708_fb.fbheight") == 0 && + v != NULL) + sc->height = (unsigned int)strtol(v, NULL, 0); + else if (strcmp(n, "bcm2708_fb.fbswap") == 0 && + v != NULL) + if (*v == '1') + sc->fbswap = 1; + } + } + root = OF_finddevice("/"); if ((root != 0) && (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) { - if ((OF_getprop(display, "broadcom,width", - &cell, sizeof(cell))) > 0) - va_sc->width = (int)fdt32_to_cpu(cell); - - if ((OF_getprop(display, "broadcom,height", - &cell, sizeof(cell))) > 0) - va_sc->height = (int)fdt32_to_cpu(cell); - } + if (sc->width == 0) { + if ((OF_getprop(display, "broadcom,width", + &cell, sizeof(cell))) > 0) + sc->width = (int)fdt32_to_cpu(cell); + } - if (va_sc->width == 0) - va_sc->width = FB_WIDTH; - if (va_sc->height == 0) - va_sc->height = FB_HEIGHT; + if (sc->height == 0) { + if ((OF_getprop(display, "broadcom,height", + &cell, sizeof(cell))) > 0) + sc->height = (int)fdt32_to_cpu(cell); + } + } - bcmfb_init(0, &va_sc->va, 0); + if (sc->width == 0) + sc->width = FB_WIDTH; + if (sc->height == 0) + sc->height = FB_HEIGHT; - va_sc->initialized = 1; + bcmfb_init(0, &sc->va, 0); + sc->initialized = 1; return (0); } @@ -641,20 +496,19 @@ bcmfb_probe(int unit, video_adapter_t ** static int bcmfb_init(int unit, video_adapter_t *adp, int flags) { - struct video_adapter_softc *sc; + struct bcmsc_softc *sc; video_info_t *vi; - sc = (struct video_adapter_softc *)adp; + sc = (struct bcmsc_softc *)adp; vi = &adp->va_info; vid_init_struct(adp, "bcmfb", -1, unit); sc->font = dflt_font_16; vi->vi_cheight = BCMFB_FONT_HEIGHT; - vi->vi_cwidth = 8; - - vi->vi_width = sc->width/8; - vi->vi_height = sc->height/vi->vi_cheight; + vi->vi_cwidth = BCMFB_FONT_WIDTH; + vi->vi_width = sc->width / vi->vi_cwidth; + vi->vi_height = sc->height / vi->vi_cheight; /* * Clamp width/height to syscons maximums @@ -665,8 +519,7 @@ bcmfb_init(int unit, video_adapter_t *ad vi->vi_height = ROW; sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; - sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; - + sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2; adp->va_window = (vm_offset_t) bcmfb_static_window; adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; @@ -706,8 +559,9 @@ static int bcmfb_load_font(video_adapter_t *adp, int page, int size, int width, u_char *data, int c, int count) { - struct video_adapter_softc *sc = (struct video_adapter_softc *)adp; + struct bcmsc_softc *sc; + sc = (struct bcmsc_softc *)adp; sc->font = data; return (0); @@ -780,9 +634,9 @@ static int bcmfb_blank_display(video_adapter_t *adp, int mode) { - struct video_adapter_softc *sc; + struct bcmsc_softc *sc; - sc = (struct video_adapter_softc *)adp; + sc = (struct bcmsc_softc *)adp; if (sc && sc->fb_addr) memset((void*)sc->fb_addr, 0, sc->fb_size); @@ -793,9 +647,9 @@ static int bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { - struct video_adapter_softc *sc; + struct bcmsc_softc *sc; - sc = (struct video_adapter_softc *)adp; + sc = (struct bcmsc_softc *)adp; /* * This might be a legacy VGA mem request: if so, just point it at the @@ -812,10 +666,10 @@ bcmfb_mmap(video_adapter_t *adp, vm_ooff static int bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) { - struct video_adapter_softc *sc; + struct bcmsc_softc *sc; struct fbtype *fb; - sc = (struct video_adapter_softc *)adp; + sc = (struct bcmsc_softc *)adp; switch (cmd) { case FBIOGTYPE: @@ -897,16 +751,13 @@ bcmfb_putp(video_adapter_t *adp, vm_offs static int bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) { - struct video_adapter_softc *sc; - int row; - int col; - int i, j, k; - uint8_t *addr; + int bytes, col, i, j, k, row; + struct bcmsc_softc *sc; u_char *p; - uint8_t fg, bg, color; + uint8_t *addr, fg, bg, color; uint16_t rgb; - sc = (struct video_adapter_softc *)adp; + sc = (struct bcmsc_softc *)adp; if (sc->fb_addr == 0) return (0); @@ -921,6 +772,7 @@ bcmfb_putc(video_adapter_t *adp, vm_offs fg = a & 0xf ; bg = (a >> 4) & 0xf; + bytes = sc->depth / 8; for (i = 0; i < BCMFB_FONT_HEIGHT; i++) { for (j = 0, k = 7; j < 8; j++, k--) { if ((p[i] & (1 << k)) == 0) @@ -930,22 +782,32 @@ bcmfb_putc(video_adapter_t *adp, vm_offs switch (sc->depth) { case 32: - addr[4*j+0] = bcmfb_palette[color].r; - addr[4*j+1] = bcmfb_palette[color].g; - addr[4*j+2] = bcmfb_palette[color].b; - addr[4*j+3] = bcmfb_palette[color].a; - break; case 24: - addr[3*j] = bcmfb_palette[color].r; - addr[3*j+1] = bcmfb_palette[color].g; - addr[3*j+2] = bcmfb_palette[color].b; + if (sc->fbswap) { + addr[bytes * j + 0] = + bcmfb_palette[color].b; + addr[bytes * j + 1] = + bcmfb_palette[color].g; + addr[bytes * j + 2] = + bcmfb_palette[color].r; + } else { + addr[bytes * j + 0] = + bcmfb_palette[color].r; + addr[bytes * j + 1] = + bcmfb_palette[color].g; + addr[bytes * j + 2] = + bcmfb_palette[color].b; + } + if (sc->depth == 32) + addr[bytes * j + 3] = + bcmfb_palette[color].a; break; case 16: rgb = (bcmfb_palette[color].r >> 3) << 11; rgb |= (bcmfb_palette[color].g >> 2) << 5; rgb |= (bcmfb_palette[color].b >> 3); - addr[2*j] = rgb & 0xff; - addr[2*j + 1] = (rgb >> 8) & 0xff; + addr[bytes * j] = rgb & 0xff; + addr[bytes * j + 1] = (rgb >> 8) & 0xff; default: /* Not supported yet */ break;