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


The following commit(s) were added to refs/heads/master by this push:
     new 5accd7c146 drivers/video: add Goldfish-FB driver
5accd7c146 is described below

commit 5accd7c1468b93764b151fdb1019aa15f2d4aee9
Author: jianglianfang <[email protected]>
AuthorDate: Thu Jun 29 19:18:09 2023 +0800

    drivers/video: add Goldfish-FB driver
    
    the register definition is described here:
    
https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
    
    Goldfish-FB driver is to communicate with Goldfish-FB in QEMU, and push the 
framebuffer data to the emulator for display on the screen.
    test: CONFIG_GOLDFISH_FB =1, and run demo=>lvgldemo widgets
    
    Signed-off-by: jianglianfang <[email protected]>
---
 drivers/video/Kconfig       |  28 +++
 drivers/video/Make.defs     |   4 +
 drivers/video/goldfish_fb.c | 443 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index fcb80547bd..3e1e38d181 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -56,6 +56,34 @@ config VIDEO_STREAM
        ---help---
                Enable video Stream support
 
+config GOLDFISH_FB
+       bool "Goldfish Framebuffer character driver"
+       depends on VIDEO_FB
+       default n
+
+config GOLDFISH_FB_VIDEO_MODE
+       bool "Goldfish Framebuffer display mode"
+       depends on GOLDFISH_FB
+       default n
+       ---help---
+               GOLDFISH_FB_VIDEO_MODE = y  enable video mode
+               GOLDFISH_FB_VIDEO_MODE = n  enable command mode
+
+config GOLDFISH_FB_IRQ
+       int "Goldfish fb irq"
+       depends on GOLDFISH_FB
+       default 48
+
+config GOLDFISH_FB_BASE
+       hex "Goldfish fb base"
+       depends on GOLDFISH_FB
+       default 0x0a020000
+
+config GOLDFISH_FB_FRAME_NBUFFER
+       int "Goldfish fb vsync size"
+       depends on GOLDFISH_FB
+       default 2
+
 if VIDEO_STREAM
 
 config VIDEO_REQBUFS_COUNT_MAX
diff --git a/drivers/video/Make.defs b/drivers/video/Make.defs
index b40305ee28..3bd614f612 100644
--- a/drivers/video/Make.defs
+++ b/drivers/video/Make.defs
@@ -48,6 +48,10 @@ endif
 
 endif
 
+ifeq ($(CONFIG_GOLDFISH_FB),y)
+  CSRCS += goldfish_fb.c
+endif
+
 # These video drivers depend on SPI support
 
 ifeq ($(CONFIG_SPI),y)
