1 /*
2 * Copyright (c) 2022 Byte-Lab d.o.o. <dev@byte-lab.com>
3 * Copyright 2023 NXP
4 * Copyright (c) 2024 STMicroelectronics
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define DT_DRV_COMPAT st_stm32_ltdc
10
11 #include <string.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <stm32_ll_rcc.h>
15 #include <zephyr/drivers/display.h>
16 #include <zephyr/drivers/gpio.h>
17 #include <zephyr/drivers/pinctrl.h>
18 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
19 #include <zephyr/drivers/clock_control.h>
20 #include <zephyr/drivers/reset.h>
21 #include <zephyr/pm/device.h>
22 #include <zephyr/sys/barrier.h>
23 #include <zephyr/cache.h>
24 #if defined(CONFIG_STM32_LTDC_FB_USE_SHARED_MULTI_HEAP)
25 #include <zephyr/multi_heap/shared_multi_heap.h>
26 #endif
27
28 #include <zephyr/logging/log.h>
29 LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL);
30
31 /* Horizontal synchronization pulse polarity */
32 #define LTDC_HSPOL_ACTIVE_LOW 0x00000000
33 #define LTDC_HSPOL_ACTIVE_HIGH 0x80000000
34
35 /* Vertical synchronization pulse polarity */
36 #define LTDC_VSPOL_ACTIVE_LOW 0x00000000
37 #define LTDC_VSPOL_ACTIVE_HIGH 0x40000000
38
39 /* Data enable pulse polarity */
40 #define LTDC_DEPOL_ACTIVE_LOW 0x00000000
41 #define LTDC_DEPOL_ACTIVE_HIGH 0x20000000
42
43 /* Pixel clock polarity */
44 #define LTDC_PCPOL_ACTIVE_LOW 0x00000000
45 #define LTDC_PCPOL_ACTIVE_HIGH 0x10000000
46
47 #if CONFIG_STM32_LTDC_ARGB8888
48 #define STM32_LTDC_INIT_PIXEL_SIZE 4u
49 #define STM32_LTDC_INIT_PIXEL_FORMAT LTDC_PIXEL_FORMAT_ARGB8888
50 #define DISPLAY_INIT_PIXEL_FORMAT PIXEL_FORMAT_ARGB_8888
51 #elif CONFIG_STM32_LTDC_RGB888
52 #define STM32_LTDC_INIT_PIXEL_SIZE 3u
53 #define STM32_LTDC_INIT_PIXEL_FORMAT LTDC_PIXEL_FORMAT_RGB888
54 #define DISPLAY_INIT_PIXEL_FORMAT PIXEL_FORMAT_RGB_888
55 #elif CONFIG_STM32_LTDC_RGB565
56 #define STM32_LTDC_INIT_PIXEL_SIZE 2u
57 #define STM32_LTDC_INIT_PIXEL_FORMAT LTDC_PIXEL_FORMAT_RGB565
58 #define DISPLAY_INIT_PIXEL_FORMAT PIXEL_FORMAT_RGB_565
59 #else
60 #error "Invalid LTDC pixel format chosen"
61 #endif
62
63 struct display_stm32_ltdc_data {
64 LTDC_HandleTypeDef hltdc;
65 enum display_pixel_format current_pixel_format;
66 uint8_t current_pixel_size;
67 uint8_t *frame_buffer;
68 uint32_t frame_buffer_len;
69 const uint8_t *pend_buf;
70 const uint8_t *front_buf;
71 struct k_sem sem;
72 };
73
74 struct display_stm32_ltdc_config {
75 uint32_t width;
76 uint32_t height;
77 struct gpio_dt_spec disp_on_gpio;
78 struct gpio_dt_spec bl_ctrl_gpio;
79 struct stm32_pclken pclken;
80 const struct reset_dt_spec reset;
81 const struct pinctrl_dev_config *pctrl;
82 void (*irq_config_func)(const struct device *dev);
83 const struct device *display_controller;
84 };
85
stm32_ltdc_global_isr(const struct device * dev)86 static void stm32_ltdc_global_isr(const struct device *dev)
87 {
88 struct display_stm32_ltdc_data *data = dev->data;
89
90 if (__HAL_LTDC_GET_FLAG(&data->hltdc, LTDC_FLAG_LI) &&
91 __HAL_LTDC_GET_IT_SOURCE(&data->hltdc, LTDC_IT_LI)) {
92 if (data->front_buf != data->pend_buf) {
93 data->front_buf = data->pend_buf;
94
95 LTDC_LAYER(&data->hltdc, LTDC_LAYER_1)->CFBAR = (uint32_t)data->front_buf;
96 __HAL_LTDC_RELOAD_CONFIG(&data->hltdc);
97
98 k_sem_give(&data->sem);
99 }
100
101 __HAL_LTDC_CLEAR_FLAG(&data->hltdc, LTDC_FLAG_LI);
102 }
103 }
104
stm32_ltdc_set_pixel_format(const struct device * dev,const enum display_pixel_format format)105 static int stm32_ltdc_set_pixel_format(const struct device *dev,
106 const enum display_pixel_format format)
107 {
108 int err;
109 struct display_stm32_ltdc_data *data = dev->data;
110
111 switch (format) {
112 case PIXEL_FORMAT_RGB_565:
113 err = HAL_LTDC_SetPixelFormat(&data->hltdc, LTDC_PIXEL_FORMAT_RGB565, 0);
114 data->current_pixel_format = PIXEL_FORMAT_RGB_565;
115 data->current_pixel_size = 2u;
116 break;
117 case PIXEL_FORMAT_RGB_888:
118 err = HAL_LTDC_SetPixelFormat(&data->hltdc, LTDC_PIXEL_FORMAT_RGB888, 0);
119 data->current_pixel_format = PIXEL_FORMAT_RGB_888;
120 data->current_pixel_size = 3u;
121 break;
122 case PIXEL_FORMAT_ARGB_8888:
123 err = HAL_LTDC_SetPixelFormat(&data->hltdc, LTDC_PIXEL_FORMAT_ARGB8888, 0);
124 data->current_pixel_format = PIXEL_FORMAT_ARGB_8888;
125 data->current_pixel_size = 4u;
126 default:
127 err = -ENOTSUP;
128 break;
129 }
130
131 return err;
132 }
133
stm32_ltdc_set_orientation(const struct device * dev,const enum display_orientation orientation)134 static int stm32_ltdc_set_orientation(const struct device *dev,
135 const enum display_orientation orientation)
136 {
137 ARG_UNUSED(dev);
138
139 if (orientation == DISPLAY_ORIENTATION_NORMAL) {
140 return 0;
141 }
142
143 return -ENOTSUP;
144 }
145
stm32_ltdc_get_capabilities(const struct device * dev,struct display_capabilities * capabilities)146 static void stm32_ltdc_get_capabilities(const struct device *dev,
147 struct display_capabilities *capabilities)
148 {
149 struct display_stm32_ltdc_data *data = dev->data;
150
151 memset(capabilities, 0, sizeof(struct display_capabilities));
152
153 capabilities->x_resolution = data->hltdc.LayerCfg[0].WindowX1 -
154 data->hltdc.LayerCfg[0].WindowX0;
155 capabilities->y_resolution = data->hltdc.LayerCfg[0].WindowY1 -
156 data->hltdc.LayerCfg[0].WindowY0;
157 capabilities->supported_pixel_formats = PIXEL_FORMAT_ARGB_8888 |
158 PIXEL_FORMAT_RGB_888 |
159 PIXEL_FORMAT_RGB_565;
160 capabilities->screen_info = 0;
161
162 capabilities->current_pixel_format = data->current_pixel_format;
163 capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL;
164 }
165
stm32_ltdc_write(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,const void * buf)166 static int stm32_ltdc_write(const struct device *dev, const uint16_t x,
167 const uint16_t y,
168 const struct display_buffer_descriptor *desc,
169 const void *buf)
170 {
171 const struct display_stm32_ltdc_config *config = dev->config;
172 struct display_stm32_ltdc_data *data = dev->data;
173 uint8_t *dst = NULL;
174 const uint8_t *pend_buf = NULL;
175 const uint8_t *src = buf;
176 uint16_t row;
177
178 if ((x == 0) && (y == 0) &&
179 (desc->width == config->width) &&
180 (desc->height == config->height) &&
181 (desc->pitch == desc->width)) {
182 /* Use buf as ltdc frame buffer directly if it length same as ltdc frame buffer. */
183 pend_buf = buf;
184 } else {
185 if (CONFIG_STM32_LTDC_FB_NUM == 0) {
186 LOG_ERR("Partial write requires internal frame buffer");
187 return -ENOTSUP;
188 }
189
190 dst = data->frame_buffer;
191
192 if (CONFIG_STM32_LTDC_FB_NUM == 2) {
193 if (data->front_buf == data->frame_buffer) {
194 dst = data->frame_buffer + data->frame_buffer_len;
195 }
196
197 memcpy(dst, data->front_buf, data->frame_buffer_len);
198 }
199
200 pend_buf = dst;
201
202 /* dst = pointer to upper left pixel of the rectangle
203 * to be updated in frame buffer.
204 */
205 dst += (x * data->current_pixel_size);
206 dst += (y * config->width * data->current_pixel_size);
207
208 for (row = 0; row < desc->height; row++) {
209 (void) memcpy(dst, src, desc->width * data->current_pixel_size);
210 sys_cache_data_flush_range(dst, desc->width * data->current_pixel_size);
211 dst += (config->width * data->current_pixel_size);
212 src += (desc->pitch * data->current_pixel_size);
213 }
214
215 }
216
217 if (data->front_buf == pend_buf) {
218 return 0;
219 }
220
221 k_sem_reset(&data->sem);
222
223 data->pend_buf = pend_buf;
224
225 k_sem_take(&data->sem, K_FOREVER);
226
227 return 0;
228 }
229
stm32_ltdc_read(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,void * buf)230 static int stm32_ltdc_read(const struct device *dev, const uint16_t x,
231 const uint16_t y,
232 const struct display_buffer_descriptor *desc,
233 void *buf)
234 {
235 const struct display_stm32_ltdc_config *config = dev->config;
236 struct display_stm32_ltdc_data *data = dev->data;
237 uint8_t *dst = buf;
238 const uint8_t *src = data->front_buf;
239 uint16_t row;
240
241 /* src = pointer to upper left pixel of the rectangle to be read from frame buffer */
242 src += (x * data->current_pixel_size);
243 src += (y * config->width * data->current_pixel_size);
244
245 for (row = 0; row < desc->height; row++) {
246 (void) memcpy(dst, src, desc->width * data->current_pixel_size);
247 sys_cache_data_flush_range(dst, desc->width * data->current_pixel_size);
248 src += (config->width * data->current_pixel_size);
249 dst += (desc->pitch * data->current_pixel_size);
250 }
251
252 return 0;
253 }
254
stm32_ltdc_get_framebuffer(const struct device * dev)255 static void *stm32_ltdc_get_framebuffer(const struct device *dev)
256 {
257 struct display_stm32_ltdc_data *data = dev->data;
258
259 return ((void *)data->front_buf);
260 }
261
stm32_ltdc_display_blanking_off(const struct device * dev)262 static int stm32_ltdc_display_blanking_off(const struct device *dev)
263 {
264 const struct display_stm32_ltdc_config *config = dev->config;
265 const struct device *display_dev = config->display_controller;
266
267 /* Panel controller's phandle is not passed to LTDC in devicetree */
268 if (display_dev == NULL) {
269 LOG_ERR("There is no panel controller to forward blanking_off call to");
270 return -ENOSYS;
271 }
272
273 if (!device_is_ready(display_dev)) {
274 LOG_ERR("Display device %s not ready", display_dev->name);
275 return -ENODEV;
276 }
277
278 return display_blanking_off(display_dev);
279 }
280
stm32_ltdc_display_blanking_on(const struct device * dev)281 static int stm32_ltdc_display_blanking_on(const struct device *dev)
282 {
283 const struct display_stm32_ltdc_config *config = dev->config;
284 const struct device *display_dev = config->display_controller;
285
286 /* Panel controller's phandle is not passed to LTDC in devicetree */
287 if (display_dev == NULL) {
288 LOG_ERR("There is no panel controller to forward blanking_on call to");
289 return -ENOSYS;
290 }
291
292 if (!device_is_ready(display_dev)) {
293 LOG_ERR("Display device %s not ready", display_dev->name);
294 return -ENODEV;
295 }
296
297 return display_blanking_on(display_dev);
298 }
299
stm32_ltdc_init(const struct device * dev)300 static int stm32_ltdc_init(const struct device *dev)
301 {
302 int err;
303 const struct display_stm32_ltdc_config *config = dev->config;
304 struct display_stm32_ltdc_data *data = dev->data;
305
306 /* Configure and set display on/off GPIO */
307 if (config->disp_on_gpio.port) {
308 err = gpio_pin_configure_dt(&config->disp_on_gpio, GPIO_OUTPUT_ACTIVE);
309 if (err < 0) {
310 LOG_ERR("Configuration of display on/off control GPIO failed");
311 return err;
312 }
313 }
314
315 /* Configure and set display backlight control GPIO */
316 if (config->bl_ctrl_gpio.port) {
317 err = gpio_pin_configure_dt(&config->bl_ctrl_gpio, GPIO_OUTPUT_ACTIVE);
318 if (err < 0) {
319 LOG_ERR("Configuration of display backlight control GPIO failed");
320 return err;
321 }
322 }
323
324 /* Configure DT provided pins */
325 if (!IS_ENABLED(CONFIG_MIPI_DSI)) {
326 err = pinctrl_apply_state(config->pctrl, PINCTRL_STATE_DEFAULT);
327 if (err < 0) {
328 LOG_ERR("LTDC pinctrl setup failed");
329 return err;
330 }
331 }
332
333 if (!device_is_ready(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE))) {
334 LOG_ERR("clock control device not ready");
335 return -ENODEV;
336 }
337
338 /* Turn on LTDC peripheral clock */
339 err = clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),
340 (clock_control_subsys_t) &config->pclken);
341 if (err < 0) {
342 LOG_ERR("Could not enable LTDC peripheral clock");
343 return err;
344 }
345
346 #if defined(CONFIG_SOC_SERIES_STM32F4X)
347 LL_RCC_PLLSAI_Disable();
348 LL_RCC_PLLSAI_ConfigDomain_LTDC(LL_RCC_PLLSOURCE_HSE,
349 LL_RCC_PLLSAIM_DIV_8,
350 192,
351 LL_RCC_PLLSAIR_DIV_4,
352 LL_RCC_PLLSAIDIVR_DIV_8);
353
354 LL_RCC_PLLSAI_Enable();
355 while (LL_RCC_PLLSAI_IsReady() != 1) {
356 }
357 #endif
358
359 #if defined(CONFIG_SOC_SERIES_STM32F7X)
360 LL_RCC_PLLSAI_Disable();
361 LL_RCC_PLLSAI_ConfigDomain_LTDC(LL_RCC_PLLSOURCE_HSE,
362 LL_RCC_PLLM_DIV_25,
363 384,
364 LL_RCC_PLLSAIR_DIV_5,
365 LL_RCC_PLLSAIDIVR_DIV_8);
366
367 LL_RCC_PLLSAI_Enable();
368 while (LL_RCC_PLLSAI_IsReady() != 1) {
369 }
370 #endif
371
372 /* reset LTDC peripheral */
373 (void)reset_line_toggle_dt(&config->reset);
374
375 data->current_pixel_format = DISPLAY_INIT_PIXEL_FORMAT;
376 data->current_pixel_size = STM32_LTDC_INIT_PIXEL_SIZE;
377
378 k_sem_init(&data->sem, 0, 1);
379
380 config->irq_config_func(dev);
381
382 #ifdef CONFIG_STM32_LTDC_DISABLE_FMC_BANK1
383 /* Clear MBKEN and MTYP[1:0] bits. */
384 #ifdef CONFIG_SOC_SERIES_STM32F7X
385 FMC_Bank1->BTCR[0] &= ~(0x0000000D);
386 #else /* CONFIG_SOC_SERIES_STM32H7X */
387 FMC_Bank1_R->BTCR[0] &= ~(0x0000000D);
388 #endif
389 #endif /* CONFIG_STM32_LTDC_DISABLE_FMC_BANK1 */
390
391 /* Initialise the LTDC peripheral */
392 err = HAL_LTDC_Init(&data->hltdc);
393 if (err != HAL_OK) {
394 return err;
395 }
396
397 #if defined(CONFIG_STM32_LTDC_FB_USE_SHARED_MULTI_HEAP)
398 data->frame_buffer = shared_multi_heap_aligned_alloc(
399 CONFIG_VIDEO_BUFFER_SMH_ATTRIBUTE,
400 32,
401 CONFIG_STM32_LTDC_FB_NUM * data->frame_buffer_len);
402
403 if (data->frame_buffer == NULL) {
404 return -ENOMEM;
405 }
406
407 data->pend_buf = data->frame_buffer;
408 data->front_buf = data->frame_buffer;
409 data->hltdc.LayerCfg[0].FBStartAdress = (uint32_t) data->frame_buffer;
410 #endif
411
412 /* Configure layer 1 (only one layer is used) */
413 /* LTDC starts fetching pixels and sending them to display after this call */
414 err = HAL_LTDC_ConfigLayer(&data->hltdc, &data->hltdc.LayerCfg[0], LTDC_LAYER_1);
415 if (err != HAL_OK) {
416 return err;
417 }
418
419 /* Disable layer 2, since it not used */
420 __HAL_LTDC_LAYER_DISABLE(&data->hltdc, LTDC_LAYER_2);
421
422 /* Set the line interrupt position */
423 LTDC->LIPCR = 0U;
424
425 __HAL_LTDC_CLEAR_FLAG(&data->hltdc, LTDC_FLAG_LI);
426 __HAL_LTDC_ENABLE_IT(&data->hltdc, LTDC_IT_LI);
427
428 return 0;
429 }
430
431 #ifdef CONFIG_PM_DEVICE
stm32_ltdc_suspend(const struct device * dev)432 static int stm32_ltdc_suspend(const struct device *dev)
433 {
434 const struct display_stm32_ltdc_config *config = dev->config;
435 int err;
436
437 /* Turn off disp_en (if its GPIO is defined in device tree) */
438 if (config->disp_on_gpio.port) {
439 err = gpio_pin_set_dt(&config->disp_on_gpio, 0);
440 if (err < 0) {
441 return err;
442 }
443 }
444
445 /* Turn off backlight (if its GPIO is defined in device tree) */
446 if (config->bl_ctrl_gpio.port) {
447 err = gpio_pin_set_dt(&config->bl_ctrl_gpio, 0);
448 if (err < 0) {
449 return err;
450 }
451 }
452
453 /* Reset LTDC peripheral registers */
454 (void)reset_line_toggle_dt(&config->reset);
455
456 /* Turn off LTDC peripheral clock */
457 err = clock_control_off(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),
458 (clock_control_subsys_t) &config->pclken);
459
460 return err;
461 }
462
stm32_ltdc_pm_action(const struct device * dev,enum pm_device_action action)463 static int stm32_ltdc_pm_action(const struct device *dev,
464 enum pm_device_action action)
465 {
466 int err;
467
468 switch (action) {
469 case PM_DEVICE_ACTION_RESUME:
470 err = stm32_ltdc_init(dev);
471 break;
472 case PM_DEVICE_ACTION_SUSPEND:
473 err = stm32_ltdc_suspend(dev);
474 break;
475 default:
476 return -ENOTSUP;
477 }
478
479 if (err < 0) {
480 LOG_ERR("%s: failed to set power mode", dev->name);
481 }
482
483 return err;
484 }
485 #endif /* CONFIG_PM_DEVICE */
486
487 static DEVICE_API(display, stm32_ltdc_display_api) = {
488 .write = stm32_ltdc_write,
489 .read = stm32_ltdc_read,
490 .get_framebuffer = stm32_ltdc_get_framebuffer,
491 .get_capabilities = stm32_ltdc_get_capabilities,
492 .set_pixel_format = stm32_ltdc_set_pixel_format,
493 .set_orientation = stm32_ltdc_set_orientation,
494 .blanking_off = stm32_ltdc_display_blanking_off,
495 .blanking_on = stm32_ltdc_display_blanking_on,
496 };
497
498 #if DT_INST_NODE_HAS_PROP(0, ext_sdram)
499
500 #if DT_SAME_NODE(DT_INST_PHANDLE(0, ext_sdram), DT_NODELABEL(sdram1))
501 #define FRAME_BUFFER_SECTION __stm32_sdram1_section
502 #elif DT_SAME_NODE(DT_INST_PHANDLE(0, ext_sdram), DT_NODELABEL(sdram2))
503 #define FRAME_BUFFER_SECTION __stm32_sdram2_section
504 #else
505 #error "LTDC ext-sdram property in device tree does not reference SDRAM1 or SDRAM2 node"
506 #define FRAME_BUFFER_SECTION
507 #endif /* DT_SAME_NODE(DT_INST_PHANDLE(0, ext_sdram), DT_NODELABEL(sdram1)) */
508
509 #else
510 #define FRAME_BUFFER_SECTION
511 #endif /* DT_INST_NODE_HAS_PROP(0, ext_sdram) */
512
513 #ifdef CONFIG_MIPI_DSI
514 #define STM32_LTDC_DEVICE_PINCTRL_INIT(n)
515 #define STM32_LTDC_DEVICE_PINCTRL_GET(n) (NULL)
516 #else
517 #define STM32_LTDC_DEVICE_PINCTRL_INIT(n) PINCTRL_DT_INST_DEFINE(n)
518 #define STM32_LTDC_DEVICE_PINCTRL_GET(n) PINCTRL_DT_INST_DEV_CONFIG_GET(n)
519 #endif
520
521 #define STM32_LTDC_FRAME_BUFFER_LEN(inst) \
522 (STM32_LTDC_INIT_PIXEL_SIZE * DT_INST_PROP(inst, height) * DT_INST_PROP(inst, width)) \
523
524 #if defined(CONFIG_STM32_LTDC_FB_USE_SHARED_MULTI_HEAP)
525 #define STM32_LTDC_FRAME_BUFFER_ADDR(inst) (NULL)
526 #define STM32_LTDC_FRAME_BUFFER_DEFINE(inst)
527 #else
528 #define STM32_LTDC_FRAME_BUFFER_ADDR(inst) frame_buffer_##inst
529 #define STM32_LTDC_FRAME_BUFFER_DEFINE(inst) \
530 /* frame buffer aligned to cache line width for optimal cache flushing */ \
531 FRAME_BUFFER_SECTION static uint8_t __aligned(32) \
532 frame_buffer_##inst[CONFIG_STM32_LTDC_FB_NUM * STM32_LTDC_FRAME_BUFFER_LEN(inst)];
533 #endif
534
535 #define STM32_LTDC_DEVICE(inst) \
536 STM32_LTDC_FRAME_BUFFER_DEFINE(inst); \
537 STM32_LTDC_DEVICE_PINCTRL_INIT(inst); \
538 PM_DEVICE_DT_INST_DEFINE(inst, stm32_ltdc_pm_action); \
539 static void stm32_ltdc_irq_config_func_##inst(const struct device *dev) \
540 { \
541 IRQ_CONNECT(DT_INST_IRQN(inst), \
542 DT_INST_IRQ(inst, priority), \
543 stm32_ltdc_global_isr, \
544 DEVICE_DT_INST_GET(inst), \
545 0); \
546 irq_enable(DT_INST_IRQN(inst)); \
547 } \
548 static struct display_stm32_ltdc_data stm32_ltdc_data_##inst = { \
549 .frame_buffer = STM32_LTDC_FRAME_BUFFER_ADDR(inst), \
550 .frame_buffer_len = STM32_LTDC_FRAME_BUFFER_LEN(inst), \
551 .front_buf = STM32_LTDC_FRAME_BUFFER_ADDR(inst), \
552 .pend_buf = STM32_LTDC_FRAME_BUFFER_ADDR(inst), \
553 .hltdc = { \
554 .Instance = (LTDC_TypeDef *) DT_INST_REG_ADDR(inst), \
555 .Init = { \
556 .HSPolarity = (DT_PROP(DT_INST_CHILD(inst, display_timings), \
557 hsync_active) ? \
558 LTDC_HSPOL_ACTIVE_HIGH : LTDC_HSPOL_ACTIVE_LOW),\
559 .VSPolarity = (DT_PROP(DT_INST_CHILD(inst, \
560 display_timings), vsync_active) ? \
561 LTDC_VSPOL_ACTIVE_HIGH : LTDC_VSPOL_ACTIVE_LOW),\
562 .DEPolarity = (DT_PROP(DT_INST_CHILD(inst, \
563 display_timings), de_active) ? \
564 LTDC_DEPOL_ACTIVE_HIGH : LTDC_DEPOL_ACTIVE_LOW),\
565 .PCPolarity = (DT_PROP(DT_INST_CHILD(inst, \
566 display_timings), pixelclk_active) ? \
567 LTDC_PCPOL_ACTIVE_HIGH : LTDC_PCPOL_ACTIVE_LOW),\
568 .HorizontalSync = DT_PROP(DT_INST_CHILD(inst, \
569 display_timings), hsync_len) - 1, \
570 .VerticalSync = DT_PROP(DT_INST_CHILD(inst, \
571 display_timings), vsync_len) - 1, \
572 .AccumulatedHBP = DT_PROP(DT_INST_CHILD(inst, \
573 display_timings), hback_porch) + \
574 DT_PROP(DT_INST_CHILD(inst, \
575 display_timings), hsync_len) - 1, \
576 .AccumulatedVBP = DT_PROP(DT_INST_CHILD(inst, \
577 display_timings), vback_porch) + \
578 DT_PROP(DT_INST_CHILD(inst, \
579 display_timings), vsync_len) - 1, \
580 .AccumulatedActiveW = DT_PROP(DT_INST_CHILD(inst, \
581 display_timings), hback_porch) + \
582 DT_PROP(DT_INST_CHILD(inst, \
583 display_timings), hsync_len) + \
584 DT_INST_PROP(inst, width) - 1, \
585 .AccumulatedActiveH = DT_PROP(DT_INST_CHILD(inst, \
586 display_timings), vback_porch) + \
587 DT_PROP(DT_INST_CHILD(inst, \
588 display_timings), vsync_len) + \
589 DT_INST_PROP(inst, height) - 1, \
590 .TotalWidth = DT_PROP(DT_INST_CHILD(inst, \
591 display_timings), hback_porch) + \
592 DT_PROP(DT_INST_CHILD(inst, \
593 display_timings), hsync_len) + \
594 DT_INST_PROP(inst, width) + \
595 DT_PROP(DT_INST_CHILD(inst, \
596 display_timings), hfront_porch) - 1, \
597 .TotalHeigh = DT_PROP(DT_INST_CHILD(inst, \
598 display_timings), vback_porch) + \
599 DT_PROP(DT_INST_CHILD(inst, \
600 display_timings), vsync_len) + \
601 DT_INST_PROP(inst, height) + \
602 DT_PROP(DT_INST_CHILD(inst, \
603 display_timings), vfront_porch) - 1, \
604 .Backcolor.Red = \
605 DT_INST_PROP_OR(inst, def_back_color_red, 0xFF), \
606 .Backcolor.Green = \
607 DT_INST_PROP_OR(inst, def_back_color_green, 0xFF), \
608 .Backcolor.Blue = \
609 DT_INST_PROP_OR(inst, def_back_color_blue, 0xFF), \
610 }, \
611 .LayerCfg[0] = { \
612 .WindowX0 = DT_INST_PROP_OR(inst, window0_x0, 0), \
613 .WindowX1 = DT_INST_PROP_OR(inst, window0_x1, \
614 DT_INST_PROP(inst, width)), \
615 .WindowY0 = DT_INST_PROP_OR(inst, window0_y0, 0), \
616 .WindowY1 = DT_INST_PROP_OR(inst, window0_y1, \
617 DT_INST_PROP(inst, height)), \
618 .PixelFormat = STM32_LTDC_INIT_PIXEL_FORMAT, \
619 .Alpha = 255, \
620 .Alpha0 = 0, \
621 .BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA, \
622 .BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA, \
623 .FBStartAdress = (uint32_t) STM32_LTDC_FRAME_BUFFER_ADDR(inst), \
624 .ImageWidth = DT_INST_PROP(inst, width), \
625 .ImageHeight = DT_INST_PROP(inst, height), \
626 .Backcolor.Red = \
627 DT_INST_PROP_OR(inst, def_back_color_red, 0xFF), \
628 .Backcolor.Green = \
629 DT_INST_PROP_OR(inst, def_back_color_green, 0xFF), \
630 .Backcolor.Blue = \
631 DT_INST_PROP_OR(inst, def_back_color_blue, 0xFF), \
632 }, \
633 }, \
634 }; \
635 static const struct display_stm32_ltdc_config stm32_ltdc_config_##inst = { \
636 .width = DT_INST_PROP(inst, width), \
637 .height = DT_INST_PROP(inst, height), \
638 .disp_on_gpio = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, disp_on_gpios), \
639 (GPIO_DT_SPEC_INST_GET(inst, disp_on_gpios)), ({ 0 })), \
640 .bl_ctrl_gpio = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, bl_ctrl_gpios), \
641 (GPIO_DT_SPEC_INST_GET(inst, bl_ctrl_gpios)), ({ 0 })), \
642 .reset = RESET_DT_SPEC_INST_GET(0), \
643 .pclken = { \
644 .enr = DT_INST_CLOCKS_CELL(inst, bits), \
645 .bus = DT_INST_CLOCKS_CELL(inst, bus) \
646 }, \
647 .pctrl = STM32_LTDC_DEVICE_PINCTRL_GET(inst), \
648 .irq_config_func = stm32_ltdc_irq_config_func_##inst, \
649 .display_controller = DEVICE_DT_GET_OR_NULL( \
650 DT_INST_PHANDLE(inst, display_controller)), \
651 }; \
652 DEVICE_DT_INST_DEFINE(inst, \
653 &stm32_ltdc_init, \
654 PM_DEVICE_DT_INST_GET(inst), \
655 &stm32_ltdc_data_##inst, \
656 &stm32_ltdc_config_##inst, \
657 POST_KERNEL, \
658 CONFIG_DISPLAY_INIT_PRIORITY, \
659 &stm32_ltdc_display_api);
660
661 DT_INST_FOREACH_STATUS_OKAY(STM32_LTDC_DEVICE)
662