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