This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 310a808d3d51087e316e63f72efaeb611fc20bcd Author: Matteo Golin <[email protected]> AuthorDate: Fri Nov 7 17:56:31 2025 -0500 rpi4b/framebuffer: Introduce frame buffer support to the RPi4B Introduces a very basic frame buffer driver implementation for the RPi4B which is registered at startup and works with frame buffer graphics examples (and LVGL). Graphics are displayed on the HDMI0 and HDMI1 output, depending which one is plugged into the display. I have not tested using both at once, nor does the driver account for that. They are both referred to as display 0, plane 0 since the RPi4B frame buffer interface does not seem to have a way of distinguishing. Signed-off-by: Matteo Golin <[email protected]> --- arch/arm64/src/bcm2711/CMakeLists.txt | 6 + arch/arm64/src/bcm2711/Kconfig | 11 + arch/arm64/src/bcm2711/Make.defs | 6 + arch/arm64/src/bcm2711/bcm2711_fb.c | 494 +++++++++++++++++++++ arch/arm64/src/bcm2711/bcm2711_mailbox.c | 474 ++++++++++++++++++++ arch/arm64/src/bcm2711/bcm2711_mailbox.h | 209 +++++++++ arch/arm64/src/bcm2711/hardware/bcm2711_mailbox.h | 18 + boards/arm64/bcm2711/raspberrypi-4b/Kconfig | 7 + .../bcm2711/raspberrypi-4b/configs/fb/defconfig | 59 +++ .../bcm2711/raspberrypi-4b/configs/lvgl/defconfig | 68 +++ .../bcm2711/raspberrypi-4b/src/rpi4b_bringup.c | 14 + 11 files changed, 1366 insertions(+) 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 <nuttx/config.h> + +#include <debug.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> + +#include <arch/board/board.h> +#include <nuttx/arch.h> +#include <nuttx/mutex.h> +#include <nuttx/semaphore.h> +#include <nuttx/video/fb.h> + +#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 <nuttx/fs/fs.h> #endif +#ifdef CONFIG_RPI4B_FRAMEBUFFER +#include <nuttx/video/fb.h> +#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; }
