Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 43 additions & 50 deletions examples/fb/fb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ static void pan_display(FAR struct fb_state_s *state)
{
struct pollfd pfd;
int ret;

pfd.fd = state->fd;
pfd.events = POLLOUT;

Expand Down Expand Up @@ -193,6 +194,7 @@ static int fbdev_get_pinfo(int fd, FAR struct fb_planeinfo_s *pinfo)
if (ioctl(fd, FBIOGET_PLANEINFO, (unsigned long)((uintptr_t)pinfo)) < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n",
errcode);
return EXIT_FAILURE;
Expand Down Expand Up @@ -226,72 +228,51 @@ static int fbdev_get_pinfo(int fd, FAR struct fb_planeinfo_s *pinfo)

static int fb_init_mem2(FAR struct fb_state_s *state)
{
int ret;
uintptr_t buf_offset;
struct fb_planeinfo_s pinfo;
FAR void *fbmem;
FAR void *mem2;
size_t framesize;
off_t offset;
int ret;

/* Get display[1] planeinfo */

memset(&pinfo, 0, sizeof(pinfo));
pinfo.display = state->pinfo.display + 1;

if ((ret = fbdev_get_pinfo(state->fd, &pinfo)) < 0)
{
return EXIT_FAILURE;
return ret;
}

fbmem = mmap(NULL, pinfo.fblen, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FILE, state->fd, 0);

if (fbmem == MAP_FAILED)
{
int errcode = errno;
fprintf(stderr, "ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n",
errcode);
return EXIT_FAILURE;
}

/* Check bpp */

if (pinfo.bpp != state->pinfo.bpp)
{
fprintf(stderr, "ERROR: fbmem2 is incorrect\n");
fprintf(stderr, "ERROR: fbmem2 bpp mismatch\n");
return -EINVAL;
}

/* Check the buffer address offset,
* It needs to be divisible by pinfo.stride
*/

buf_offset = fbmem - state->fbmem;
/* Use virtual offset = fblen = stride * yres */

if ((buf_offset % state->pinfo.stride) != 0)
{
fprintf(stderr, "ERROR: It is detected that buf_offset(%" PRIuPTR ") "
"and stride(%d) are not divisible, please ensure "
"that the driver handles the address offset by itself.\n",
buf_offset, state->pinfo.stride);
}
framesize = state->vinfo.yres * state->pinfo.stride;
offset = framesize;
state->mem2_yoffset = state->vinfo.yres;

/* Calculate the address and yoffset of fbmem2 */

if (buf_offset == 0)
mem2 = mmap(NULL, framesize,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FILE,
state->fd, offset);
if (mem2 == MAP_FAILED)
{
/* Use consecutive fbmem2. */

state->mem2_yoffset = state->vinfo.yres;
state->fbmem2 = fbmem + state->mem2_yoffset * pinfo.stride;
printf("Use consecutive fbmem2 = %p, yoffset = %" PRIu32"\n",
state->fbmem2, state->mem2_yoffset);
fprintf(stderr, "ERROR: mmap mem2 failed: %d\n", errno);
return -errno;
}
else
{
/* Use non-consecutive fbmem2. */

state->mem2_yoffset = buf_offset / state->pinfo.stride;
state->fbmem2 = fbmem;
printf("Use non-consecutive fbmem2 = %p, yoffset = %" PRIu32"\n",
state->fbmem2, state->mem2_yoffset);
}
state->fbmem2 = mem2;
fprintf(stderr, "Mapped FB mem2: %p, yoffset: %" PRIu32
", gap: %td (%s)\n",
state->fbmem2, state->mem2_yoffset,
(char *)mem2 - ((char *)state->fbmem + framesize),
((char *)mem2 == (char *)state->fbmem + framesize) ?
"consecutive" : "non-consecutive");

return 0;
}
Expand Down Expand Up @@ -505,13 +486,15 @@ static void present_area(FAR struct fb_state_s *state,

int yoffset = state->act_fbmem == state->fbmem ?
0 : state->mem2_yoffset;

update.y += yoffset;

ret = ioctl(state->fd, FBIO_UPDATE,
(unsigned long)((uintptr_t)&update));
if (ret < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: ioctl(FBIO_UPDATE) failed: %d\n",
errcode);
}
Expand Down Expand Up @@ -587,10 +570,12 @@ int main(int argc, FAR char *argv[])

/* Open the framebuffer driver */

memset(&state, 0, sizeof(state));
state.fd = open(fbdev, O_RDWR);
if (state.fd < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: Failed to open %s: %d\n", fbdev, errcode);
return EXIT_FAILURE;
}
Expand All @@ -602,6 +587,7 @@ int main(int argc, FAR char *argv[])
if (ret < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: ioctl(FBIOGET_VIDEOINFO) failed: %d\n",
errcode);
close(state.fd);
Expand All @@ -623,6 +609,7 @@ int main(int argc, FAR char *argv[])
if (ret < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: ioctl(FBIO_SELECT_OVERLAY) failed: %d\n",
errcode);
close(state.fd);
Expand All @@ -637,6 +624,7 @@ int main(int argc, FAR char *argv[])
if (ret < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: ioctl(FBIOGET_OVERLAYINFO) failed: %d\n",
errcode);
close(state.fd);
Expand Down Expand Up @@ -665,6 +653,7 @@ int main(int argc, FAR char *argv[])
if (ret < 0)
{
int errcode = errno;

fprintf(stderr, "ERROR: ioctl(FBIO_SELECT_OVERLAY) failed: %d\n",
errcode);
close(state.fd);
Expand Down Expand Up @@ -693,21 +682,24 @@ int main(int argc, FAR char *argv[])
if (state.fbmem == MAP_FAILED)
{
int errcode = errno;

fprintf(stderr, "ERROR: mmap() failed: %d\n",
errcode);
close(state.fd);
return EXIT_FAILURE;
}

printf("Mapped FB: %p\n", state.fbmem);
printf("Mapped FB mem: %p\n", state.fbmem);

/* double buffer mode */

if (state.pinfo.yres_virtual == (state.vinfo.yres * 2))
{
if ((ret = fb_init_mem2(&state)) < 0)
{
goto out;
munmap(state.fbmem, state.pinfo.fblen);
close(state.fd);
return ret;
}
}

Expand Down Expand Up @@ -774,8 +766,9 @@ int main(int argc, FAR char *argv[])

printf("Test finished\n");
ret = EXIT_SUCCESS;
out:

munmap(state.fbmem, state.pinfo.fblen);
munmap(state.fbmem2, state.pinfo.fblen);
close(state.fd);
return ret;

Expand Down
168 changes: 168 additions & 0 deletions graphics/lvgl/0001-nuttx-fbdev-use-virtual-framebuffer-offset.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
From: jianglianfang <jianglianfang@xiaomi.com>
Date: Sat, 9 May 2026 19:07:22 +0800
Subject: [PATCH] nuttx: fbdev: use virtual framebuffer offset

Minimal backport of e2a03f78735104a582a938281dec7d4fd0f3866b
(Gerrit 7769608, patch set 1) to LVGL v9.2.2.

Map the second frame separately at stride * yres and use yres for
panning instead of deriving a virtual offset from physical addresses.
Unlike the original change, v9.2.2 needs the second mapping introduced
here. Release both mappings on failure, rebinding and display deletion;
keep the existing off-screen mode. Avoid subtracting unrelated mapped
pointers for diagnostics.

Signed-off-by: jianglianfang <jianglianfang@xiaomi.com>
---
diff --git a/src/drivers/nuttx/lv_nuttx_fbdev.c b/src/drivers/nuttx/lv_nuttx_fbdev.c
--- a/src/drivers/nuttx/lv_nuttx_fbdev.c
+++ b/src/drivers/nuttx/lv_nuttx_fbdev.c
@@ -54,6 +54,7 @@
static lv_color_format_t fb_fmt_to_color_format(int fmt);
static int fbdev_get_pinfo(int fd, struct fb_planeinfo_s * pinfo);
static int fbdev_init_mem2(lv_nuttx_fb_t * dsc);
+static void fbdev_release(lv_nuttx_fb_t * dsc);
static void display_refr_timer_cb(lv_timer_t * tmr);
static void display_release_cb(lv_event_t * e);
#if defined(CONFIG_FB_UPDATE)
@@ -96,7 +97,8 @@
LV_ASSERT(disp && file);
lv_nuttx_fb_t * dsc = lv_display_get_driver_data(disp);

- if(dsc->fd >= 0) close(dsc->fd);
+ lv_display_set_draw_buffers(disp, NULL, NULL);
+ fbdev_release(dsc);

/* Open the file for reading and writing*/

@@ -125,14 +127,16 @@

lv_color_format_t color_format = fb_fmt_to_color_format(dsc->vinfo.fmt);
if(color_format == LV_COLOR_FORMAT_UNKNOWN) {
+ ret = -EINVAL;
goto errout;
}

dsc->mem = mmap(NULL, dsc->pinfo.fblen, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FILE, dsc->fd, 0);
if(dsc->mem == MAP_FAILED) {
- LV_LOG_ERROR("ioctl(FBIOGET_PLANEINFO) failed: %d", errno);
+ LV_LOG_ERROR("mmap mem failed: %d", errno);
ret = -errno;
+ dsc->mem = NULL;
goto errout;
}

@@ -176,8 +180,7 @@
return 0;

errout:
- close(dsc->fd);
- dsc->fd = -1;
+ fbdev_release(dsc);
return ret;
}

@@ -328,8 +331,9 @@

static int fbdev_init_mem2(lv_nuttx_fb_t * dsc)
{
- uintptr_t buf_offset;
struct fb_planeinfo_s pinfo;
+ void * mem2;
+ size_t framesize;
int ret;

lv_memzero(&pinfo, sizeof(pinfo));
@@ -349,35 +353,46 @@
return -EINVAL;
}

- /* Check the buffer address offset,
- * It needs to be divisible by pinfo.stride
- */
-
- buf_offset = pinfo.fbmem - dsc->mem;
-
- if((buf_offset % dsc->pinfo.stride) != 0) {
- LV_LOG_WARN("It is detected that buf_offset(%" PRIuPTR ") "
- "and stride(%d) are not divisible, please ensure "
- "that the driver handles the address offset by itself.",
- buf_offset, dsc->pinfo.stride);
- }
-
- /* Calculate the address and yoffset of mem2 */
-
- if(buf_offset == 0) {
- dsc->mem2_yoffset = dsc->vinfo.yres;
- dsc->mem2 = pinfo.fbmem + dsc->mem2_yoffset * pinfo.stride;
- LV_LOG_USER("Use consecutive mem2 = %p, yoffset = %" LV_PRIu32,
- dsc->mem2, dsc->mem2_yoffset);
- }
- else {
- dsc->mem2_yoffset = buf_offset / dsc->pinfo.stride;
- dsc->mem2 = pinfo.fbmem;
- LV_LOG_USER("Use non-consecutive mem2 = %p, yoffset = %" LV_PRIu32,
- dsc->mem2, dsc->mem2_yoffset);
- }
+ /* The second frame follows the first in the virtual framebuffer. */
+ framesize = (size_t)dsc->vinfo.yres * dsc->pinfo.stride;
+ mem2 = mmap(NULL, framesize, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FILE, dsc->fd, framesize);
+ if(mem2 == MAP_FAILED) {
+ int errcode = errno;
+ LV_LOG_ERROR("mmap mem2 failed: %d", errcode);
+ return -errcode;
+ }
+
+ dsc->mem2 = mem2;
+ dsc->mem2_yoffset = dsc->vinfo.yres;
+ LV_LOG_USER("Mapped mem2 = %p, yoffset = %" LV_PRIu32,
+ dsc->mem2, dsc->mem2_yoffset);

return 0;
+}
+
+static void fbdev_release(lv_nuttx_fb_t * dsc)
+{
+ if(dsc->mem2) {
+ munmap(dsc->mem2, (size_t)dsc->vinfo.yres * dsc->pinfo.stride);
+ dsc->mem2 = NULL;
+ }
+ dsc->mem2_yoffset = 0;
+
+ if(dsc->mem) {
+ munmap(dsc->mem, dsc->pinfo.fblen);
+ dsc->mem = NULL;
+ }
+
+ if(dsc->mem_off_screen) {
+ free(dsc->mem_off_screen);
+ dsc->mem_off_screen = NULL;
+ }
+
+ if(dsc->fd >= 0) {
+ close(dsc->fd);
+ dsc->fd = -1;
+ }
}

static void display_release_cb(lv_event_t * e)
@@ -388,16 +403,7 @@
lv_display_set_driver_data(disp, NULL);
lv_display_set_flush_cb(disp, NULL);

- if(dsc->fd >= 0) {
- close(dsc->fd);
- dsc->fd = -1;
- }
-
- if(dsc->mem_off_screen) {
- /* Free the off-screen buffer */
- free(dsc->mem_off_screen);
- dsc->mem_off_screen = NULL;
- }
+ fbdev_release(dsc);

lv_free(dsc);
}
Loading
Loading