This is an automated email from the ASF dual-hosted git repository.

xiaoxiang 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 27e587b179 arch/esp32s3: fb add pandisplay
27e587b179 is described below

commit 27e587b1799bc0a0703bdcc81b44c6ed7fd3275c
Author: liamHowatt <[email protected]>
AuthorDate: Tue Nov 19 04:17:47 2024 +0000

    arch/esp32s3: fb add pandisplay
    
    Signed-off-by: liamHowatt <[email protected]>
---
 arch/xtensa/src/esp32s3/Kconfig       |   7 ++
 arch/xtensa/src/esp32s3/esp32s3_lcd.c | 137 ++++++++++++++++++++++++++++++++--
 drivers/video/fb.c                    |   6 +-
 3 files changed, 141 insertions(+), 9 deletions(-)

diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index 44b7913436..009f31e93b 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -2534,6 +2534,13 @@ config ESP32S3_LCD_BUFFER_LAYERS
        int "LCD Buffer Layer Number"
        default 1
 
+config ESP32S3_LCD_DOUBLE_BUFFERED
+       bool "LCD Double Buffered"
+       default y
+       ---help---
+               Double the framebuffer size per layer.
+               Twice as much memory will be allocated.
+
 choice
        prompt "LCD Data Width"
        default ESP32S3_LCD_DATA_16BIT
diff --git a/arch/xtensa/src/esp32s3/esp32s3_lcd.c 
b/arch/xtensa/src/esp32s3/esp32s3_lcd.c
index b0009e4ec7..d36ea55df6 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_lcd.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_lcd.c
@@ -135,6 +135,18 @@
                                    CONFIG_ESP32S3_LCD_VRES * \
                                    ESP32S3_LCD_DATA_WIDTH)
 
+#ifdef CONFIG_ESP32S3_LCD_DOUBLE_BUFFERED
+#  define ESP32S3_LCD_FB_MULT     2
+#else
+#  define ESP32S3_LCD_FB_MULT     1
+#endif
+
+#define ESP32S3_LCD_HRES_VIRTUAL  CONFIG_ESP32S3_LCD_HRES
+#define ESP32S3_LCD_VRES_VIRTUAL  (CONFIG_ESP32S3_LCD_VRES * \
+                                   ESP32S3_LCD_FB_MULT)
+
+#define ESP32S3_LCD_FB_MEM_SIZE   (ESP32S3_LCD_FB_SIZE * ESP32S3_LCD_FB_MULT)
+
 #define ESP32S3_LCD_DMADESC_NUM   (ESP32S3_LCD_FB_SIZE / \
                                    ESP32S3_DMA_BUFLEN_MAX + 1)
 
@@ -188,6 +200,8 @@ struct esp32s3_lcd_s
 
   uint8_t cur_layer;              /* Current layer number */
 
+  uint32_t yoffset;               /* The current pan offset */
+
   int cpuint;                     /* CPU interrupt assigned to this LCD */
   uint8_t cpu;                    /* CPU ID */
   int32_t dma_channel;            /* DMA channel */
@@ -244,6 +258,11 @@ static int esp32s3_lcd_base_updatearea(struct fb_vtable_s 
*vtable,
                                        const struct fb_area_s *area);
 #endif
 
+#ifdef CONFIG_ESP32S3_LCD_DOUBLE_BUFFERED
+static int esp32s3_lcd_base_pandisplay(struct fb_vtable_s *vtable,
+                                       struct fb_planeinfo_s *pinfo);
+#endif
+
 /* Initialization ***********************************************************/
 
 static int esp32s3_lcd_dmasetup(void);
@@ -300,13 +319,16 @@ static const struct fb_videoinfo_s g_base_videoinfo =
 
 /* This structure provides the base layer interface */
 
