Skip to content

Commit

Permalink
arch/esp32s3: fb add pandisplay
Browse files Browse the repository at this point in the history
Signed-off-by: liamHowatt <[email protected]>
  • Loading branch information
liamHowatt committed Nov 18, 2024
1 parent a88652f commit 4bd54f6
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 9 deletions.
7 changes: 7 additions & 0 deletions arch/xtensa/src/esp32s3/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
129 changes: 121 additions & 8 deletions arch/xtensa/src/esp32s3/esp32s3_lcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
};

/****************************************************************************
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -545,10 +569,66 @@ static int esp32s3_lcd_base_getplaneinfo(struct fb_vtable_s *vtable,
static int esp32s3_lcd_base_updatearea(struct fb_vtable_s *vtable,
const struct fb_area_s *area)
{
if (area->w == 0 || area->h == 0)
{
return 0;
}

if (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;
}

struct esp32s3_lcd_s *priv = &g_lcd_priv;

cache_writeback_addr(CURRENT_LAYER(priv)->framebuffer,
ESP32S3_LCD_FB_SIZE);
uint8_t *first_pixel = CURRENT_LAYER(priv)->framebuffer +
(area->y * ESP32S3_LCD_STRIDE +
area->x * ESP32S3_LCD_DATA_WIDTH);

uint32_t 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;
}
Expand All @@ -575,6 +655,8 @@ 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);
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)
Expand Down Expand Up @@ -603,10 +685,41 @@ 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 */

if (fb_paninfo_count(&g_base_vtable, FB_NO_OVERLAY) > 1)
{
fb_remove_paninfo(&g_base_vtable, FB_NO_OVERLAY);
}

if (fb_peek_paninfo(&g_base_vtable, &info, FB_NO_OVERLAY) == OK)
{
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

Expand Down Expand Up @@ -662,9 +775,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,
Expand Down Expand Up @@ -1013,7 +1126,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
{
Expand Down
6 changes: 5 additions & 1 deletion drivers/video/fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 4bd54f6

Please sign in to comment.