diff --git a/drivers/video/goldfish_fb.c b/drivers/video/goldfish_fb.c
new file mode 100644
index 0000000000..44d5158011
--- /dev/null
+++ b/drivers/video/goldfish_fb.c
@@ -0,0 +1,443 @@
+/****************************************************************************
+ * drivers/video/goldfish_fb.c
+ *
+ * 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 <debug.h>
+#include <nuttx/config.h>
+#include <nuttx/video/fb.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mm/circbuf.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#ifndef putreg32
+#define putreg32(v, x) (*(volatile uint32_t *)(x) = (v))
+#endif
+
+#ifndef getreg32
+#define getreg32(x) (*(uint32_t *)(x))
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum
+{
+  GOLDFISH_FB_GET_WIDTH = 0x00,
+  GOLDFISH_FB_GET_HEIGHT = 0x04,
+  GOLDFISH_FB_INT_STATUS = 0x08,
+  GOLDFISH_FB_INT_ENABLE = 0x0c,
+  GOLDFISH_FB_SET_BASE = 0x10,
+  GOLDFISH_FB_SET_ROTATION = 0x14,
+  GOLDFISH_FB_SET_BLANK = 0x18,
+  GOLDFISH_FB_GET_PHYS_WIDTH = 0x1c,
+  GOLDFISH_FB_GET_PHYS_HEIGHT = 0x20,
+  GOLDFISH_FB_GET_FORMAT = 0x24,
+  GOLDFISH_FB_INT_VSYNC = 1U << 0,
+  GOLDFISH_FB_INT_UPDATE_DONE = 1U << 1,
+  GOLDFISH_FB_FORMAT_BRGA_8888 = 1,
+  GOLDFISH_FB_FORMAT_RGBX_8888 = 2,
+  GOLDFISH_FB_FORMAT_RGB_888 = 3,
+  GOLDFISH_FB_FORMAT_RGB_565 = 4,
+  GOLDFISH_FB_FORMAT_BGRA_8888 = 5,
+  GOLDFISH_FB_FORMAT_RGBA_5551 = 6,
+  GOLDFISH_FB_FORMAT_RGBA_4444 = 8
+};
+
+struct goldfish_fb_format_s
+{
+  uint8_t fmt;
+  uint8_t bpp;
+};
+
+struct goldfish_fb_s
+{
+  struct fb_vtable_s vtable;
+  struct fb_planeinfo_s planeinfo;
+  struct fb_videoinfo_s videoinfo;
+  FAR void *base;
+  int irq;
+  struct circbuf_s vsync;   /* Vsync event queued */
+#ifdef CONFIG_GOLDFISH_FB_VIDEO_MODE
+  bool busy; /* Only used in the video mode */
+  uintptr_t cur_buf;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static FAR struct goldfish_fb_s *g_goldfish_fb;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int goldfish_fb_pan_display(FAR struct fb_vtable_s *vtable,
+                                   FAR struct fb_planeinfo_s *pinfo);
+static int goldfish_getvideoinfo(FAR struct fb_vtable_s *vtable,
+                                 FAR struct fb_videoinfo_s *vinfo);
+static int goldfish_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
+                                 FAR struct fb_planeinfo_s *pinfo);
+static int goldfish_fb_interrupt(int irq, FAR void *dev_id, FAR void *arg);
+static void goldfish_fb_vsync_irq(FAR struct goldfish_fb_s *fb);
+static void goldfish_fb_framedone_irq(FAR struct goldfish_fb_s *fb);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: goldfish_fb_vsync_irq
+ ****************************************************************************/
+
+#ifdef CONFIG_GOLDFISH_FB_VIDEO_MODE
+static void goldfish_fb_vsync_irq(FAR struct goldfish_fb_s *fb)
+{
+  struct fb_planeinfo_s pinfo;
+
+  /* Attempte to retrieve a frame from the vsync queue */
+
+  ssize_t ret = circbuf_read(&fb->vsync, &pinfo,
+                             sizeof(struct fb_planeinfo_s));
+  DEBUGASSERT(ret <= 0 || ret == sizeof(struct fb_planeinfo_s));
+
+  fb->busy = true;
+  if (ret > 0)
+    {
+      fb->cur_buf = (uintptr_t)((uint8_t *)fb->planeinfo.fbmem +
+                                           fb->planeinfo.stride *
+                                           pinfo.yoffset);
+    }
+
+  if (fb->cur_buf)
+    {
+      /* Send buffer addr to GOLDFISH */
+
+      putreg32(fb->cur_buf, fb->base + GOLDFISH_FB_SET_BASE);
+    }
+}
+#else
+static void goldfish_fb_vsync_irq(FAR struct goldfish_fb_s *fb)
+{
+  struct fb_planeinfo_s pinfo;
+
+  /* Attempte to retrieve a frame from the vsync queue */
+
+  ssize_t ret = circbuf_read(&fb->vsync, &pinfo,
+                             sizeof(struct fb_planeinfo_s));
+  DEBUGASSERT(ret <= 0 || ret == sizeof(struct fb_planeinfo_s));
+
+  if (ret > 0)
+    {
+      uintptr_t buf = (uintptr_t)((uint8_t *)fb->planeinfo.fbmem +
+                                             fb->planeinfo.stride *
+                                             pinfo.yoffset);
+
+      /* Send buffer addr to GOLDFISH */
+
+      putreg32(buf, fb->base + GOLDFISH_FB_SET_BASE);
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: goldfish_fb_framedone_irq
+ ****************************************************************************/
+
+#ifdef CONFIG_GOLDFISH_FB_VIDEO_MODE
+static void goldfish_fb_framedone_irq(FAR struct goldfish_fb_s *fb)
+{
+  fb->busy = false;
+
+  if (fb->cur_buf && !circbuf_is_empty(&fb->vsync))
+    {
+      /* Clear the current frame buffer */
+
+      fb->cur_buf = 0;
+
+      /* After the sending is completed, notify the upper
+       * layer that the framebuffer can be written.
+       */
+
+      fb_pollnotify(&fb->vtable);
+    }
+}
+#else
+static void goldfish_fb_framedone_irq(FAR struct goldfish_fb_s *fb)
+{
+  /* After the sending is completed, notify the upper
+   * layer that the framebuffer can be written.
+   */
+
+  fb_pollnotify(&fb->vtable);
+}
+#endif
+
+/****************************************************************************
+ * Name: goldfish_fb_interrupt
+ ****************************************************************************/
+
+static int goldfish_fb_interrupt(int irq, FAR void *dev_id, FAR void *arg)
+{
+  FAR struct goldfish_fb_s *fb = arg;
+  irqstate_t flags;
+  uint32_t status;
+
+  flags = enter_critical_section();
+  status = getreg32(fb->base + GOLDFISH_FB_INT_STATUS);
+  if (status & GOLDFISH_FB_INT_VSYNC)
+    {
+      goldfish_fb_vsync_irq(fb);
+    }
+
+  else if (status & GOLDFISH_FB_INT_UPDATE_DONE)
+    {
+      goldfish_fb_framedone_irq(fb);
+    }
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: goldfish_fb_pan_display
+ ****************************************************************************/
+
+static int goldfish_fb_pan_display(FAR struct fb_vtable_s *vtable,
+                                   FAR struct fb_planeinfo_s *pinfo)
+{
+  struct goldfish_fb_s *fb = (FAR struct goldfish_fb_s *)vtable;
+  irqstate_t flags;
+  ssize_t ret;
+
+  /** Disable the interrupt when writing to the queue to
+   *  prevent it from being modified by the interrupted
+   * thread during the writing process.
+   */
+
+  flags = enter_critical_section();
+
+  /* Write the planeinfo information submitted
+   * by the renderer to the queue
+   */
+
+  ret = circbuf_write(&fb->vsync, pinfo,
+                      sizeof(struct fb_planeinfo_s));
+  DEBUGASSERT(ret == sizeof(struct fb_planeinfo_s));
+
+#ifdef CONFIG_GOLDFISH_FB_VIDEO_MODE
+  if (fb->cur_buf && !fb->busy)
+    {
+      /* Clear the current frame buffer if not busy in transfering */
+
+      fb->cur_buf = 0;
+
+      /* Notify the upper layer that the framebuffer can be written */
+
+      fb_pollnotify(&fb->vtable);
+    }
+#endif
+
+  /* Re-enable interrupts */
+
+  leave_critical_section(flags);
+  return ret < 0 ? ret : 0;
+}
+
+/****************************************************************************
+ * Name: goldfish_getvideoinfo
+ ****************************************************************************/
+
+static int goldfish_getvideoinfo(FAR struct fb_vtable_s *vtable,
+                                 FAR struct fb_videoinfo_s *vinfo)
+{
+  FAR struct goldfish_fb_s *fb = (FAR struct goldfish_fb_s *)vtable;
+
+  ginfo("vtable=%p vinfo=%p\n", vtable, vinfo);
+  if (fb && vinfo)
+    {
+      memcpy(vinfo, &fb->videoinfo, sizeof(struct fb_videoinfo_s));
+      return OK;
+    }
+
+  gerr("ERROR: Returning EINVAL\n");
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: goldfish_getplaneinfo
+ ****************************************************************************/
+
+static int goldfish_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
+                                 FAR struct fb_planeinfo_s *pinfo)
+{
+  FAR struct goldfish_fb_s *fb = (FAR struct goldfish_fb_s *)vtable;
+
+  ginfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo);
+  if (fb && planeno == 0 && pinfo)
+    {
+      memcpy(pinfo, &fb->planeinfo, sizeof(struct fb_planeinfo_s));
+      return OK;
+    }
+
+  gerr("ERROR: Returning EINVAL\n");
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_fbinitialize
+ ****************************************************************************/
+
+int up_fbinitialize(int display)
+{
+  FAR struct goldfish_fb_s *fb;
+  uint32_t fmt;
+  int ret = OK;
+
+  const struct goldfish_fb_format_s format_map[] =
+  {
+    [GOLDFISH_FB_FORMAT_BRGA_8888] =
+    {FB_FMT_RGBA32, 32},
+    [GOLDFISH_FB_FORMAT_RGBX_8888] =
+    {FB_FMT_RGB32, 32},
+    [GOLDFISH_FB_FORMAT_RGB_888] =
+    {FB_FMT_RGB24, 24},
+    [GOLDFISH_FB_FORMAT_RGB_565] =
+    {FB_FMT_RGB16_565, 16},
+    [GOLDFISH_FB_FORMAT_BGRA_8888] =
+    {FB_FMT_RGBA32, 32},
+    [GOLDFISH_FB_FORMAT_RGBA_5551] =
+    {FB_FMT_RGB16_555, 16},
+    [GOLDFISH_FB_FORMAT_RGBA_4444] =
+    {FB_FMT_RGBA16, 16},
+  };
+
+  fb = kmm_zalloc(sizeof(*fb));
+  if (fb == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  fb->base = (FAR void *)CONFIG_GOLDFISH_FB_BASE;
+  fb->irq = CONFIG_GOLDFISH_FB_IRQ;
+
+  /* Initialize vsync queue */
+
+  ret = circbuf_init(&fb->vsync, NULL,
+                     CONFIG_GOLDFISH_FB_FRAME_NBUFFER *
+                     sizeof(struct fb_planeinfo_s));
+  if (ret < 0)
+    {
+      goto err_circbuf_alloc_failed;
+    }
+
+  fmt = getreg32(fb->base + GOLDFISH_FB_GET_FORMAT);
+
+  fb->videoinfo.xres = getreg32(fb->base + GOLDFISH_FB_GET_WIDTH);
+  fb->videoinfo.yres = getreg32(fb->base + GOLDFISH_FB_GET_HEIGHT);
+  fb->videoinfo.nplanes = 1;
+  fb->videoinfo.fmt = format_map[fmt].fmt;
+
+  fb->planeinfo.bpp = format_map[fmt].bpp;
+  fb->planeinfo.stride = fb->videoinfo.xres * (fb->planeinfo.bpp >> 3);
+  fb->planeinfo.yres_virtual = fb->videoinfo.yres *
+                               CONFIG_GOLDFISH_FB_FRAME_NBUFFER;
+  fb->planeinfo.xres_virtual = fb->videoinfo.xres;
+
+  fb->planeinfo.fblen = fb->planeinfo.stride * fb->planeinfo.yres_virtual;
+  fb->planeinfo.fbmem = kmm_zalloc(fb->planeinfo.fblen);
+  if (fb->planeinfo.fbmem == NULL)
+    {
+      gerr("ERROR: Failed to allocate framebuffer memory: %zu KB\n",
+           fb->planeinfo.fblen / 1024);
+      ret = -ENOMEM;
+      goto err_fbmem_alloc_failed;
+    }
+
+  fb->vtable.pandisplay = goldfish_fb_pan_display;
+  fb->vtable.getplaneinfo = goldfish_getplaneinfo;
+  fb->vtable.getvideoinfo = goldfish_getvideoinfo;
+
+  ret = irq_attach(fb->irq, goldfish_fb_interrupt, fb);
+  if (ret < 0)
+    {
+      goto err_irq_attach_failed;
+    }
+
+  up_enable_irq(fb->irq);
+  putreg32(GOLDFISH_FB_INT_VSYNC | GOLDFISH_FB_INT_UPDATE_DONE,
+           fb->base + GOLDFISH_FB_INT_ENABLE);
+
+  /* Updates base */
+
+  putreg32((uintptr_t)fb->planeinfo.fbmem,
+           fb->base + GOLDFISH_FB_SET_BASE);
+
+  g_goldfish_fb = fb;
+  return OK;
+
+err_irq_attach_failed:
+  kmm_free(fb->planeinfo.fbmem);
+err_fbmem_alloc_failed:
+  circbuf_uninit(&fb->vsync);
+err_circbuf_alloc_failed:
+  kmm_free(fb);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: up_fbgetvplane
+ ****************************************************************************/
+
+FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
+{
+  return vplane || display ? NULL : &(g_goldfish_fb->vtable);
+}
+
+/****************************************************************************
+ * Name: up_fbuninitialize
+ ****************************************************************************/
+
+void up_fbuninitialize(int display)
+{
+  if (display == 0)
+    {
+      FAR struct goldfish_fb_s *fb = g_goldfish_fb;
+
+      irq_detach(fb->irq);
+      circbuf_uninit(&fb->vsync);
+      kmm_free(fb->planeinfo.fbmem);
+      kmm_free(fb);
+      g_goldfish_fb = NULL;
+    }
+}

Reply via email to