-static const struct fb_vtable_s g_base_vtable =
+static struct fb_vtable_s g_base_vtable =
 {
   .getvideoinfo  = esp32s3_lcd_base_getvideoinfo,
   .getplaneinfo  = esp32s3_lcd_base_getplaneinfo,
 #ifdef CONFIG_FB_UPDATE
   .updatearea    = esp32s3_lcd_base_updatearea,
 #endif
+#ifdef CONFIG_ESP32S3_LCD_DOUBLE_BUFFERED
+  .pandisplay    = esp32s3_lcd_base_pandisplay,
+#endif
 };
 
 /****************************************************************************
@@ -515,9 +537,11 @@ static int esp32s3_lcd_base_getplaneinfo(struct 
fb_vtable_s *vtable,
 
       pinfo->display = 0;
       pinfo->fbmem   = (void *)layer->framebuffer;
-      pinfo->fblen   = ESP32S3_LCD_FB_SIZE;
+      pinfo->fblen   = ESP32S3_LCD_FB_MEM_SIZE;
       pinfo->stride  = ESP32S3_LCD_STRIDE;
       pinfo->bpp     = ESP32S3_LCD_DATA_BPP;
+      pinfo->xres_virtual = ESP32S3_LCD_HRES_VIRTUAL;
+      pinfo->yres_virtual = ESP32S3_LCD_VRES_VIRTUAL;
       return OK;
     }
 
@@ -546,9 +570,69 @@ static int esp32s3_lcd_base_updatearea(struct fb_vtable_s 
*vtable,
                                        const struct fb_area_s *area)
 {
   struct esp32s3_lcd_s *priv = &g_lcd_priv;
+  uint8_t *first_pixel;
+  uint32_t size;
 
-  cache_writeback_addr(CURRENT_LAYER(priv)->framebuffer,
-                       ESP32S3_LCD_FB_SIZE);
+  if (area->w == 0 || area->h == 0)
+    {
+      return 0;
+    }
+
+  if (area->x > UINT16_MAX - area->w ||
+      area->y > UINT16_MAX - area->h ||
+      area->x + area->w > ESP32S3_LCD_HRES_VIRTUAL ||
+      area->y + area->h > ESP32S3_LCD_VRES_VIRTUAL)
+    {
+      gerr("ERROR: updatearea area is out of bounds. "
+           "x: %" PRIu16 ", y: %" PRIu16 ", w: %" PRIu16 ", h: %" PRIu16 ", "
+           "virtual hres: %d, virtual vres: %d\n",
+           area->x, area->y, area->w, area->h,
+           ESP32S3_LCD_HRES_VIRTUAL, ESP32S3_LCD_VRES_VIRTUAL);
+      return -EINVAL;
+    }
+
+  first_pixel = CURRENT_LAYER(priv)->framebuffer +
+                (area->y * ESP32S3_LCD_STRIDE +
+                 area->x * ESP32S3_LCD_DATA_WIDTH);
+
+  size = (area->h - 1) * ESP32S3_LCD_STRIDE +
+         area->w       * ESP32S3_LCD_DATA_WIDTH;
+
+  cache_writeback_addr(first_pixel, size);
+
+  return 0;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_lcd_base_pandisplay
+ *
+ * Description:
+ *   Validate the pan info. The pan info is queued by the framebuffer
+ *   subsystem.
+ *
+ * Input Parameters:
+ *   vtable - The framebuffer driver object
+ *   pinfo  - the planeinfo object
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_LCD_DOUBLE_BUFFERED
+static int esp32s3_lcd_base_pandisplay(struct fb_vtable_s *vtable,
+                                       struct fb_planeinfo_s *pinfo)
+{
+  if (pinfo->yoffset > ESP32S3_LCD_VRES_VIRTUAL - CONFIG_ESP32S3_LCD_VRES)
+    {
+      gerr("ERROR: pandisplay yoffset out of bounds: %" PRIu32 ". "
+           "The maximum is: %d\n",
+           pinfo->yoffset,
+           ESP32S3_LCD_VRES_VIRTUAL - CONFIG_ESP32S3_LCD_VRES);
+      return -EINVAL;
+    }
 
   return 0;
 }
@@ -575,6 +659,9 @@ static int IRAM_ATTR lcd_interrupt(int irq, void *context, 
void *arg)
   uint32_t regval;
   struct esp32s3_lcd_s *priv = &g_lcd_priv;
   uint32_t status = esp32s3_lcd_getreg(LCD_CAM_LC_DMA_INT_ST_REG);
+  int paninfo_count;
+  union fb_paninfo_u info;
+  struct esp32s3_layer_s *layer;
 
   esp32s3_lcd_putreg(LCD_CAM_LC_DMA_INT_CLR_REG, status);
   if (status & LCD_CAM_LCD_VSYNC_INT_ST_M)
@@ -603,10 +690,44 @@ static int IRAM_ATTR lcd_interrupt(int irq, void 
*context, void *arg)
                        true);
 #endif
 
+#ifdef CONFIG_ESP32S3_LCD_DOUBLE_BUFFERED
+      /* Pan the display to a new buffer offset if one was queued */
+
+      paninfo_count = fb_paninfo_count(&g_base_vtable, FB_NO_OVERLAY);
+      if (paninfo_count > 1)
+        {
+          fb_remove_paninfo(&g_base_vtable, FB_NO_OVERLAY);
+        }
+
+      if (paninfo_count > 0 &&
+          fb_peek_paninfo(&g_base_vtable, &info, FB_NO_OVERLAY) == OK &&
+          priv->yoffset != info.planeinfo.yoffset)
+        {
+          priv->yoffset = info.planeinfo.yoffset;
+          layer = CURRENT_LAYER(priv);
+
+          esp32s3_dma_setup(layer->dmadesc,
+                            ESP32S3_LCD_DMADESC_NUM,
+                            &layer->framebuffer[priv->yoffset *
+                                                ESP32S3_LCD_STRIDE],
+                            ESP32S3_LCD_FB_SIZE,
+                            true,
+                            priv->dma_channel);
+
+          /* Leave this paninfo in the panbuffer so the buffer will be full
+           * after the user adds another. poll will report unreadyness to
+           * write until it's taken by the next cycle here.
+           */
+        }
+#endif
+
 #ifndef CONFIG_FB_UPDATE
       /* Write framebuffer data from D-cache to PSRAM */
 
