diff --git a/arch/arm64/src/bcm2711/CMakeLists.txt b/arch/arm64/src/bcm2711/CMakeLists.txt index 2236ee22540..d8811d477a0 100644 --- a/arch/arm64/src/bcm2711/CMakeLists.txt +++ b/arch/arm64/src/bcm2711/CMakeLists.txt @@ -47,4 +47,10 @@ if(CONFIG_BCM2711_EMMC) list(APPEND SRCS bcm2711_sdio.c) endif() +# Graphics + +if(CONFIG_BCM2711_FRAMEBUFFER) + list(APPEND SRCS bcm2711_fb.c) +endif() + target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm64/src/bcm2711/Kconfig b/arch/arm64/src/bcm2711/Kconfig index 880f81f27c7..2228d41ccc3 100644 --- a/arch/arm64/src/bcm2711/Kconfig +++ b/arch/arm64/src/bcm2711/Kconfig @@ -329,6 +329,17 @@ config BCM2711_EMMC2_XFERSPEED endif # BCM2711_EMMC +##################################################################### +# Graphics +##################################################################### + +config BCM2711_FRAMEBUFFER + bool "Frame buffer graphics support" + depends on VIDEO_FB + default n + ---help--- + Support for the VideoCore frame buffer interface. + endmenu # Broadcom BCM2711 Peripheral Selection endif # ARCH_CHIP_BCM2711 diff --git a/arch/arm64/src/bcm2711/Make.defs b/arch/arm64/src/bcm2711/Make.defs index 0d7b71c8bd7..4a7b5855eb7 100644 --- a/arch/arm64/src/bcm2711/Make.defs +++ b/arch/arm64/src/bcm2711/Make.defs @@ -51,3 +51,9 @@ endif ifeq ($(CONFIG_BCM2711_EMMC),y) CHIP_CSRCS += bcm2711_sdio.c endif + +# Graphics + +ifeq ($(CONFIG_BCM2711_FRAMEBUFFER),y) +CHIP_CSRCS += bcm2711_fb.c +endif diff --git a/arch/arm64/src/bcm2711/bcm2711_fb.c b/arch/arm64/src/bcm2711/bcm2711_fb.c new file mode 100644 index 00000000000..9fd577695bb --- /dev/null +++ b/arch/arm64/src/bcm2711/bcm2711_fb.c @@ -0,0 +1,494 @@ +/**************************************************************************** + * arch/arm64/src/bcm2711/bcm2711_fb.c + * + * Contributed by Matteo Golin + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bcm2711_mailbox.h" +#include "arm64_arch.h" +#include "arm64_gic.h" +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Screen resolution */ + +#define FB_WIDTH (1920) +#define FB_HEIGHT (1080) + +/* Bits per pixel (32 for RGB) */ + +#define FB_BPP (32) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct bcm2711_fb_s +{ + struct fb_vtable_s vtable; /* vtable device */ + void *fb; /* Frame buffer pointer */ + uint32_t fbsize; /* Size of frame buffer in bytes */ + int dispno; /* Display number */ + bool inited; /* True when initialized */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int bcm2711_getvideoinfo(struct fb_vtable_s *vtable, + struct fb_videoinfo_s *vinfo); +static int bcm2711_getplaneinfo(struct fb_vtable_s *vtable, int planeno, + struct fb_planeinfo_s *pinfo); + +/* TODO: implement functions for other features available with the RPi + * frame buffer. There is some mailbox commands for a cursor, for instance. + */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* NOTE: It appears that the frame buffer can refer to either HDMI0 or HDMI1, + * depending which one is plugged into the display. I don't know what happens + * when both are plugged in at once, since I only have a single display to + * test with at the moment. I will therefore just refer to it generally as + * display 0, but some way to differentiate later would be beneficial. + */ + +static struct bcm2711_fb_s g_bcm2711_fb0 = +{ + .inited = 0, + .dispno = 0, + .vtable = + { + .getvideoinfo = bcm2711_getvideoinfo, + .getplaneinfo = bcm2711_getplaneinfo, + } +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bcm2711_getvideoinfo + * + * Description: + * Get the videoinfo for the framebuffer. (ioctl Entrypoint: + * FBIOGET_VIDEOINFO) + * + * Input Parameters: + * vtable - Framebuffer driver object + * vinfo - Returned videoinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int bcm2711_getvideoinfo(struct fb_vtable_s *vtable, + struct fb_videoinfo_s *vinfo) +{ + int err; + uint32_t bpp; + uint32_t xres; + uint32_t yres; + + DEBUGASSERT(vtable != NULL); + DEBUGASSERT(vinfo != NULL); + + vinfo->nplanes = 1; /* Only one plane supported */ + + err = bcm2711_mbox_getdisp(&xres, &yres); + if (err < 0) + { + gerr("Couldn't get display dimensions: %d", err); + return err; + } + + vinfo->xres = xres; + vinfo->yres = yres; + + err = bcm2711_mbox_getdepth(&bpp); + if (err < 0) + { + gerr("Couldn't get display depth: %d", err); + return err; + } + + /* NOTE: there appears to be no FB_FMT_* descriptors for BGR pixel + * ordering, so I will assume RGB always. + * + * TODO: not even sure how to check for some of the formats. No idea if 16 + * bpp is the 555 or 565 version. + * Should I also be making an attempt to set pixel order to RGB if the + * mailbox reports BGR? + */ + + err = bcm2711_mbox_getalpha(&xres); + if (err < 0) + { + gerr("Couldn't get alpha mode: %d", err); + return err; + } + + /* TODO: this method ignores the case when the alpha channel is reversed. + * Not sure how the frame buffer upper-half can handle that. + */ + + if (xres == 1) + { + gwarn("Alpha channel reversed, this is not handled"); + } + else + { + ginfo("Alpha channel: %s", xres == 0 ? "enabled" : "ignored"); + } + + switch (bpp) + { + case 4: + DEBUGASSERT(xres == 2); + vinfo->fmt = FB_FMT_RGB4; + break; + case 8: + DEBUGASSERT(xres == 2); + vinfo->fmt = FB_FMT_RGB8; + break; + case 16: + vinfo->fmt = xres == 0 ? FB_FMT_RGBA16 : FB_FMT_RGB16_555; + break; + case 24: + DEBUGASSERT(xres == 2); + vinfo->fmt = FB_FMT_RGB24; + break; + case 32: + vinfo->fmt = xres == 0 ? FB_FMT_RGBA32 : FB_FMT_RGB32; + break; + default: + gerr("Unknown depth of %u bpp", bpp); + return -EIO; + } + +#ifdef CONFIG_FB_OVERLAY + vinfo->noverlays = 0; /* No overlays supported */ +#endif + + return 0; +} + +/**************************************************************************** + * Name: pinephone_getplaneinfo + * + * Description: + * Get the planeinfo for the framebuffer. (ioctl Entrypoint: + * FBIOGET_PLANEINFO) + * + * Input Parameters: + * vtable - Framebuffer driver object + * pinfo - Returned planeinfo object + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int bcm2711_getplaneinfo(struct fb_vtable_s *vtable, int planeno, + struct fb_planeinfo_s *pinfo) +{ + int err; + uint32_t result; +#ifdef CONFIG_DEBUG_GRAPHICS_INFO + uint32_t overscan[4]; +#endif + struct bcm2711_fb_s *priv = (struct bcm2711_fb_s *)vtable; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(pinfo != NULL); + DEBUGASSERT(planeno == 0); /* Only one supported plane */ + +#ifdef CONFIG_DEBUG_GRAPHICS_INFO + + /* Get overscan for debugging purposes */ + + err = bcm2711_mbox_getoscan(&overscan[0], &overscan[1], &overscan[2], + &overscan[3]); + if (err < 0) + { + gerr("Couldn't get overscan amounts: %d", err); + } + + ginfo("Overscan px: top=%u, bot=%u, left=%u, right=%u", overscan[0], + overscan[1], overscan[2], overscan[3]); +#endif /* CONFIG_DEBUG_GRAPHICS_INFO */ + + /* With over-scan, the frame buffer is actually larger than the screen + * resolution. We have an extra `top + bottom` pixels in the y, and `left + + * right` in the x. + */ + + pinfo->fbmem = priv->fb; + pinfo->fblen = priv->fbsize; + pinfo->display = priv->dispno; + + /* Get VideoCore information about stride */ + + err = bcm2711_mbox_getpitch(&result); + if (err < 0) + { + gerr("Couldn't get pitch: %d", err); + return err; + } + + pinfo->stride = result; + + /* Get VideoCore information about bits per pixel */ + + err = bcm2711_mbox_getdepth(&result); + if (err < 0) + { + gerr("Couldn't get display depth: %d", err); + return err; + } + + pinfo->bpp = result; + + /* Get virtual resolution */ + + err = bcm2711_mbox_getvirtres(&pinfo->xres_virtual, &pinfo->yres_virtual); + if (err) + { + gerr("Couldn't get virtual resolution: %d", err); + return err; + } + + ginfo("Virtual resolution: %u x %u px", + pinfo->xres_virtual, pinfo->yres_virtual); + + /* Get offset from virtual resolution to visible resolution */ + + err = bcm2711_mbox_getvirtoff(&pinfo->xoffset, &pinfo->yoffset); + if (err) + { + gerr("Couldn't get virtual offset: %d", err); + return err; + } + + ginfo("Virtual offset: (%u, %u) px", pinfo->xoffset, pinfo->yoffset); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_fbinitialize + * + * Description: + * Initialize the framebuffer video hardware associated with the display. + * + * There are multiple logic paths that may call up_fbinitialize() so any + * implementation of up_fbinitialize() should be tolerant of being called + * multiple times. + * + * Input Parameters: + * display - In the case of hardware with multiple displays, this + * specifies the display. Normally this is zero. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +int up_fbinitialize(int display) +{ + int err; + uint8_t tries = 0; + uint32_t xres = FB_WIDTH; + uint32_t yres = FB_HEIGHT; + uint32_t bpp = FB_BPP; + struct bcm2711_fb_s *priv; + + switch (display) + { + case 0: + priv = &g_bcm2711_fb0; + break; + default: + gerr("Unsupported display: %d", display); + return -EINVAL; + } + + /* Already initialized */ + + if (priv->inited) + { + return 0; + } + + /* Basic initialization of members */ + + priv->fb = NULL; + priv->fbsize = 0; + + /* Initialize the frame-buffer in a bulk request. Doing this piece-wise + * never seems to work, always resulting a virtual resolution of 2x2 px. + * This attempts the initialization three times since the operation always + * seems to fail right after boot time. + */ + + do + { + err = bcm2711_mbox_fbinit(&xres, &yres, &bpp, + &priv->fb, &priv->fbsize); + tries++; + } + while (err < 0 && tries < 3); + + if (err < 0) + { + gerr("Failed to initialize frame buffer: %d", err); + return err; + } + + if (xres != FB_WIDTH || yres != FB_HEIGHT) + { + gerr("Display mismatch: wanted %u x %u px, but got %u x %u px", + FB_WIDTH, FB_HEIGHT, xres, yres); + return -EIO; + } + + if (bpp != FB_BPP) + { + gerr("Depth mismatch: wanted %u bpp, got %u bpp", FB_BPP, bpp); + return -EIO; + } + + priv->inited = true; + ginfo("Display %d initialized.", display); + return 0; +} + +/**************************************************************************** + * Name: up_fbgetvplane + * + * Description: + * Return a reference to the framebuffer object for the specified video + * plane of the specified plane. Many OSDs support multiple planes of + * video. + * + * Input Parameters: + * display - In the case of hardware with multiple displays, this + * specifies the display. Normally this is zero. + * vplane - Identifies the plane being queried. + * + * Returned Value: + * A non-NULL pointer to the frame buffer access structure is returned on + * success; NULL is returned on any failure. + * + ****************************************************************************/ + +struct fb_vtable_s *up_fbgetvplane(int display, int vplane) +{ + DEBUGASSERT(vplane == 0); /* Only one plane supported */ + + switch (display) + { + case 0: + return &g_bcm2711_fb0.vtable; + break; + default: + gerr("Invalid display: %d", display); + return NULL; + } +} + +/**************************************************************************** + * Name: up_fbuninitialize + * + * Description: + * Uninitialize the framebuffer support for the specified display. + * + * Input Parameters: + * display - In the case of hardware with multiple displays, this + * specifies the display. Normally this is zero. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_fbuninitialize(int display) +{ + int err; + struct bcm2711_fb_s *priv; + + switch (display) + { + case 0: + priv = &g_bcm2711_fb0; + break; + default: + gerr("Invalid display: %d", display); + return; + } + + /* Already uninitialized */ + + if (!priv->inited) + { + return; + } + + /* Release frame buffer via mailbox. */ + + err = bcm2711_mbox_releasefb(); + if (err < 0) + { + gerr("Couldn't release frame buffer: %d", err); + return; + } + + priv->inited = false; + ginfo("Display %d uninitialized.", display); +} diff --git a/arch/arm64/src/bcm2711/bcm2711_mailbox.c b/arch/arm64/src/bcm2711/bcm2711_mailbox.c index 9a23890bb26..5065e33d312 100644 --- a/arch/arm64/src/bcm2711/bcm2711_mailbox.c +++ b/arch/arm64/src/bcm2711/bcm2711_mailbox.c @@ -746,3 +746,477 @@ int bcm2711_mbox_setclkrate(uint8_t id, uint32_t *rate, bool turbo) *rate = buf[6]; return err; } + +/**************************************************************************** + * Name: bcm2711_mbox_getfb + * + * Description: + * Allocates a frame buffer and returns it. + * + * Input parameters: + * fb - A place to store the frame buffer address + * size - The frame buffer size in bytes + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getfb(void **fb, uint32_t *size) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 2] ALIGNED_MBOX; + + DEBUGASSERT(fb != NULL); + + buf[0] = 16; /* Alignment in bytes TODO: should this be variable? */ + buf[1] = 0; + + bcm2711_mbox_makereq(MBOX_TAG_FALLOC, buf, 2 * sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + + *fb = (void *)(unsigned long)VCADDR_TO_ARM(buf[5]); + *size = buf[6]; + + /* Docs say that if size is returned as 0, the alignment was + * invalid because the frame buffer wasn't allocated. + */ + + if (buf[6] == 0 && !err) + { + ipcerr("Frame buffer alignment of 16 bytes invalid."); + return -EINVAL; /* Invalid alignment */ + } + + /* Frame buffer address needs to be modified since the address is what's + * seen from the VideoCore memory. + */ + + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_releasefb + * + * Description: + * Releases the previously allocated frame buffer. + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_releasefb(void) +{ + uint32_t buf[BUF_FIELDS + TAG_FIELDS] ALIGNED_MBOX; + bcm2711_mbox_makereq(MBOX_TAG_FREL, buf, 0, sizeof(buf)); + return bcm2711_mbox_sendreq(buf, sizeof(buf)); +} + +/**************************************************************************** + * Name: bcm2711_mbox_getdisp + * + * Description: + * Get physical display width and height. + * + * Input parameters: + * x - Width in pixels + * y - Height in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getdisp(uint32_t *x, uint32_t *y) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 2] ALIGNED_MBOX; + + DEBUGASSERT(x != NULL); + DEBUGASSERT(y != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETDISP, buf, 2 * sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + + *x = buf[5]; + *y = buf[6]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getdepth + * + * Description: + * Get the bits per pixel used for the display. + * + * Input parameters: + * bpp - Bits per pixel + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getdepth(uint32_t *bpp) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 1] ALIGNED_MBOX; + + DEBUGASSERT(bpp != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETDEPTH, buf, sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *bpp = buf[5]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getalpha + * + * Description: + * Get the alpha mode. + * + * Input parameters: + * alpha - Returned alpha state: 0 enabled, 1 reversed, 2 ignored + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getalpha(uint32_t *alpha) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 1] ALIGNED_MBOX; + + DEBUGASSERT(alpha != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETALPHA, buf, sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *alpha = buf[5]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getpitch + * + * Description: + * Get the number of bytes per line. + * + * Input parameters: + * bpl - Bytes per line + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getpitch(uint32_t *bpl) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 1] ALIGNED_MBOX; + + DEBUGASSERT(bpl != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETPITCH, buf, sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *bpl = buf[5]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getvirtres + * + * Description: + * Get the virtual resolution of the display. + * + * Input parameters: + * x - Width in pixels + * y - Height in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getvirtres(uint32_t *x, uint32_t *y) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 2] ALIGNED_MBOX; + + DEBUGASSERT(x != NULL); + DEBUGASSERT(y != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETVBUF, buf, 2 * sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *x = buf[5]; + *y = buf[6]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_setvirtres + * + * Description: + * Set the virtual resolution of the display. The new virtual resolution is + * returned in the input parameters. + * + * Input parameters: + * x - Width in pixels + * y - Height in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_setvirtres(uint32_t *x, uint32_t *y) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 2] ALIGNED_MBOX; + + DEBUGASSERT(x != NULL); + DEBUGASSERT(y != NULL); + + buf[0] = *x; + buf[1] = *y; + + bcm2711_mbox_makereq(MBOX_TAG_SETVBUF, buf, 2 * sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *x = buf[5]; + *y = buf[6]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getvirtoff + * + * Description: + * Get the virtual buffer offset in pixels + * + * Input parameters: + * x - X in pixels + * y - Y in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getvirtoff(uint32_t *x, uint32_t *y) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 2] ALIGNED_MBOX; + + DEBUGASSERT(x != NULL); + DEBUGASSERT(y != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETVIRTOFF, buf, 2 * sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *x = buf[5]; + *y = buf[6]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getpixord + * + * Description: + * Get the pixel order of the frame buffer. + * + * Input parameters: + * rgb - True if RGB order, false for BGR order + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getpixord(bool *rgb) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 1] ALIGNED_MBOX; + + DEBUGASSERT(rgb != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETPIXORD, buf, sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *rgb = buf[5] ? true : false; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_setpixord + * + * Description: + * Set the pixel order of the frame buffer. + * + * Input parameters: + * rgb - True if RGB order, false for BGR order + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_setpixord(bool rgb) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 1] ALIGNED_MBOX; + + buf[0] = rgb ? 1 : 0; + + bcm2711_mbox_makereq(MBOX_TAG_SETPIXORD, buf, sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + + if (buf[5] != rgb) + { + ipcinfo("Pixel order refused."); + return -EAGAIN; + } + + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_getoscan + * + * Description: + * Get the overscan values of the frame buffer in pixels. + * + * Input parameters: + * top - The amount of top overscan in pixels + * bot - The amount of bottom overscan in pixels + * left - The amount of left overscan in pixels + * right - The amount of right overscan in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getoscan(uint32_t *top, uint32_t *bot, uint32_t *left, + uint32_t *right) +{ + int err; + uint32_t buf[BUF_FIELDS + TAG_FIELDS + 4] ALIGNED_MBOX; + + DEBUGASSERT(top != NULL); + DEBUGASSERT(bot != NULL); + DEBUGASSERT(left != NULL); + DEBUGASSERT(right != NULL); + + bcm2711_mbox_makereq(MBOX_TAG_GETOVSCAN, buf, 4 * sizeof(uint32_t), + sizeof(buf)); + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + *top = buf[5]; + *bot = buf[6]; + *left = buf[7]; + *right = buf[8]; + return err; +} + +/**************************************************************************** + * Name: bcm2711_mbox_fbinit + * + * Description: + * Initializes the frame buffer video interface with the desired settings. + * NOTE: performing each of these actions individually does not appear to + * work correctly. I experienced 2x2 virtual resolution when I was trying + * to do this piece-wise. Other examples online take this bulk approach, + * and it seems to work without issue. + * + * Input parameters: + * x - The resolution (width) in pixels (physical display width returned + * here) + * y - The resolution (height) in pixels (physical display height returned + * here) + * bpp - The bits per pixel (depth) (real value returned her) + * fb - The returned frame buffer address + * fblen - The length of the frame buffer in bytes + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_fbinit(uint32_t *x, uint32_t *y, uint32_t *bpp, void **fb, + uint32_t *fblen) +{ + int err; + uint32_t buf[35] ALIGNED_MBOX; + + DEBUGASSERT(x != NULL); + DEBUGASSERT(y != NULL); + DEBUGASSERT(fb != NULL); + + buf[0] = sizeof(buf); + buf[1] = BCM_VC_MBOX_REQUEST; + + /* First, set the physical display height and width */ + + buf[2] = MBOX_TAG_SETDISP; + buf[3] = 8; + buf[4] = 0; + buf[5] = *x; + buf[6] = *y; + + /* Set the virtual resolution */ + + buf[7] = MBOX_TAG_SETVBUF; + buf[8] = 8; + buf[9] = 8; + buf[10] = *x; + buf[11] = *y; + + /* Set offset into virtual display as 0 */ + + buf[12] = MBOX_TAG_SETVIRTOFF; + buf[13] = 8; + buf[14] = 8; + buf[15] = 0; + buf[16] = 0; + + /* Set bits per pixel */ + + buf[17] = MBOX_TAG_SETDEPTH; + buf[18] = 4; + buf[19] = 4; + buf[20] = *bpp; + + /* Set the pixel order to RGB order */ + + buf[21] = MBOX_TAG_SETPIXORD; + buf[22] = 4; + buf[23] = 4; + buf[24] = 0; + + /* Allocate a frame buffer */ + + buf[25] = MBOX_TAG_FALLOC; + buf[26] = 8; + buf[27] = 8; + buf[28] = *bpp; /* Alignment in bits */ + buf[29] = 0; + + /* Get the stride */ + + buf[30] = MBOX_TAG_GETPITCH; + buf[31] = 4; + buf[32] = 4; + buf[33] = 0; + + buf[34] = BCM_VC_MBOX_TAGLIST_END; + + err = bcm2711_mbox_sendreq(buf, sizeof(buf)); + if (err < 0) + { + ipcerr("Couldn't send frame buffer init request: %d.", err); + return err; + } + + *x = buf[10]; + *y = buf[11]; + *bpp = buf[20]; + *fb = (void *)(uintptr_t)VCADDR_TO_ARM(buf[28]); + *fblen = buf[29]; + return 0; +} diff --git a/arch/arm64/src/bcm2711/bcm2711_mailbox.h b/arch/arm64/src/bcm2711/bcm2711_mailbox.h index c9674e32e6e..c139f6ae77a 100644 --- a/arch/arm64/src/bcm2711/bcm2711_mailbox.h +++ b/arch/arm64/src/bcm2711/bcm2711_mailbox.h @@ -359,6 +359,215 @@ int bcm2711_mbox_getclkrate(uint8_t id, uint32_t *rate, bool measured); int bcm2711_mbox_setclkrate(uint8_t id, uint32_t *rate, bool turbo); +/**************************************************************************** + * Name: bcm2711_mbox_getfb + * + * Description: + * Allocates a frame buffer and returns it. + * + * Input parameters: + * fb - A place to store the frame buffer address + * size - The frame buffer size in bytes + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getfb(void **fb, uint32_t *size); + +/**************************************************************************** + * Name: bcm2711_mbox_releasefb + * + * Description: + * Releases the previously allocated frame buffer. + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_releasefb(void); + +/**************************************************************************** + * Name: bcm2711_mbox_getdisp + * + * Description: + * Get physical display width and height. + * + * Input parameters: + * x - Width in pixels + * y - Height in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getdisp(uint32_t *x, uint32_t *y); + +/**************************************************************************** + * Name: bcm2711_mbox_getdepth + * + * Description: + * Get the bits per pixel used for the display. + * + * Input parameters: + * bpp - Bits per pixel + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getdepth(uint32_t *bpp); + +/**************************************************************************** + * Name: bcm2711_mbox_getalpha + * + * Description: + * Get the alpha mode. + * + * Input parameters: + * alpha - Returned alpha state: 0 enabled, 1 reversed, 2 ignored + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getalpha(uint32_t *alpha); + +/**************************************************************************** + * Name: bcm2711_mbox_getpitch + * + * Description: + * Get the number of bytes per line. + * + * Input parameters: + * bpl - Bytes per line + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getpitch(uint32_t *bpl); + +/**************************************************************************** + * Name: bcm2711_mbox_getvirtres + * + * Description: + * Get the virtual resolution of the display. + * + * Input parameters: + * x - Width in pixels + * y - Height in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getvirtres(uint32_t *x, uint32_t *y); + +/**************************************************************************** + * Name: bcm2711_mbox_setvirtres + * + * Description: + * Set the virtual resolution of the display. The new virtual resolution is + * returned in the input parameters. + * + * Input parameters: + * x - Width in pixels + * y - Height in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_setvirtres(uint32_t *x, uint32_t *y); + +/**************************************************************************** + * Name: bcm2711_mbox_getvirtoff + * + * Description: + * Get the virtual buffer offset in pixels + * + * Input parameters: + * x - X in pixels + * y - Y in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getvirtoff(uint32_t *x, uint32_t *y); + +/**************************************************************************** + * Name: bcm2711_mbox_getpixord + * + * Description: + * Get the pixel order of the frame buffer. + * + * Input parameters: + * rgb - True if RGB order, false for BGR order + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getpixord(bool *rgb); + +/**************************************************************************** + * Name: bcm2711_mbox_setpixord + * + * Description: + * Set the pixel order of the frame buffer. + * + * Input parameters: + * rgb - True if RGB order, false for BGR order + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_setpixord(bool rgb); + +/**************************************************************************** + * Name: bcm2711_mbox_getoscan + * + * Description: + * Get the overscan values of the frame buffer in pixels. + * + * Input parameters: + * top - The amount of top overscan in pixels + * bot - The amount of bottom overscan in pixels + * left - The amount of left overscan in pixels + * right - The amount of right overscan in pixels + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_getoscan(uint32_t *top, uint32_t *bot, uint32_t *left, + uint32_t *right); + +/**************************************************************************** + * Name: bcm2711_mbox_fbinit + * + * Description: + * Initializes the frame buffer video interface with the desired settings. + * + * Input parameters: + * x - The resolution (width) in pixels (physical display width returned + * here) + * y - The resolution (height) in pixels (physical display height returned + * here) + * bpp - The bits per pixel (depth) (real value returned her) + * fb - The returned frame buffer address + * fblen - The length of the frame buffer in bytes + * + * Returned Value: + * 0 on success, negated error code on failure. + ****************************************************************************/ + +int bcm2711_mbox_fbinit(uint32_t *x, uint32_t *y, uint32_t *bpp, void **fb, + uint32_t *fblen); + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_mailbox.h b/arch/arm64/src/bcm2711/hardware/bcm2711_mailbox.h index f7fe0879c9d..9eca185b249 100644 --- a/arch/arm64/src/bcm2711/hardware/bcm2711_mailbox.h +++ b/arch/arm64/src/bcm2711/hardware/bcm2711_mailbox.h @@ -160,4 +160,22 @@ #define BCM_VC_MBOX_FIFO_DEPTH (8) /* 8-deep FIFO of 32-bit words */ +/* We assume L2 cache enabled. The user can disable this from config.txt but + * that's their problem. + */ + +#define L2_CACHE_EN 1 + +/* Physical address mappings between VideoCore and ARM bus */ + +#ifdef L2_CACHE_EN +#define PHY_MEM_START (0x40000000) +#else +#define PHY_MEM_START (0xc0000000) +#endif /* L2_CACHE_EN */ + +/* Maps VideoCore addresses to ARM addresses. As seen in LLD */ + +#define VCADDR_TO_ARM(addr) (((addr) | PHY_MEM_START) & ~(0xc0000000)) + #endif /* __ARCH_ARM64_SRC_BCM2711_MAILBOX_H */ diff --git a/boards/arm64/bcm2711/raspberrypi-4b/Kconfig b/boards/arm64/bcm2711/raspberrypi-4b/Kconfig index cba685a54e3..a20867c9f7b 100644 --- a/boards/arm64/bcm2711/raspberrypi-4b/Kconfig +++ b/boards/arm64/bcm2711/raspberrypi-4b/Kconfig @@ -53,4 +53,11 @@ config RPI4B_MOUNT_BOOT Mounts the boot partition of the micro SD card to NuttX as a read/write file system. +config RPI4B_FRAMEBUFFER + bool "Register frame buffer driver" + depends on BCM2711_FRAMEBUFFER + default BCM2711_FRAMEBUFFER + ---help--- + Registers a frame buffer character driver for graphical output. + endif # ARCH_BOARD_RASPBERRYPI_4B diff --git a/boards/arm64/bcm2711/raspberrypi-4b/configs/fb/defconfig b/boards/arm64/bcm2711/raspberrypi-4b/configs/fb/defconfig new file mode 100644 index 00000000000..a8268ea2cd7 --- /dev/null +++ b/boards/arm64/bcm2711/raspberrypi-4b/configs/fb/defconfig @@ -0,0 +1,59 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_SYSTEM_DD is not set +CONFIG_ARCH="arm64" +CONFIG_ARCH_ARM64=y +CONFIG_ARCH_BOARD="raspberrypi-4b" +CONFIG_ARCH_BOARD_RASPBERRYPI_4B=y +CONFIG_ARCH_CHIP="bcm2711" +CONFIG_ARCH_CHIP_BCM2711=y +CONFIG_ARCH_EARLY_PRINT=y +CONFIG_ARCH_INTERRUPTSTACK=4096 +CONFIG_BCM2711_FRAMEBUFFER=y +CONFIG_BOARD_LOOPSPERMSEC=132954 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=8192 +CONFIG_DRIVERS_VIDEO=y +CONFIG_EXAMPLES_FB=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PTHREAD_STACK_MIN=8192 +CONFIG_RAMLOG=y +CONFIG_RAM_SIZE=4227858432 +CONFIG_RAM_START=0x00000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SPINLOCK=y +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2022 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TESTING_OSTEST=y +CONFIG_USEC_PER_TICK=1000 +CONFIG_USERLED=y +CONFIG_VIDEO_FB=y diff --git a/boards/arm64/bcm2711/raspberrypi-4b/configs/lvgl/defconfig b/boards/arm64/bcm2711/raspberrypi-4b/configs/lvgl/defconfig new file mode 100644 index 00000000000..d959a08a0c4 --- /dev/null +++ b/boards/arm64/bcm2711/raspberrypi-4b/configs/lvgl/defconfig @@ -0,0 +1,68 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_SYSTEM_DD is not set +CONFIG_ARCH="arm64" +CONFIG_ARCH_ARM64=y +CONFIG_ARCH_BOARD="raspberrypi-4b" +CONFIG_ARCH_BOARD_RASPBERRYPI_4B=y +CONFIG_ARCH_CHIP="bcm2711" +CONFIG_ARCH_CHIP_BCM2711=y +CONFIG_ARCH_EARLY_PRINT=y +CONFIG_ARCH_INTERRUPTSTACK=4096 +CONFIG_BCM2711_FRAMEBUFFER=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=132954 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=8192 +CONFIG_DRIVERS_VIDEO=y +CONFIG_EXAMPLES_LVGLDEMO=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_GRAPHICS_LVGL=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_INIT_ARGS="\"widgets\"" +CONFIG_INIT_ENTRYPOINT="lvgldemo_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_LV_COLOR_DEPTH_32=y +CONFIG_LV_DPI_DEF=250 +CONFIG_LV_USE_CLIB_MALLOC=y +CONFIG_LV_USE_CLIB_SPRINTF=y +CONFIG_LV_USE_CLIB_STRING=y +CONFIG_LV_USE_DEMO_WIDGETS=y +CONFIG_LV_USE_NUTTX=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PTHREAD_STACK_MIN=8192 +CONFIG_RAMLOG=y +CONFIG_RAM_SIZE=4227858432 +CONFIG_RAM_START=0x00000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SPINLOCK=y +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2022 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_SYSTEM_TIME64=y +CONFIG_USEC_PER_TICK=1000 +CONFIG_USERLED=y +CONFIG_VIDEO_FB=y diff --git a/boards/arm64/bcm2711/raspberrypi-4b/src/rpi4b_bringup.c b/boards/arm64/bcm2711/raspberrypi-4b/src/rpi4b_bringup.c index ddd6903c248..bcb90de619c 100644 --- a/boards/arm64/bcm2711/raspberrypi-4b/src/rpi4b_bringup.c +++ b/boards/arm64/bcm2711/raspberrypi-4b/src/rpi4b_bringup.c @@ -41,6 +41,10 @@ #include #endif +#ifdef CONFIG_RPI4B_FRAMEBUFFER +#include +#endif + #include "rpi4b.h" /**************************************************************************** @@ -141,5 +145,15 @@ int rpi4b_bringup(void) } #endif +#ifdef CONFIG_RPI4B_FRAMEBUFFER + /* Initialize and register the frame buffer driver */ + + ret = fb_register(0, 0); + if (ret < 0) + { + syslog(LOG_ERR, "Couldn't register framebuffer driver: %d", ret); + } +#endif + return ret; }