From 2f35a81e0d9835896e41bb2ad76ccbad161e6695 Mon Sep 17 00:00:00 2001 From: Martin Stumpf Date: Wed, 16 Oct 2024 16:42:15 +0200 Subject: [PATCH] display: add display_finalize_frame Propagates the `lv_disp_flush_is_last` to the `display` subsystem. Can be used to combine multiple `writes` to a single page-flip. Signed-off-by: Martin Stumpf --- drivers/display/display_dummy.c | 6 ++++++ include/zephyr/drivers/display.h | 30 ++++++++++++++++++++++++++++++ modules/lvgl/Kconfig | 1 + modules/lvgl/lvgl_display.c | 9 +++++++++ modules/lvgl/lvgl_display_mono.c | 4 ++++ 5 files changed, 50 insertions(+) diff --git a/drivers/display/display_dummy.c b/drivers/display/display_dummy.c index 1a11ee2bf36d7ab..8016af9ff519c06 100644 --- a/drivers/display/display_dummy.c +++ b/drivers/display/display_dummy.c @@ -57,6 +57,11 @@ static int dummy_display_write(const struct device *dev, const uint16_t x, return 0; } +static int dummy_display_finalize_frame(const struct device *dev) +{ + return 0; +} + static int dummy_display_blanking_off(const struct device *dev) { return 0; @@ -110,6 +115,7 @@ static const struct display_driver_api dummy_display_api = { .blanking_on = dummy_display_blanking_on, .blanking_off = dummy_display_blanking_off, .write = dummy_display_write, + .finalize_frame = dummy_display_finalize_frame, .set_brightness = dummy_display_set_brightness, .set_contrast = dummy_display_set_contrast, .get_capabilities = dummy_display_get_capabilities, diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index 067d441d4551b4e..f0e074dd2cc5211 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -163,6 +163,13 @@ typedef int (*display_read_api)(const struct device *dev, const uint16_t x, const struct display_buffer_descriptor *desc, void *buf); +/** + * @typedef display_finalize_frame_api + * @brief Callback API to indicate that all writes for the current frame are done + * See display_finalize_frame() for argument description + */ +typedef int (*display_finalize_frame_api)(const struct device *dev); + /** * @typedef display_get_framebuffer_api * @brief Callback API to get framebuffer pointer @@ -222,6 +229,7 @@ __subsystem struct display_driver_api { display_blanking_off_api blanking_off; display_write_api write; display_read_api read; + display_finalize_frame_api finalize_frame; display_get_framebuffer_api get_framebuffer; display_set_brightness_api set_brightness; display_set_contrast_api set_contrast; @@ -279,6 +287,28 @@ static inline int display_read(const struct device *dev, const uint16_t x, return api->read(dev, x, y, desc, buf); } +/** + * @brief Indicates that all writes for the current frame are done + * + * Can be used to present all previous writes simultaneously, for + * double buffered or latched displays. + * + * @param dev Pointer to device structure + * + * @retval 0 on success else negative errno code. + */ +static inline int display_finalize_frame(const struct device *dev) +{ + struct display_driver_api *api = (struct display_driver_api *)dev->api; + + if (api->finalize_frame == NULL) { + return -ENOSYS; + } + + return api->finalize_frame(dev); +} + + /** * @brief Get pointer to framebuffer for direct access * diff --git a/modules/lvgl/Kconfig b/modules/lvgl/Kconfig index 932df9e55d979bf..a31015cc30beb62 100644 --- a/modules/lvgl/Kconfig +++ b/modules/lvgl/Kconfig @@ -102,6 +102,7 @@ config LV_Z_FLUSH_THREAD_STACK_SIZE default 1024 help Stack size for LVGL flush thread, which will call display_write + and display_finalize_frame config LV_Z_FLUSH_THREAD_PRIO int "LVGL flush thread priority" diff --git a/modules/lvgl/lvgl_display.c b/modules/lvgl/lvgl_display.c index 604cd0078d806f9..e52511805bef77d 100644 --- a/modules/lvgl/lvgl_display.c +++ b/modules/lvgl/lvgl_display.c @@ -28,6 +28,10 @@ void lvgl_flush_thread_entry(void *arg1, void *arg2, void *arg3) display_write(data->display_dev, flush.x, flush.y, &flush.desc, flush.buf); + if (lv_disp_flush_is_last(flush.disp_drv)) { + display_finalize_frame(data->display_dev); + } + lv_disp_flush_ready(flush.disp_drv); k_sem_give(&flush_complete); } @@ -134,6 +138,11 @@ void lvgl_flush_display(struct lvgl_display_flush *request) display_write(data->display_dev, request->x, request->y, &request->desc, request->buf); + + if (lv_disp_flush_is_last(request->disp_drv)) { + display_finalize_frame(data->display_dev); + } + lv_disp_flush_ready(request->disp_drv); #endif } diff --git a/modules/lvgl/lvgl_display_mono.c b/modules/lvgl/lvgl_display_mono.c index 07f84b7d19efc7a..b515c586b479407 100644 --- a/modules/lvgl/lvgl_display_mono.c +++ b/modules/lvgl/lvgl_display_mono.c @@ -38,6 +38,10 @@ void lvgl_flush_cb_mono(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color display_write(display_dev, area->x1, area->y1, &desc, (void *)color_p); } + if (is_last) { + display_finalize_frame(display_dev); + } + if (is_epd && is_last && data->blanking_on) { /* * The entire screen has now been rendered. Update the