-      cache_writeback_addr(CURRENT_LAYER(priv)->framebuffer,
+      layer = CURRENT_LAYER(priv);
+
+      cache_writeback_addr(&layer->framebuffer[priv->yoffset *
+                                               ESP32S3_LCD_STRIDE],
                            ESP32S3_LCD_FB_SIZE);
 #endif
 
@@ -662,9 +783,9 @@ static int esp32s3_lcd_dmasetup(void)
     {
       struct esp32s3_layer_s *layer = &priv->layer[i];
 
-      layer->framebuffer = memalign(64, ESP32S3_LCD_FB_SIZE);
+      layer->framebuffer = memalign(64, ESP32S3_LCD_FB_MEM_SIZE);
       DEBUGASSERT(layer->framebuffer != NULL);
-      memset(layer->framebuffer, 0, ESP32S3_LCD_FB_SIZE);
+      memset(layer->framebuffer, 0, ESP32S3_LCD_FB_MEM_SIZE);
 
       esp32s3_dma_setup(layer->dmadesc,
                         ESP32S3_LCD_DMADESC_NUM,
@@ -1013,7 +1134,7 @@ struct fb_vtable_s *up_fbgetvplane(int display, int 
vplane)
   lcdinfo("vplane: %d\n", vplane);
   if (vplane == 0)
     {
-      return (struct fb_vtable_s *)&g_base_vtable;
+      return &g_base_vtable;
     }
   else
     {
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index 49ccdae76b..4b0f575712 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -987,7 +987,11 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
 
           if (fb->vtable->pandisplay != NULL)
             {
-              fb->vtable->pandisplay(fb->vtable, pinfo);
+              ret = fb->vtable->pandisplay(fb->vtable, pinfo);
+              if (ret < 0)
+                {
+                  break;
+                }
             }
 
           ret = fb_add_paninfo(fb, &paninfo, FB_NO_OVERLAY);

Reply via email to