diff --git a/Kconfig b/Kconfig index ab65204d5c..9944e3244e 100644 --- a/Kconfig +++ b/Kconfig @@ -1190,10 +1190,6 @@ menu "LVGL configuration" bool "Use BSD flavored framebuffer device" depends on LV_USE_LINUX_FBDEV default n - config LV_LINUX_FBDEV_NUTTX - bool "Use NuttX flavored framebuffer device" - depends on LV_USE_LINUX_FBDEV - default n choice prompt "Framebuffer device render mode" @@ -1247,6 +1243,10 @@ menu "LVGL configuration" depends on LV_USE_LINUX_FBDEV && LV_LINUX_FBDEV_CUSTOM_BUFFER default 60 + config LV_USE_NUTTX_FBDEV + bool "Use Nuttx framebuffer device" + default n + config LV_USE_NUTTX_LCD bool "Use NuttX LCD device" default n diff --git a/env_support/cmsis-pack/README.md b/env_support/cmsis-pack/README.md index 5d61ac6cce..5c453d6d73 100644 --- a/env_support/cmsis-pack/README.md +++ b/env_support/cmsis-pack/README.md @@ -168,6 +168,8 @@ Make sure `LV_MEM_SIZE` is no less than `(64*1024U)`. - LV_USE_LINUX_FBDEV + - LV_USE_NUTTX_FBDEV + - LV_USE_LINUX_DRM - LV_USE_TFT_ESPI diff --git a/lv_conf_template.h b/lv_conf_template.h index 67bf8ddca4..f8428c6d4c 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -745,12 +745,13 @@ #define LV_USE_LINUX_FBDEV 0 #if LV_USE_LINUX_FBDEV #define LV_LINUX_FBDEV_BSD 0 - #define LV_LINUX_FBDEV_NUTTX 0 #define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL #define LV_LINUX_FBDEV_BUFFER_COUNT 0 #define LV_LINUX_FBDEV_BUFFER_SIZE 60 #endif +#define LV_USE_NUTTX_FBDEV 0 + /*Driver for /dev/lcd*/ #define LV_USE_NUTTX_LCD 0 #if LV_USE_NUTTX_LCD diff --git a/lvgl.h b/lvgl.h index 3023b5dab9..a3334d7ea1 100644 --- a/lvgl.h +++ b/lvgl.h @@ -118,6 +118,7 @@ extern "C" { #include "src/dev/display/drm/lv_linux_drm.h" #include "src/dev/display/fb/lv_linux_fbdev.h" +#include "src/dev/display/fb/lv_nuttx_fbdev.h" #include "src/dev/display/lcd/lv_nuttx_lcd.h" #include "src/dev/input/touchscreen/lv_nuttx_touchscreen.h" diff --git a/src/dev/display/fb/lv_linux_fbdev.c b/src/dev/display/fb/lv_linux_fbdev.c index 0ba05f7ba4..e3a79a25d2 100644 --- a/src/dev/display/fb/lv_linux_fbdev.c +++ b/src/dev/display/fb/lv_linux_fbdev.c @@ -22,8 +22,6 @@ #include #include #include -#elif LV_LINUX_FBDEV_NUTTX - #include #else #include #endif /* LV_LINUX_FBDEV_BSD */ @@ -130,13 +128,11 @@ void lv_linux_fbdev_set_file(lv_display_t * disp, const char * file) } LV_LOG_INFO("The framebuffer device was opened successfully"); -#if !LV_LINUX_FBDEV_NUTTX /* Make sure that the display is on.*/ if(ioctl(dsc->fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) { perror("ioctl(FBIOBLANK)"); /* Don't return. Some framebuffer drivers like efifb or simplefb don't implement FBIOBLANK.*/ } -#endif /* !LV_LINUX_FBDEV_NUTTX */ #if LV_LINUX_FBDEV_BSD struct fbtype fb; @@ -256,16 +252,6 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * colo } } -#if LV_LINUX_FBDEV_NUTTX && defined(CONFIG_FB_UPDATE) - /*May be some direct update command is required*/ - struct fb_area_s fb_area; - fb_area.x = area->x1; - fb_area.y = area->y1; - fb_area.w = lv_area_get_width(area); - fb_area.h = lv_area_get_height(area); - ioctl(dsc->fbfd, FBIO_UPDATE, (unsigned long)((uintptr_t)&fb_area)); -#endif - lv_display_flush_ready(disp); } diff --git a/src/dev/display/fb/lv_nuttx_fbdev.c b/src/dev/display/fb/lv_nuttx_fbdev.c new file mode 100644 index 0000000000..0444f31915 --- /dev/null +++ b/src/dev/display/fb/lv_nuttx_fbdev.c @@ -0,0 +1,281 @@ +/** + * @file lv_nuttx_fbdev.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_nuttx_fbdev.h" +#if LV_USE_NUTTX_FBDEV + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../lvgl_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + struct fb_videoinfo_s vinfo; + struct fb_planeinfo_s pinfo; + + void * mem; + void * mem2; + uint32_t mem2_yoffset; + int fd; +} lv_nuttx_fb_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p); +static int fbdev_get_pinfo(int fd, struct fb_planeinfo_s * pinfo); +static int fbdev_init_mem2(lv_nuttx_fb_t * dsc); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/**************************************************************************** + * Name: lv_nuttx_fbdev_create + ****************************************************************************/ + +lv_display_t * lv_nuttx_fbdev_create(void) +{ + lv_nuttx_fb_t * dsc = lv_malloc(sizeof(lv_nuttx_fb_t)); + LV_ASSERT_MALLOC(dsc); + if(dsc == NULL) return NULL; + lv_memzero(dsc, sizeof(lv_nuttx_fb_t)); + + lv_display_t * disp = lv_display_create(800, 480); + if(disp == NULL) { + lv_free(dsc); + return NULL; + } + dsc->fd = -1; + lv_display_set_driver_data(disp, dsc); + lv_display_set_flush_cb(disp, flush_cb); + return disp; +} + +/**************************************************************************** + * Name: lv_nuttx_fbdev_set_file + ****************************************************************************/ + +int lv_nuttx_fbdev_set_file(lv_display_t * disp, const char * file) +{ + int ret; + LV_ASSERT(disp && file); + lv_nuttx_fb_t * dsc = lv_display_get_driver_data(disp); + + if(dsc->fd >= 0) close(dsc->fd); + + /* Open the file for reading and writing*/ + dsc->fd = open(file, O_RDWR); + if(dsc->fd < 0) { + LV_LOG_ERROR("Error: cannot open framebuffer device"); + return -errno; + } + LV_LOG_INFO("The framebuffer device was opened successfully"); + + if(ioctl(dsc->fd, FBIOGET_VIDEOINFO, (unsigned long)((uintptr_t)&dsc->vinfo)) < 0) { + LV_LOG_ERROR("ioctl(FBIOGET_VIDEOINFO) failed: %d", errno); + ret = -errno; + goto errout; + } + + LV_LOG_INFO("VideoInfo:"); + LV_LOG_INFO(" fmt: %u", dsc->vinfo.fmt); + LV_LOG_INFO(" xres: %u", dsc->vinfo.xres); + LV_LOG_INFO(" yres: %u", dsc->vinfo.yres); + LV_LOG_INFO(" nplanes: %u", dsc->vinfo.nplanes); + + if((ret = fbdev_get_pinfo(dsc->fd, &dsc->pinfo)) < 0) { + 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); + ret = -errno; + goto errout; + } + + /* double buffer mode */ + if(dsc->pinfo.yres_virtual == (dsc->vinfo.yres * 2)) { + if((ret = fbdev_init_mem2(dsc)) < 0) { + goto errout; + } + } + + lv_display_set_draw_buffers(disp, dsc->mem, dsc->mem2, + (dsc->pinfo.stride * dsc->vinfo.yres), LV_DISP_RENDER_MODE_DIRECT); + lv_display_set_resolution(disp, dsc->vinfo.xres, dsc->vinfo.yres); + + LV_LOG_INFO("Resolution is set to %dx%d at %ddpi", dsc->vinfo.xres, dsc->vinfo.yres, lv_display_get_dpi(disp)); + return 0; + +errout: + close(dsc->fd); + dsc->fd = -1; + return ret; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p) +{ + lv_nuttx_fb_t * dsc = lv_display_get_driver_data(disp); + + if(dsc->mem == NULL || + area->x2 < 0 || area->y2 < 0 || + area->x1 > (int32_t)dsc->vinfo.xres - 1 || area->y1 > (int32_t)dsc->vinfo.yres - 1) { + lv_display_flush_ready(disp); + return; + } + +#if defined(CONFIG_FB_UPDATE) + /*May be some direct update command is required*/ + struct fb_area_s fb_area; + fb_area.x = area->x1; + fb_area.y = area->y1; + fb_area.w = lv_area_get_width(area); + fb_area.h = lv_area_get_height(area); + if(ioctl(dsc->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)&fb_area)) < 0) { + LV_LOG_ERROR("ioctl(FBIO_UPDATE) failed: %d", errno); + } +#endif + + /* double framebuffer */ + if(dsc->mem2 != NULL) { + if(disp->buf_act == disp->buf_1) { + dsc->pinfo.yoffset = 0; + } + else { + dsc->pinfo.yoffset = dsc->mem2_yoffset; + } + + if(ioctl(dsc->fd, FBIOPAN_DISPLAY, (unsigned long)((uintptr_t) & (dsc->pinfo))) < 0) { + LV_LOG_ERROR("ioctl(FBIOPAN_DISPLAY) failed: %d", errno); + } + } + lv_display_flush_ready(disp); +} + + +/**************************************************************************** + * Name: fbdev_get_pinfo + ****************************************************************************/ + +static int fbdev_get_pinfo(int fd, FAR struct fb_planeinfo_s * pinfo) +{ + if(ioctl(fd, FBIOGET_PLANEINFO, (unsigned long)((uintptr_t)pinfo)) < 0) { + LV_LOG_ERROR("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d", errno); + return -errno; + } + + LV_LOG_INFO("PlaneInfo (plane %d):", pinfo->display); + LV_LOG_INFO(" mem: %p", pinfo->mem); + LV_LOG_INFO(" fblen: %zu", pinfo->fblen); + LV_LOG_INFO(" stride: %u", pinfo->stride); + LV_LOG_INFO(" display: %u", pinfo->display); + LV_LOG_INFO(" bpp: %u", pinfo->bpp); + + /* Only these pixel depths are supported. viinfo.fmt is ignored, only + * certain color formats are supported. + */ + + if(pinfo->bpp != 32 && pinfo->bpp != 16 && + pinfo->bpp != 8 && pinfo->bpp != 1) { + LV_LOG_ERROR("bpp = %u not supported", pinfo->bpp); + return -EINVAL; + } + + return 0; +} + +/**************************************************************************** + * Name: fbdev_init_mem2 + ****************************************************************************/ + +static int fbdev_init_mem2(lv_nuttx_fb_t * dsc) +{ + uintptr_t buf_offset; + struct fb_planeinfo_s pinfo; + int ret; + + memset(&pinfo, 0, sizeof(pinfo)); + + /* Get display[1] planeinfo */ + + pinfo.display = dsc->pinfo.display + 1; + + if((ret = fbdev_get_pinfo(dsc->fd, &pinfo)) < 0) { + return ret; + } + + /* Check bpp */ + + if(pinfo.bpp != dsc->pinfo.bpp) { + LV_LOG_WARN("mem2 is incorrect"); + 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_INFO("Use consecutive mem2 = %p, yoffset = %" PRIu32, + dsc->mem2, dsc->mem2_yoffset); + } + else { + dsc->mem2_yoffset = buf_offset / dsc->pinfo.stride; + dsc->mem2 = pinfo.fbmem; + LV_LOG_INFO("Use non-consecutive mem2 = %p, yoffset = %" PRIu32, + dsc->mem2, dsc->mem2_yoffset); + } + + return 0; +} + +#endif /*LV_USE_NUTTX_FBDEV*/ diff --git a/src/dev/display/fb/lv_nuttx_fbdev.h b/src/dev/display/fb/lv_nuttx_fbdev.h new file mode 100644 index 0000000000..873552977b --- /dev/null +++ b/src/dev/display/fb/lv_nuttx_fbdev.h @@ -0,0 +1,46 @@ +/** + * @file lv_nuttx_fbdev_h + * + */ + +#ifndef LV_NUTTX_FBDEV_H +#define LV_NUTTX_FBDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../../../display/lv_display.h" + +#if LV_USE_NUTTX_FBDEV + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +lv_display_t * lv_nuttx_fbdev_create(void); + +int lv_nuttx_fbdev_set_file(lv_display_t * disp, const char * file); + +/********************** + * MACROS + **********************/ + +#endif /* LV_USE_NUTTX_FBDEV */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_NUTTX_FBDEV_H */ diff --git a/src/dev/input/touchscreen/lv_nuttx_touchscreen.h b/src/dev/input/touchscreen/lv_nuttx_touchscreen.h index 0fc896e926..5f4e4c82ca 100644 --- a/src/dev/input/touchscreen/lv_nuttx_touchscreen.h +++ b/src/dev/input/touchscreen/lv_nuttx_touchscreen.h @@ -40,7 +40,7 @@ lv_indev_t * lv_nuttx_touchscreen_create(const char * dev_path); * MACROS **********************/ -#endif /* LV_USE_LINUX_FBDEV */ +#endif /* LV_USE_NUTTX_TOUCHSCREEN */ #ifdef __cplusplus } /* extern "C" */ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 6b161320c6..bb51b44960 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -2435,13 +2435,6 @@ #define LV_LINUX_FBDEV_BSD 0 #endif #endif - #ifndef LV_LINUX_FBDEV_NUTTX - #ifdef CONFIG_LV_LINUX_FBDEV_NUTTX - #define LV_LINUX_FBDEV_NUTTX CONFIG_LV_LINUX_FBDEV_NUTTX - #else - #define LV_LINUX_FBDEV_NUTTX 0 - #endif - #endif #ifndef LV_LINUX_FBDEV_RENDER_MODE #ifdef CONFIG_LV_LINUX_FBDEV_RENDER_MODE #define LV_LINUX_FBDEV_RENDER_MODE CONFIG_LV_LINUX_FBDEV_RENDER_MODE @@ -2465,6 +2458,14 @@ #endif #endif +#ifndef LV_USE_NUTTX_FBDEV + #ifdef CONFIG_LV_USE_NUTTX_FBDEV + #define LV_USE_NUTTX_FBDEV CONFIG_LV_USE_NUTTX_FBDEV + #else + #define LV_USE_NUTTX_FBDEV 0 + #endif +#endif + /*Driver for /dev/lcd*/ #ifndef LV_USE_NUTTX_LCD #ifdef CONFIG_LV_USE_NUTTX_LCD