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