11/*
22 * Copyright (c) 2018-2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
3+ * Copyright (c) 2025 Abderrahmane JARMOUNI
34 *
45 * SPDX-License-Identifier: Apache-2.0
56 */
2122#include <zephyr/logging/log.h>
2223LOG_MODULE_REGISTER (lvgl , CONFIG_LV_Z_LOG_LEVEL );
2324
24- static lv_display_t * display ;
25- struct lvgl_disp_data disp_data = {
25+ static lv_display_t * lv_displays [ DT_ZEPHYR_DISPLAYS_COUNT ] ;
26+ struct lvgl_disp_data disp_data [ DT_ZEPHYR_DISPLAYS_COUNT ] = { {
2627 .blanking_on = false,
27- };
28+ }};
29+
30+ #if DT_HAS_COMPAT_STATUS_OKAY (zephyr_displays )
31+ #define DISPLAY_NODE (n ) DT_ZEPHYR_DISPLAY(n)
32+ #elif DT_HAS_CHOSEN (zephyr_display )
33+ #define DISPLAY_NODE (n ) DT_CHOSEN(zephyr_display)
34+ #else
35+ #error Could not find "zephyr,display" chosen property, or a "zephyr,displays" compatible node in DT
36+ #define DISPLAY_NODE (n ) DT_INVALID_NODE
37+ #endif
38+
39+ #define IS_MONOCHROME_DISPLAY \
40+ UTIL_OR(IS_EQ(CONFIG_LV_Z_BITS_PER_PIXEL, 1), IS_EQ(CONFIG_LV_COLOR_DEPTH_1, 1))
2841
29- #define DISPLAY_NODE DT_CHOSEN(zephyr_display)
30- #define IS_MONOCHROME_DISPLAY ((CONFIG_LV_Z_BITS_PER_PIXEL == 1) || (CONFIG_LV_COLOR_DEPTH_1 == 1))
3142#define ALLOC_MONOCHROME_CONV_BUFFER \
32- ((IS_MONOCHROME_DISPLAY == 1) && (CONFIG_LV_Z_MONOCHROME_CONVERSION_BUFFER == 1))
43+ UTIL_AND(IS_EQ(IS_MONOCHROME_DISPLAY, 1), \
44+ IS_EQ(CONFIG_LV_Z_MONOCHROME_CONVERSION_BUFFER, 1))
3345
3446#ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC
3547
36- #define DISPLAY_WIDTH DT_PROP(DISPLAY_NODE, width)
37- #define DISPLAY_HEIGHT DT_PROP(DISPLAY_NODE, height)
48+ #define DISPLAY_WIDTH ( n ) DT_PROP(DISPLAY_NODE(n) , width)
49+ #define DISPLAY_HEIGHT ( n ) DT_PROP(DISPLAY_NODE(n) , height)
3850
3951#if IS_MONOCHROME_DISPLAY
4052/* monochrome buffers are expected to have 8 preceding bytes for the color palette */
41- #define BUFFER_SIZE \
42- (((CONFIG_LV_Z_VDB_SIZE * ROUND_UP(DISPLAY_WIDTH, 8) * ROUND_UP(DISPLAY_HEIGHT, 8)) / \
53+ #define BUFFER_SIZE (n ) \
54+ (((CONFIG_LV_Z_VDB_SIZE * ROUND_UP(DISPLAY_WIDTH(n), 8) * \
55+ ROUND_UP(DISPLAY_HEIGHT(n), 8)) / \
4356 100) / 8 + \
4457 8)
4558#else
46- #define BUFFER_SIZE \
59+ #define BUFFER_SIZE ( n ) \
4760 (CONFIG_LV_Z_BITS_PER_PIXEL * \
48- ((CONFIG_LV_Z_VDB_SIZE * DISPLAY_WIDTH * DISPLAY_HEIGHT) / 100) / 8)
61+ ((CONFIG_LV_Z_VDB_SIZE * DISPLAY_WIDTH(n) * DISPLAY_HEIGHT(n) ) / 100) / 8)
4962#endif /* IS_MONOCHROME_DISPLAY */
5063
51- /* NOTE: depending on chosen color depth buffer may be accessed using uint8_t *,
52- * uint16_t * or uint32_t *, therefore buffer needs to be aligned accordingly to
53- * prevent unaligned memory accesses.
54- */
55- static uint8_t buf0 [BUFFER_SIZE ]
56- #ifdef CONFIG_LV_Z_VDB_CUSTOM_SECTION
57- Z_GENERIC_SECTION (.lvgl_buf )
58- #endif
59- __aligned (CONFIG_LV_Z_VDB_ALIGN );
64+ static uint32_t disp_buf_size [DT_ZEPHYR_DISPLAYS_COUNT ] = {0 };
65+ static uint8_t * buf0_p [DT_ZEPHYR_DISPLAYS_COUNT ] = {NULL };
6066
6167#ifdef CONFIG_LV_Z_DOUBLE_VDB
62- static uint8_t buf1 [BUFFER_SIZE ]
63- #ifdef CONFIG_LV_Z_VDB_CUSTOM_SECTION
64- Z_GENERIC_SECTION (.lvgl_buf )
68+ static uint8_t * buf1_p [DT_ZEPHYR_DISPLAYS_COUNT ] = {NULL };
6569#endif
66- __aligned (CONFIG_LV_Z_VDB_ALIGN );
67- #endif /* CONFIG_LV_Z_DOUBLE_VDB */
6870
6971#if ALLOC_MONOCHROME_CONV_BUFFER
70- static uint8_t mono_vtile_buf [BUFFER_SIZE ]
71- #ifdef CONFIG_LV_Z_VDB_CUSTOM_SECTION
72- Z_GENERIC_SECTION (.lvgl_buf )
72+ static uint8_t * mono_vtile_buf_p [DT_ZEPHYR_DISPLAYS_COUNT ] = {NULL };
7373#endif
74- __aligned (CONFIG_LV_Z_VDB_ALIGN );
75- #endif /* ALLOC_MONOCHROME_CONV_BUFFER */
74+
75+ /* NOTE: depending on chosen color depth, buffers may be accessed using uint8_t *,*/
76+ /* uint16_t * or uint32_t *, therefore buffer needs to be aligned accordingly to */
77+ /* prevent unaligned memory accesses. */
78+
79+ /* clang-format off */
80+ #define LV_BUFFERS_DEFINE (n ) \
81+ static uint8_t buf0_##n[BUFFER_SIZE(n)] \
82+ IF_ENABLED(CONFIG_LV_Z_VDB_CUSTOM_SECTION, (Z_GENERIC_SECTION(.lvgl_buf))) \
83+ __aligned(CONFIG_LV_Z_VDB_ALIGN); \
84+ \
85+ IF_ENABLED(CONFIG_LV_Z_DOUBLE_VDB, ( \
86+ static uint8_t buf1_##n[BUFFER_SIZE(n)] \
87+ IF_ENABLED(CONFIG_LV_Z_VDB_CUSTOM_SECTION, (Z_GENERIC_SECTION(.lvgl_buf))) \
88+ __aligned(CONFIG_LV_Z_VDB_ALIGN); \
89+ )) \
90+ \
91+ IF_ENABLED(ALLOC_MONOCHROME_CONV_BUFFER, ( \
92+ static uint8_t mono_vtile_buf_##n[BUFFER_SIZE(n)] \
93+ IF_ENABLED(CONFIG_LV_Z_VDB_CUSTOM_SECTION, (Z_GENERIC_SECTION(.lvgl_buf))) \
94+ __aligned(CONFIG_LV_Z_VDB_ALIGN); \
95+ ))
96+
97+ FOR_EACH (LV_BUFFERS_DEFINE , ( ), LV_DISPLAYS_IDX_LIST );
98+
99+ #define LV_BUFFERS_REFERENCES (n ) \
100+ disp_buf_size[n] = (uint32_t)BUFFER_SIZE(n); \
101+ buf0_p[n] = buf0_##n; \
102+ IF_ENABLED(CONFIG_LV_Z_DOUBLE_VDB, (buf1_p[n] = buf1_##n;)) \
103+ IF_ENABLED(ALLOC_MONOCHROME_CONV_BUFFER, (mono_vtile_buf_p[n] = mono_vtile_buf_##n;))
104+ /* clang-format on */
76105
77106#endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */
78107
@@ -101,21 +130,19 @@ static void lvgl_log(lv_log_level_t level, const char *buf)
101130
102131#ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC
103132
104- static int lvgl_allocate_rendering_buffers (lv_display_t * display )
133+ static void lvgl_allocate_rendering_buffers_static (lv_display_t * display , int disp_idx )
105134{
106- int err = 0 ;
107-
108135#ifdef CONFIG_LV_Z_DOUBLE_VDB
109- lv_display_set_buffers (display , & buf0 , & buf1 , BUFFER_SIZE , LV_DISPLAY_RENDER_MODE_PARTIAL );
136+ lv_display_set_buffers (display , buf0_p [disp_idx ], buf1_p [disp_idx ], disp_buf_size [disp_idx ],
137+ LV_DISPLAY_RENDER_MODE_PARTIAL );
110138#else
111- lv_display_set_buffers (display , & buf0 , NULL , BUFFER_SIZE , LV_DISPLAY_RENDER_MODE_PARTIAL );
112- #endif /* CONFIG_LV_Z_DOUBLE_VDB */
139+ lv_display_set_buffers (display , buf0_p [disp_idx ], NULL , disp_buf_size [disp_idx ],
140+ LV_DISPLAY_RENDER_MODE_PARTIAL );
141+ #endif /* CONFIG_LV_Z_DOUBLE_VDB */
113142
114143#if ALLOC_MONOCHROME_CONV_BUFFER
115- lvgl_set_mono_conversion_buffer (mono_vtile_buf , BUFFER_SIZE );
116- #endif /* ALLOC_MONOCHROME_CONV_BUFFER */
117-
118- return err ;
144+ lvgl_set_mono_conversion_buffer (mono_vtile_buf_p [disp_idx ], disp_buf_size [disp_idx ]);
145+ #endif
119146}
120147
121148#else
@@ -224,15 +251,22 @@ lv_result_t lv_mem_test_core(void)
224251 return LV_RESULT_OK ;
225252}
226253
254+ #define ENUMERATE_DISPLAY_DEVS (n ) display_dev[n] = DEVICE_DT_GET(DISPLAY_NODE(n));
255+
227256int lvgl_init (void )
228257{
229- const struct device * display_dev = DEVICE_DT_GET (DISPLAY_NODE );
230-
231- int err = 0 ;
232-
233- if (!device_is_ready (display_dev )) {
234- LOG_ERR ("Display device not ready." );
235- return - ENODEV ;
258+ const struct device * display_dev [DT_ZEPHYR_DISPLAYS_COUNT ];
259+ struct lvgl_disp_data * p_disp_data ;
260+ int err ;
261+
262+ /* clang-format off */
263+ FOR_EACH (ENUMERATE_DISPLAY_DEVS , ( ), LV_DISPLAYS_IDX_LIST );
264+ /* clang-format on */
265+ for (int i = 0 ; i < DT_ZEPHYR_DISPLAYS_COUNT ; i ++ ) {
266+ if (!device_is_ready (display_dev [i ])) {
267+ LOG_ERR ("Display device %d is not ready" , i );
268+ return - ENODEV ;
269+ }
236270 }
237271
238272#if CONFIG_LV_Z_LOG_LEVEL != 0
@@ -246,28 +280,43 @@ int lvgl_init(void)
246280 lvgl_fs_init ();
247281#endif
248282
249- disp_data .display_dev = display_dev ;
250- display_get_capabilities (display_dev , & disp_data .cap );
283+ #ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC
284+ /* clang-format off */
285+ FOR_EACH (LV_BUFFERS_REFERENCES , ( ), LV_DISPLAYS_IDX_LIST );
286+ /* clang-format on */
287+ #endif
251288
252- display = lv_display_create (disp_data .cap .x_resolution , disp_data .cap .y_resolution );
253- if (!display ) {
254- return - ENOMEM ;
255- }
256- lv_display_set_user_data (display , & disp_data );
289+ for (int i = 0 ; i < DT_ZEPHYR_DISPLAYS_COUNT ; i ++ ) {
290+ p_disp_data = & disp_data [i ];
291+ p_disp_data -> display_dev = display_dev [i ];
292+ display_get_capabilities (display_dev [i ], & p_disp_data -> cap );
257293
258- if (set_lvgl_rendering_cb (display ) != 0 ) {
259- LOG_ERR ("Display not supported." );
260- return - ENOTSUP ;
261- }
294+ lv_displays [i ] = lv_display_create (p_disp_data -> cap .x_resolution ,
295+ p_disp_data -> cap .y_resolution );
296+ if (!lv_displays [i ]) {
297+ LOG_ERR ("Failed to create display %d LV object." , i );
298+ return - ENOMEM ;
299+ }
262300
263- err = lvgl_allocate_rendering_buffers (display );
264- if (err != 0 ) {
265- return err ;
266- }
301+ lv_display_set_user_data (lv_displays [i ], p_disp_data );
302+ if (set_lvgl_rendering_cb (lv_displays [i ]) != 0 ) {
303+ LOG_ERR ("Display %d not supported." , i );
304+ return - ENOTSUP ;
305+ }
306+
307+ #ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC
308+ lvgl_allocate_rendering_buffers_static (lv_displays [i ], i );
309+ #else
310+ err = lvgl_allocate_rendering_buffers (lv_displays [i ]);
311+ if (err < 0 ) {
312+ return err ;
313+ }
314+ #endif
267315
268316#ifdef CONFIG_LV_Z_FULL_REFRESH
269- lv_display_set_render_mode (display , LV_DISPLAY_RENDER_MODE_FULL );
317+ lv_display_set_render_mode (lv_displays [ i ] , LV_DISPLAY_RENDER_MODE_FULL );
270318#endif
319+ }
271320
272321 err = lvgl_init_input_devices ();
273322 if (err < 0 ) {
0 commit comments