1 /*
2  * Copyright (c) 2023 bytes at work AG
3  * Copyright (c) 2020 Teslabs Engineering S.L.
4  * based on dsi_mcux.c
5  * Copyright (c) 2022, NXP
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #define DT_DRV_COMPAT st_stm32_mipi_dsi
11 
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/sys/printk.h>
15 #include <zephyr/drivers/clock_control.h>
16 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
17 #include <zephyr/drivers/gpio.h>
18 #include <zephyr/drivers/mipi_dsi.h>
19 #include <zephyr/drivers/reset.h>
20 #include <zephyr/logging/log.h>
21 
22 LOG_MODULE_REGISTER(dsi_stm32, CONFIG_MIPI_DSI_LOG_LEVEL);
23 
24 #if defined(CONFIG_STM32_LTDC_ARGB8888)
25 #define STM32_DSI_INIT_PIXEL_FORMAT	DSI_RGB888
26 #elif defined(CONFIG_STM32_LTDC_RGB888)
27 #define STM32_DSI_INIT_PIXEL_FORMAT	DSI_RGB888
28 #elif defined(CONFIG_STM32_LTDC_RGB565)
29 #define STM32_DSI_INIT_PIXEL_FORMAT	DSI_RGB565
30 #else
31 #error "Invalid LTDC pixel format chosen"
32 #endif /* CONFIG_STM32_LTDC_ARGB8888 */
33 
34 #define MAX_TX_ESC_CLK_KHZ 20000
35 #define MAX_TX_ESC_CLK_DIV 8
36 
37 struct mipi_dsi_stm32_config {
38 	const struct device *rcc;
39 	const struct reset_dt_spec reset;
40 	struct stm32_pclken dsi_clk;
41 	struct stm32_pclken ref_clk;
42 	struct stm32_pclken pix_clk;
43 	uint32_t data_lanes;
44 	uint32_t active_errors;
45 	uint32_t lp_rx_filter_freq;
46 	int test_pattern;
47 };
48 
49 struct mipi_dsi_stm32_data {
50 	DSI_HandleTypeDef hdsi;
51 	DSI_HOST_TimeoutTypeDef *host_timeouts;
52 	DSI_PHY_TimerTypeDef *phy_timings;
53 	DSI_VidCfgTypeDef vid_cfg;
54 	DSI_PLLInitTypeDef pll_init;
55 	uint32_t lane_clk_khz;
56 	uint32_t pixel_clk_khz;
57 };
58 
mipi_dsi_stm32_log_config(const struct device * dev)59 static void mipi_dsi_stm32_log_config(const struct device *dev)
60 {
61 	const struct mipi_dsi_stm32_config *config = dev->config;
62 	struct mipi_dsi_stm32_data *data = dev->data;
63 
64 	LOG_DBG("DISPLAY: pix %d kHz, lane %d kHz", data->pixel_clk_khz, data->lane_clk_khz);
65 	LOG_DBG("HAL_DSI_Init setup:");
66 	LOG_DBG("  AutomaticClockLaneControl 0x%x", data->hdsi.Init.AutomaticClockLaneControl);
67 	LOG_DBG("  TXEscapeCkdiv %u", data->hdsi.Init.TXEscapeCkdiv);
68 	LOG_DBG("  NumberOfLanes %u", data->hdsi.Init.NumberOfLanes);
69 	LOG_DBG("  PLLNDIV %u", data->pll_init.PLLNDIV);
70 	LOG_DBG("  PLLIDF %u", data->pll_init.PLLIDF);
71 	LOG_DBG("  PLLODF %u", data->pll_init.PLLODF);
72 
73 	LOG_DBG("HAL_DSI_ConfigVideoMode setup:");
74 	LOG_DBG("  VirtualChannelID %u", data->vid_cfg.VirtualChannelID);
75 	LOG_DBG("  ColorCoding 0x%x", data->vid_cfg.ColorCoding);
76 	LOG_DBG("  LooselyPacked 0x%x", data->vid_cfg.LooselyPacked);
77 	LOG_DBG("  Mode 0x%x", data->vid_cfg.Mode);
78 	LOG_DBG("  PacketSize %u", data->vid_cfg.PacketSize);
79 	LOG_DBG("  NumberOfChunks %u", data->vid_cfg.NumberOfChunks);
80 	LOG_DBG("  NullPacketSize %u", data->vid_cfg.NullPacketSize);
81 	LOG_DBG("  HSPolarity 0x%x", data->vid_cfg.HSPolarity);
82 	LOG_DBG("  VSPolarity 0x%x", data->vid_cfg.VSPolarity);
83 	LOG_DBG("  DEPolarity 0x%x", data->vid_cfg.DEPolarity);
84 	LOG_DBG("  HorizontalSyncActive %u", data->vid_cfg.HorizontalSyncActive);
85 	LOG_DBG("  HorizontalBackPorch %u", data->vid_cfg.HorizontalBackPorch);
86 	LOG_DBG("  HorizontalLine %u", data->vid_cfg.HorizontalLine);
87 	LOG_DBG("  VerticalSyncActive %u", data->vid_cfg.VerticalSyncActive);
88 	LOG_DBG("  VerticalBackPorch %u", data->vid_cfg.VerticalBackPorch);
89 	LOG_DBG("  VerticalFrontPorch %u", data->vid_cfg.VerticalFrontPorch);
90 	LOG_DBG("  VerticalActive %u", data->vid_cfg.VerticalActive);
91 	LOG_DBG("  LPCommandEnable 0x%x", data->vid_cfg.LPCommandEnable);
92 	LOG_DBG("  LPLargestPacketSize %u", data->vid_cfg.LPLargestPacketSize);
93 	LOG_DBG("  LPVACTLargestPacketSize %u", data->vid_cfg.LPVACTLargestPacketSize);
94 	LOG_DBG("  LPHorizontalFrontPorchEnable 0x%x", data->vid_cfg.LPHorizontalFrontPorchEnable);
95 	LOG_DBG("  LPHorizontalBackPorchEnable 0x%x", data->vid_cfg.LPHorizontalBackPorchEnable);
96 	LOG_DBG("  LPVerticalActiveEnable 0x%x", data->vid_cfg.LPVerticalActiveEnable);
97 	LOG_DBG("  LPVerticalFrontPorchEnable 0x%x", data->vid_cfg.LPVerticalFrontPorchEnable);
98 	LOG_DBG("  LPVerticalBackPorchEnable 0x%x", data->vid_cfg.LPVerticalBackPorchEnable);
99 	LOG_DBG("  LPVerticalSyncActiveEnable 0x%x", data->vid_cfg.LPVerticalSyncActiveEnable);
100 	LOG_DBG("  FrameBTAAcknowledgeEnable 0x%x", data->vid_cfg.FrameBTAAcknowledgeEnable);
101 
102 	if (config->active_errors) {
103 		LOG_DBG("HAL_DSI_ConfigErrorMonitor: 0x%x", config->active_errors);
104 	}
105 
106 	if (config->lp_rx_filter_freq) {
107 		LOG_DBG("HAL_DSI_SetLowPowerRXFilter: %d", config->lp_rx_filter_freq);
108 	}
109 
110 	if (data->host_timeouts) {
111 		DSI_HOST_TimeoutTypeDef *ht = data->host_timeouts;
112 
113 		LOG_DBG("HAL_DSI_ConfigHostTimeouts:");
114 		LOG_DBG("  TimeoutCkdiv %u", ht->TimeoutCkdiv);
115 		LOG_DBG("  HighSpeedTransmissionTimeout %u", ht->HighSpeedTransmissionTimeout);
116 		LOG_DBG("  LowPowerReceptionTimeout %u", ht->LowPowerReceptionTimeout);
117 		LOG_DBG("  HighSpeedReadTimeout %u", ht->HighSpeedReadTimeout);
118 		LOG_DBG("  LowPowerReadTimeout %u", ht->LowPowerReadTimeout);
119 		LOG_DBG("  HighSpeedWriteTimeout %u", ht->HighSpeedWriteTimeout);
120 		LOG_DBG("  HighSpeedWritePrespMode %u", ht->HighSpeedWritePrespMode);
121 		LOG_DBG("  LowPowerWriteTimeout %u", ht->LowPowerWriteTimeout);
122 		LOG_DBG("  BTATimeout %u", ht->BTATimeout);
123 	}
124 
125 	if (data->phy_timings) {
126 		LOG_DBG("HAL_DSI_ConfigPhyTimer:");
127 		LOG_DBG("  ClockLaneHS2LPTime %u", data->phy_timings->ClockLaneHS2LPTime);
128 		LOG_DBG("  ClockLaneLP2HSTime %u", data->phy_timings->ClockLaneLP2HSTime);
129 		LOG_DBG("  DataLaneHS2LPTime %u", data->phy_timings->DataLaneHS2LPTime);
130 		LOG_DBG("  DataLaneLP2HSTime %u", data->phy_timings->DataLaneLP2HSTime);
131 		LOG_DBG("  DataLaneMaxReadTime %u", data->phy_timings->DataLaneMaxReadTime);
132 		LOG_DBG("  StopWaitTime %u", data->phy_timings->StopWaitTime);
133 	}
134 }
135 
mipi_dsi_stm32_host_init(const struct device * dev)136 static int mipi_dsi_stm32_host_init(const struct device *dev)
137 {
138 	const struct mipi_dsi_stm32_config *config = dev->config;
139 	struct mipi_dsi_stm32_data *data = dev->data;
140 	uint32_t hse_clock;
141 	int ret;
142 
143 	switch (config->data_lanes) {
144 	case 1:
145 		data->hdsi.Init.NumberOfLanes = DSI_ONE_DATA_LANE;
146 		break;
147 	case 2:
148 		data->hdsi.Init.NumberOfLanes = DSI_TWO_DATA_LANES;
149 		break;
150 	default:
151 		LOG_ERR("Number of DSI lanes (%d) not supported!", config->data_lanes);
152 		return -ENOTSUP;
153 	}
154 
155 	ret = clock_control_get_rate(config->rcc, (clock_control_subsys_t)&config->pix_clk,
156 				     &data->pixel_clk_khz);
157 	if (ret) {
158 		LOG_ERR("Get pixel clock failed! (%d)", ret);
159 		return ret;
160 	}
161 
162 	data->pixel_clk_khz /= 1000;
163 	ret = clock_control_get_rate(config->rcc, (clock_control_subsys_t)&config->ref_clk,
164 				     &hse_clock);
165 	if (ret) {
166 		LOG_ERR("Get HSE clock failed! (%d)", ret);
167 		return ret;
168 	}
169 
170 	/* LANE_BYTE_CLOCK = CLK_IN / PLLIDF * 2 * PLLNDIV / 2 / PLLODF / 8 */
171 	data->lane_clk_khz = hse_clock / data->pll_init.PLLIDF * 2 * data->pll_init.PLLNDIV / 2 /
172 			     (1UL << data->pll_init.PLLODF) / 8 / 1000;
173 
174 	/* stm32x_hal_dsi: The values 0 and 1 stop the TX_ESC clock generation */
175 	data->hdsi.Init.TXEscapeCkdiv = 0;
176 	for (int i = 2; i <= MAX_TX_ESC_CLK_DIV; i++) {
177 		if ((data->lane_clk_khz / i) <= MAX_TX_ESC_CLK_KHZ) {
178 			data->hdsi.Init.TXEscapeCkdiv = i;
179 			break;
180 		}
181 	}
182 
183 	if (data->hdsi.Init.TXEscapeCkdiv < 2) {
184 		LOG_WRN("DSI TX escape clock disabled.");
185 	}
186 
187 	ret = HAL_DSI_Init(&data->hdsi, &data->pll_init);
188 	if (ret != HAL_OK) {
189 		LOG_ERR("DSI init failed! (%d)", ret);
190 		return -ret;
191 	}
192 
193 	if (data->host_timeouts) {
194 		ret = HAL_DSI_ConfigHostTimeouts(&data->hdsi, data->host_timeouts);
195 		if (ret != HAL_OK) {
196 			LOG_ERR("Set DSI host timeouts failed! (%d)", ret);
197 			return -ret;
198 		}
199 	}
200 
201 	if (data->phy_timings) {
202 		ret = HAL_DSI_ConfigPhyTimer(&data->hdsi, data->phy_timings);
203 		if (ret != HAL_OK) {
204 			LOG_ERR("Set DSI PHY timings failed! (%d)", ret);
205 			return -ret;
206 		}
207 	}
208 
209 	ret = HAL_DSI_ConfigFlowControl(&data->hdsi, DSI_FLOW_CONTROL_BTA);
210 	if (ret != HAL_OK) {
211 		LOG_ERR("Setup DSI flow control failed! (%d)", ret);
212 		return -ret;
213 	}
214 
215 	if (config->lp_rx_filter_freq) {
216 		ret = HAL_DSI_SetLowPowerRXFilter(&data->hdsi, config->lp_rx_filter_freq);
217 		if (ret != HAL_OK) {
218 			LOG_ERR("Setup DSI LP RX filter failed! (%d)", ret);
219 			return -ret;
220 		}
221 	}
222 
223 	ret = HAL_DSI_ConfigErrorMonitor(&data->hdsi, config->active_errors);
224 	if (ret != HAL_OK) {
225 		LOG_ERR("Setup DSI error monitor failed! (%d)", ret);
226 		return -ret;
227 	}
228 
229 	return 0;
230 }
231 
232 
mipi_dsi_stm32_attach(const struct device * dev,uint8_t channel,const struct mipi_dsi_device * mdev)233 static int mipi_dsi_stm32_attach(const struct device *dev, uint8_t channel,
234 				 const struct mipi_dsi_device *mdev)
235 {
236 	const struct mipi_dsi_stm32_config *config = dev->config;
237 	struct mipi_dsi_stm32_data *data = dev->data;
238 	DSI_VidCfgTypeDef *vcfg = &data->vid_cfg;
239 	int ret;
240 
241 	if (!(mdev->mode_flags & MIPI_DSI_MODE_VIDEO)) {
242 		LOG_ERR("DSI host supports video mode only!");
243 		return -ENOTSUP;
244 	}
245 
246 	vcfg->VirtualChannelID = channel;
247 	vcfg->ColorCoding = STM32_DSI_INIT_PIXEL_FORMAT;
248 
249 	if (mdev->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
250 		vcfg->Mode = DSI_VID_MODE_BURST;
251 	} else if (mdev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
252 		vcfg->Mode = DSI_VID_MODE_NB_PULSES;
253 	} else {
254 		vcfg->Mode = DSI_VID_MODE_NB_EVENTS;
255 	}
256 
257 	vcfg->PacketSize = mdev->timings.hactive;
258 	vcfg->NumberOfChunks = 0;
259 	vcfg->NullPacketSize = 0xFFFU;
260 
261 	vcfg->HorizontalSyncActive =
262 		(mdev->timings.hsync * data->lane_clk_khz) / data->pixel_clk_khz;
263 	vcfg->HorizontalBackPorch =
264 		(mdev->timings.hbp * data->lane_clk_khz) / data->pixel_clk_khz;
265 	vcfg->HorizontalLine =
266 		((mdev->timings.hactive + mdev->timings.hsync + mdev->timings.hbp +
267 		  mdev->timings.hfp) * data->lane_clk_khz) / data->pixel_clk_khz;
268 	vcfg->VerticalSyncActive = mdev->timings.vsync;
269 	vcfg->VerticalBackPorch = mdev->timings.vbp;
270 	vcfg->VerticalFrontPorch = mdev->timings.vfp;
271 	vcfg->VerticalActive = mdev->timings.vactive;
272 
273 	if (mdev->mode_flags & MIPI_DSI_MODE_LPM) {
274 		vcfg->LPCommandEnable = DSI_LP_COMMAND_ENABLE;
275 	} else {
276 		vcfg->LPCommandEnable = DSI_LP_COMMAND_DISABLE;
277 	}
278 
279 	vcfg->LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
280 	vcfg->LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
281 	vcfg->LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
282 	vcfg->LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
283 	vcfg->LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
284 	vcfg->LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
285 
286 	ret = HAL_DSI_ConfigVideoMode(&data->hdsi, vcfg);
287 	if (ret != HAL_OK) {
288 		LOG_ERR("Setup DSI video mode failed! (%d)", ret);
289 		return -ret;
290 	}
291 
292 	if (IS_ENABLED(CONFIG_MIPI_DSI_LOG_LEVEL_DBG)) {
293 		mipi_dsi_stm32_log_config(dev);
294 	}
295 
296 	ret = HAL_DSI_Start(&data->hdsi);
297 	if (ret != HAL_OK) {
298 		LOG_ERR("Start DSI host failed! (%d)", ret);
299 		return -ret;
300 	}
301 
302 	if (config->test_pattern >= 0) {
303 		ret = HAL_DSI_PatternGeneratorStart(&data->hdsi, 0, config->test_pattern);
304 		if (ret != HAL_OK) {
305 			LOG_ERR("Start DSI pattern generator failed! (%d)", ret);
306 			return -ret;
307 		}
308 	}
309 
310 	return 0;
311 }
312 
mipi_dsi_stm32_transfer(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)313 static ssize_t mipi_dsi_stm32_transfer(const struct device *dev, uint8_t channel,
314 				       struct mipi_dsi_msg *msg)
315 {
316 	struct mipi_dsi_stm32_data *data = dev->data;
317 	uint32_t param1 = 0;
318 	uint32_t param2 = 0;
319 	ssize_t len;
320 	int ret;
321 
322 	switch (msg->type) {
323 	case MIPI_DSI_DCS_READ:
324 		ret = HAL_DSI_Read(&data->hdsi, channel, (uint8_t *)msg->rx_buf, msg->rx_len,
325 				   msg->type, msg->cmd, (uint8_t *)msg->rx_buf);
326 		len =  msg->rx_len;
327 		break;
328 	case MIPI_DSI_DCS_SHORT_WRITE:
329 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
330 		param1 = msg->cmd;
331 		if (msg->tx_len >= 1U) {
332 			param2 = ((uint8_t *)msg->tx_buf)[0];
333 		}
334 
335 		ret = HAL_DSI_ShortWrite(&data->hdsi, channel, msg->type, param1, param2);
336 		len = msg->tx_len;
337 		break;
338 	case MIPI_DSI_DCS_LONG_WRITE:
339 		ret = HAL_DSI_LongWrite(&data->hdsi, channel, msg->type, msg->tx_len, msg->cmd,
340 					(uint8_t *)msg->tx_buf);
341 		len = msg->tx_len;
342 		break;
343 	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
344 	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
345 	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
346 		param1 = ((uint8_t *)msg->tx_buf)[0];
347 		if (msg->tx_len == 1U) {
348 			param2 = ((uint8_t *)msg->tx_buf)[1];
349 		}
350 
351 		if (msg->tx_len >= 2U) {
352 			param2 = *(uint16_t *)&((uint8_t *)msg->tx_buf)[1];
353 		}
354 
355 		ret = HAL_DSI_ShortWrite(&data->hdsi, channel, msg->type, param1, param2);
356 		len = msg->tx_len;
357 		break;
358 	case MIPI_DSI_GENERIC_LONG_WRITE:
359 		ret = HAL_DSI_LongWrite(&data->hdsi, channel, msg->type, msg->tx_len,
360 					((uint8_t *)msg->tx_buf)[0], &((uint8_t *)msg->tx_buf)[1]);
361 		len = msg->tx_len;
362 		break;
363 	default:
364 		LOG_ERR("Unsupported message type (%d)", msg->type);
365 		return -ENOTSUP;
366 	}
367 
368 	if (IS_ENABLED(CONFIG_MIPI_DSI_LOG_LEVEL_DBG)) {
369 		char tmp[64];
370 
371 		if (msg->type == MIPI_DSI_DCS_READ) {
372 			snprintk(tmp, sizeof(tmp), "RX: ch %3d, reg 0x%02x, len %2d",
373 				 channel, msg->cmd, msg->rx_len);
374 			LOG_HEXDUMP_DBG(msg->rx_buf, msg->rx_len, tmp);
375 		} else {
376 			snprintk(tmp, sizeof(tmp), "TX: ch %3d, reg 0x%02x, len %2d",
377 				 channel, msg->cmd, msg->tx_len);
378 			LOG_HEXDUMP_DBG(msg->tx_buf, msg->tx_len, tmp);
379 		}
380 	}
381 
382 	if (ret != HAL_OK) {
383 		LOG_ERR("Transfer failed! (%d)", ret);
384 		return -EIO;
385 	}
386 
387 	return len;
388 }
389 
390 static DEVICE_API(mipi_dsi, dsi_stm32_api) = {
391 	.attach = mipi_dsi_stm32_attach,
392 	.transfer = mipi_dsi_stm32_transfer,
393 };
394 
mipi_dsi_stm32_init(const struct device * dev)395 static int mipi_dsi_stm32_init(const struct device *dev)
396 {
397 	const struct mipi_dsi_stm32_config *config = dev->config;
398 	int ret;
399 
400 	if (!device_is_ready(config->rcc)) {
401 		LOG_ERR("clock control device not ready");
402 		return -ENODEV;
403 	}
404 
405 	ret = clock_control_on(config->rcc, (clock_control_subsys_t)&config->dsi_clk);
406 	if (ret < 0) {
407 		LOG_ERR("Enable DSI peripheral clock failed! (%d)", ret);
408 		return ret;
409 	}
410 
411 	(void)reset_line_toggle_dt(&config->reset);
412 
413 	ret = mipi_dsi_stm32_host_init(dev);
414 	if (ret) {
415 		LOG_ERR("Setup DSI host failed! (%d)", ret);
416 		return ret;
417 	}
418 
419 	return 0;
420 }
421 
422 #define CHILD_GET_DATA_LANES(child) DT_PROP(child, data_lanes)
423 
424 #define STM32_MIPI_DSI_DEVICE(inst)								\
425 	COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, host_timeouts),					\
426 		(static DSI_HOST_TimeoutTypeDef host_timeouts_##inst = {			\
427 			.TimeoutCkdiv = DT_INST_PROP_BY_IDX(inst, host_timeouts, 0),		\
428 			.HighSpeedTransmissionTimeout =						\
429 				DT_INST_PROP_BY_IDX(inst, host_timeouts, 1),			\
430 			.LowPowerReceptionTimeout =						\
431 				DT_INST_PROP_BY_IDX(inst, host_timeouts, 2),			\
432 			.HighSpeedReadTimeout = DT_INST_PROP_BY_IDX(inst, host_timeouts, 3),	\
433 			.LowPowerReadTimeout = DT_INST_PROP_BY_IDX(inst, host_timeouts, 4),	\
434 			.HighSpeedWriteTimeout = DT_INST_PROP_BY_IDX(inst, host_timeouts, 5),	\
435 			.HighSpeedWritePrespMode = DT_INST_PROP_BY_IDX(inst, host_timeouts, 6),	\
436 			.LowPowerWriteTimeout = DT_INST_PROP_BY_IDX(inst, host_timeouts, 7),	\
437 			.BTATimeout = DT_INST_PROP_BY_IDX(inst, host_timeouts, 8)		\
438 		}), ());									\
439 	COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, phy_timings),					\
440 		(static DSI_PHY_TimerTypeDef phy_timings_##inst = {				\
441 			.ClockLaneHS2LPTime = DT_INST_PROP_BY_IDX(inst, phy_timings, 0),	\
442 			.ClockLaneLP2HSTime = DT_INST_PROP_BY_IDX(inst, phy_timings, 1),	\
443 			.DataLaneHS2LPTime = DT_INST_PROP_BY_IDX(inst, phy_timings, 2),		\
444 			.DataLaneLP2HSTime = DT_INST_PROP_BY_IDX(inst, phy_timings, 3),		\
445 			.DataLaneMaxReadTime = DT_INST_PROP_BY_IDX(inst, phy_timings, 4),	\
446 			.StopWaitTime = DT_INST_PROP_BY_IDX(inst, phy_timings, 5)		\
447 		}), ());									\
448 	/* Only child data-lanes property at index 0 is taken into account */			\
449 	static const uint32_t data_lanes_##inst[] = {						\
450 		DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP_VARGS(inst, DT_PROP_BY_IDX, (,),		\
451 							    data_lanes, 0)			\
452 	};											\
453 	static const struct mipi_dsi_stm32_config stm32_dsi_config_##inst = {			\
454 		.rcc = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),					\
455 		.reset = RESET_DT_SPEC_INST_GET(inst),						\
456 		.dsi_clk = {									\
457 			.enr = DT_INST_CLOCKS_CELL_BY_NAME(inst, dsiclk, bits),			\
458 			.bus = DT_INST_CLOCKS_CELL_BY_NAME(inst, dsiclk, bus),			\
459 		},										\
460 		.ref_clk = {									\
461 			.enr = DT_INST_CLOCKS_CELL_BY_NAME(inst, refclk, bits),			\
462 			.bus = DT_INST_CLOCKS_CELL_BY_NAME(inst, refclk, bus),			\
463 		},										\
464 		.pix_clk = {									\
465 			.enr = DT_INST_CLOCKS_CELL_BY_NAME(inst, pixelclk, bits),		\
466 			.bus = DT_INST_CLOCKS_CELL_BY_NAME(inst, pixelclk, bus),		\
467 		},										\
468 		/* Use only one (the first) display configuration for DSI HOST configuration */	\
469 		.data_lanes = data_lanes_##inst[0],						\
470 		.active_errors = DT_INST_PROP_OR(inst, active_errors, HAL_DSI_ERROR_NONE),	\
471 		.lp_rx_filter_freq = DT_INST_PROP_OR(inst, lp_rx_filter, 0),			\
472 		.test_pattern = DT_INST_PROP_OR(inst, test_pattern, -1),			\
473 	};											\
474 	static struct mipi_dsi_stm32_data stm32_dsi_data_##inst = {				\
475 		.hdsi = {									\
476 			.Instance = (DSI_TypeDef *)DT_INST_REG_ADDR(inst),			\
477 			.Init = {								\
478 				.AutomaticClockLaneControl =					\
479 					DT_INST_PROP(inst, non_continuous) ?			\
480 						DSI_AUTO_CLK_LANE_CTRL_ENABLE :			\
481 						DSI_AUTO_CLK_LANE_CTRL_DISABLE,			\
482 			},									\
483 		},										\
484 		.host_timeouts = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, host_timeouts),	\
485 					     (&host_timeouts_##inst), (NULL)),			\
486 		.phy_timings = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, phy_timings),		\
487 					   (&phy_timings_##inst), (NULL)),			\
488 		.vid_cfg = {									\
489 			.HSPolarity = DT_INST_PROP(inst, hs_active_high) ?			\
490 				      DSI_HSYNC_ACTIVE_HIGH : DSI_HSYNC_ACTIVE_LOW,		\
491 			.VSPolarity = DT_INST_PROP(inst, vs_active_high) ?			\
492 				      DSI_VSYNC_ACTIVE_HIGH : DSI_VSYNC_ACTIVE_LOW,		\
493 			.DEPolarity = DT_INST_PROP(inst, de_active_high) ?			\
494 				      DSI_DATA_ENABLE_ACTIVE_HIGH : DSI_DATA_ENABLE_ACTIVE_LOW, \
495 			.LooselyPacked = DT_INST_PROP(inst, loosely_packed) ? \
496 				      DSI_LOOSELY_PACKED_ENABLE : DSI_LOOSELY_PACKED_DISABLE,	\
497 			.LPLargestPacketSize =  DT_INST_PROP_OR(inst, largest_packet_size, 4), \
498 			.LPVACTLargestPacketSize = DT_INST_PROP_OR(inst, largest_packet_size, 4), \
499 			.FrameBTAAcknowledgeEnable = DT_INST_PROP(inst, bta_ack_disable) ?	\
500 					  DSI_FBTAA_DISABLE : DSI_FBTAA_ENABLE,	\
501 		},										\
502 		.pll_init = {									\
503 			.PLLNDIV = DT_INST_PROP(inst, pll_ndiv),				\
504 			.PLLIDF = DT_INST_PROP(inst, pll_idf),					\
505 			.PLLODF = DT_INST_PROP(inst, pll_odf),					\
506 		},										\
507 	};											\
508 	DEVICE_DT_INST_DEFINE(inst, &mipi_dsi_stm32_init, NULL,					\
509 			      &stm32_dsi_data_##inst, &stm32_dsi_config_##inst,			\
510 			      POST_KERNEL, CONFIG_MIPI_DSI_INIT_PRIORITY, &dsi_stm32_api);
511 
512 DT_INST_FOREACH_STATUS_OKAY(STM32_MIPI_DSI_DEVICE)
513