1 /*
2  * Copyright 2023, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7  /* Based on dsi_mcux.c, which is (c) 2022 NXP */
8 
9 #define DT_DRV_COMPAT nxp_mipi_dsi_2l
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/mipi_dsi.h>
14 #include <zephyr/drivers/mipi_dsi/mipi_dsi_mcux_2l.h>
15 #include <zephyr/drivers/dma.h>
16 #include <zephyr/drivers/dma/dma_mcux_smartdma.h>
17 #include <zephyr/logging/log.h>
18 
19 #include <fsl_inputmux.h>
20 #include <fsl_mipi_dsi.h>
21 #include <fsl_clock.h>
22 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
23 #include <fsl_smartdma.h>
24 #endif
25 
26 #include <soc.h>
27 
28 LOG_MODULE_REGISTER(dsi_mcux_host, CONFIG_MIPI_DSI_LOG_LEVEL);
29 
30 struct mcux_mipi_dsi_config {
31 	MIPI_DSI_HOST_Type *base;
32 	dsi_dpi_config_t dpi_config;
33 	bool auto_insert_eotp;
34 	bool noncontinuous_hs_clk;
35 	const struct device *bit_clk_dev;
36 	clock_control_subsys_t bit_clk_subsys;
37 	const struct device *esc_clk_dev;
38 	clock_control_subsys_t esc_clk_subsys;
39 	const struct device *pixel_clk_dev;
40 	clock_control_subsys_t pixel_clk_subsys;
41 	uint32_t dphy_ref_freq;
42 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
43 	const struct device *smart_dma;
44 #else
45 	void (*irq_config_func)(const struct device *dev);
46 #endif
47 };
48 
49 struct mcux_mipi_dsi_data {
50 	dsi_handle_t mipi_handle;
51 	struct k_sem transfer_sem;
52 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
53 	smartdma_dsi_param_t smartdma_params __aligned(4);
54 	uint32_t smartdma_stack[32];
55 	uint8_t dma_slot;
56 #endif
57 };
58 
59 
60 /* MAX DSI TX payload */
61 #define DSI_TX_MAX_PAYLOAD_BYTE (64U * 4U)
62 
63 
64 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
65 
66 /* Callback for DSI DMA transfer completion, called in ISR context */
dsi_mcux_dma_cb(const struct device * dma_dev,void * user_data,uint32_t channel,int status)67 static void dsi_mcux_dma_cb(const struct device *dma_dev,
68 				void *user_data, uint32_t channel, int status)
69 {
70 	const struct device *dev = user_data;
71 	const struct mcux_mipi_dsi_config *config = dev->config;
72 	struct mcux_mipi_dsi_data *data = dev->data;
73 	uint32_t int_flags1, int_flags2;
74 
75 	if (status != 0) {
76 		LOG_ERR("SMARTDMA transfer failed");
77 	} else {
78 		/* Disable DSI interrupts at transfer completion */
79 		DSI_DisableInterrupts(config->base, kDSI_InterruptGroup1ApbTxDone |
80 						kDSI_InterruptGroup1HtxTo, 0U);
81 		DSI_GetAndClearInterruptStatus(config->base, &int_flags1, &int_flags2);
82 		k_sem_give(&data->transfer_sem);
83 	}
84 }
85 
86 /* Helper function to transfer DSI color (DMA based implementation) */
dsi_mcux_tx_color(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)87 static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
88 			     struct mipi_dsi_msg *msg)
89 {
90 	/*
91 	 * Color streams are a special case for this DSI peripheral, because
92 	 * the SMARTDMA peripheral (if enabled) can be used to accelerate
93 	 * the transfer of data to the DSI. The SMARTDMA has the additional
94 	 * advantage over traditional DMA of being able to automatically
95 	 * byte swap color data. This is advantageous, as most graphical
96 	 * frameworks store RGB data in little endian format, but many
97 	 * MIPI displays expect color data in big endian format.
98 	 */
99 	const struct mcux_mipi_dsi_config *config = dev->config;
100 	struct mcux_mipi_dsi_data *data = dev->data;
101 	struct dma_config dma_cfg = {0};
102 	int ret;
103 
104 	if (channel != 0) {
105 		return -ENOTSUP; /* DMA can only transfer on virtual channel 0 */
106 	}
107 
108 	/* Configure smartDMA device, and run transfer */
109 	data->smartdma_params.p_buffer = msg->tx_buf;
110 	data->smartdma_params.buffersize = msg->tx_len;
111 
112 	dma_cfg.dma_callback = dsi_mcux_dma_cb;
113 	dma_cfg.user_data = (struct device *)dev;
114 	dma_cfg.head_block = (struct dma_block_config *)&data->smartdma_params;
115 	dma_cfg.block_count = 1;
116 	dma_cfg.dma_slot = data->dma_slot;
117 	dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
118 	ret = dma_config(config->smart_dma, 0, &dma_cfg);
119 	if (ret < 0) {
120 		LOG_ERR("Could not configure SMARTDMA");
121 		return ret;
122 	}
123 	/*
124 	 * SMARTDMA uses DSI interrupt line as input for the DMA
125 	 * transfer trigger. Therefore, we need to enable DSI TX
126 	 * interrupts in order to trigger the DMA engine.
127 	 * Note that if the MIPI IRQ is enabled in
128 	 * the NVIC, it will fire on every SMARTDMA transfer
129 	 */
130 	DSI_EnableInterrupts(config->base, kDSI_InterruptGroup1ApbTxDone |
131 					kDSI_InterruptGroup1HtxTo, 0U);
132 	/* Trigger DMA engine */
133 	ret = dma_start(config->smart_dma, 0);
134 	if (ret < 0) {
135 		LOG_ERR("Could not start SMARTDMA");
136 		return ret;
137 	}
138 	/* Wait for TX completion */
139 	k_sem_take(&data->transfer_sem, K_FOREVER);
140 	return msg->tx_len;
141 }
142 
143 #else /* CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA is not set */
144 
145 /* Callback for DSI transfer completion, called in ISR context */
dsi_transfer_complete(MIPI_DSI_HOST_Type * base,dsi_handle_t * handle,status_t status,void * userData)146 static void dsi_transfer_complete(MIPI_DSI_HOST_Type *base,
147 	dsi_handle_t *handle, status_t status, void *userData)
148 {
149 	struct mcux_mipi_dsi_data *data = userData;
150 
151 	k_sem_give(&data->transfer_sem);
152 }
153 
154 
155 /* Helper function to transfer DSI color (Interrupt based implementation) */
dsi_mcux_tx_color(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)156 static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
157 			     struct mipi_dsi_msg *msg)
158 {
159 	const struct mcux_mipi_dsi_config *config = dev->config;
160 	struct mcux_mipi_dsi_data *data = dev->data;
161 	status_t status;
162 	dsi_transfer_t xfer = {
163 		.virtualChannel = channel,
164 		.txData = msg->tx_buf,
165 		.rxDataSize = (uint16_t)msg->rx_len,
166 		.rxData = msg->rx_buf,
167 		.sendDscCmd = true,
168 		.dscCmd = msg->cmd,
169 		.txDataType = kDSI_TxDataDcsLongWr,
170 		/* default to high speed unless told to use low power */
171 		.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed,
172 	};
173 
174 	/*
175 	 * Cap transfer size. Note that we subtract six bytes here,
176 	 * one for the DSC command and five to insure that
177 	 * transfers are still aligned on a pixel boundary
178 	 * (two or three byte pixel sizes are supported).
179 	 */
180 	xfer.txDataSize = MIN(msg->tx_len, (DSI_TX_MAX_PAYLOAD_BYTE - 6));
181 
182 	if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) {
183 		/* Manually swap the 16 byte color data in software */
184 		uint8_t *src = (uint8_t *)xfer.txData;
185 		uint8_t tmp;
186 
187 		for (uint32_t i = 0; i < xfer.txDataSize; i += 2) {
188 			tmp = src[i];
189 			src[i] = src[i + 1];
190 			src[i + 1] = tmp;
191 		}
192 	}
193 	/* Send TX data using non-blocking DSI API */
194 	status = DSI_TransferNonBlocking(config->base,
195 					&data->mipi_handle, &xfer);
196 	/* Wait for transfer completion */
197 	k_sem_take(&data->transfer_sem, K_FOREVER);
198 	if (status != kStatus_Success) {
199 		LOG_ERR("Transmission failed");
200 		return -EIO;
201 	}
202 	return xfer.txDataSize;
203 }
204 
205 /* ISR is used for DSI interrupt based implementation, unnecessary if DMA is used */
mipi_dsi_isr(const struct device * dev)206 static int mipi_dsi_isr(const struct device *dev)
207 {
208 	const struct mcux_mipi_dsi_config *config = dev->config;
209 	struct mcux_mipi_dsi_data *data = dev->data;
210 
211 	DSI_TransferHandleIRQ(config->base, &data->mipi_handle);
212 	return 0;
213 }
214 
215 #endif
216 
dsi_mcux_attach(const struct device * dev,uint8_t channel,const struct mipi_dsi_device * mdev)217 static int dsi_mcux_attach(const struct device *dev,
218 			   uint8_t channel,
219 			   const struct mipi_dsi_device *mdev)
220 {
221 	const struct mcux_mipi_dsi_config *config = dev->config;
222 	dsi_dphy_config_t dphy_config;
223 	dsi_config_t dsi_config;
224 	uint32_t dphy_bit_clk_freq;
225 	uint32_t dphy_esc_clk_freq;
226 	uint32_t dsi_pixel_clk_freq;
227 	uint32_t bit_width;
228 
229 	DSI_GetDefaultConfig(&dsi_config);
230 	dsi_config.numLanes = mdev->data_lanes;
231 	dsi_config.autoInsertEoTp = config->auto_insert_eotp;
232 	dsi_config.enableNonContinuousHsClk = config->noncontinuous_hs_clk;
233 
234 	imxrt_pre_init_display_interface();
235 
236 	/* Init the DSI module. */
237 	DSI_Init(config->base, &dsi_config);
238 
239 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
240 	/* Connect DSI IRQ line to SMARTDMA trigger via
241 	 * INPUTMUX.
242 	 */
243 	/* Attach INPUTMUX from MIPI to SMARTDMA */
244 	INPUTMUX_Init(INPUTMUX);
245 	INPUTMUX_AttachSignal(INPUTMUX, 0, kINPUTMUX_MipiIrqToSmartDmaInput);
246 	/* Gate inputmux clock to save power */
247 	INPUTMUX_Deinit(INPUTMUX);
248 
249 	if (!device_is_ready(config->smart_dma)) {
250 		return -ENODEV;
251 	}
252 
253 	struct mcux_mipi_dsi_data *data = dev->data;
254 
255 	switch (mdev->pixfmt) {
256 	case MIPI_DSI_PIXFMT_RGB888:
257 		data->dma_slot = kSMARTDMA_MIPI_RGB888_DMA;
258 		data->smartdma_params.disablePixelByteSwap = true;
259 		break;
260 	case MIPI_DSI_PIXFMT_RGB565:
261 		data->dma_slot = kSMARTDMA_MIPI_RGB565_DMA;
262 		if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) {
263 			data->smartdma_params.disablePixelByteSwap = false;
264 		} else {
265 			data->smartdma_params.disablePixelByteSwap = true;
266 		}
267 		break;
268 	default:
269 		LOG_ERR("SMARTDMA does not support pixel_format %u",
270 			mdev->pixfmt);
271 		return -ENODEV;
272 	}
273 
274 	data->smartdma_params.smartdma_stack = data->smartdma_stack;
275 
276 	dma_smartdma_install_fw(config->smart_dma,
277 				(uint8_t *)s_smartdmaDisplayFirmware,
278 				s_smartdmaDisplayFirmwareSize);
279 #else
280 	struct mcux_mipi_dsi_data *data = dev->data;
281 
282 	/* Create transfer handle */
283 	if (DSI_TransferCreateHandle(config->base, &data->mipi_handle,
284 				dsi_transfer_complete, data) != kStatus_Success) {
285 		return -ENODEV;
286 	}
287 #endif
288 
289 	/* Get the DPHY bit clock frequency */
290 	if (clock_control_get_rate(config->bit_clk_dev,
291 				config->bit_clk_subsys,
292 				&dphy_bit_clk_freq)) {
293 		return -EINVAL;
294 	};
295 	/* Get the DPHY ESC clock frequency */
296 	if (clock_control_get_rate(config->esc_clk_dev,
297 				config->esc_clk_subsys,
298 				&dphy_esc_clk_freq)) {
299 		return -EINVAL;
300 	}
301 	/* Get the Pixel clock frequency */
302 	if (clock_control_get_rate(config->pixel_clk_dev,
303 				config->pixel_clk_subsys,
304 				&dsi_pixel_clk_freq)) {
305 		return -EINVAL;
306 	}
307 
308 	switch (config->dpi_config.pixelPacket) {
309 	case kDSI_PixelPacket16Bit:
310 		bit_width = 16;
311 		break;
312 	case kDSI_PixelPacket18Bit:
313 		__fallthrough;
314 	case kDSI_PixelPacket18BitLoosely:
315 		bit_width = 18;
316 		break;
317 	case kDSI_PixelPacket24Bit:
318 		bit_width = 24;
319 		break;
320 	default:
321 		return -EINVAL; /* Invalid bit width enum value? */
322 	}
323 	/* Init DPHY.
324 	 *
325 	 * The DPHY bit clock must be fast enough to send out the pixels, it should be
326 	 * larger than:
327 	 *
328 	 *         (Pixel clock * bit per output pixel) / number of MIPI data lane
329 	 */
330 	if (((dsi_pixel_clk_freq * bit_width) / mdev->data_lanes) > dphy_bit_clk_freq) {
331 		return -EINVAL;
332 	}
333 
334 	DSI_GetDphyDefaultConfig(&dphy_config, dphy_bit_clk_freq, dphy_esc_clk_freq);
335 
336 	if (config->dphy_ref_freq != 0) {
337 		dphy_bit_clk_freq = DSI_InitDphy(config->base,
338 					&dphy_config, config->dphy_ref_freq);
339 	} else {
340 		/* DPHY PLL is not present, ref clock is unused */
341 		DSI_InitDphy(config->base, &dphy_config, 0);
342 	}
343 
344 	/*
345 	 * If nxp,lcdif node is present, then the MIPI DSI driver will
346 	 * accept input on the DPI port from the LCDIF, and convert the output
347 	 * to DSI data. This is useful for video mode, where the LCDIF can
348 	 * constantly refresh the MIPI panel.
349 	 */
350 	if (mdev->mode_flags & MIPI_DSI_MODE_VIDEO) {
351 		/* Init DPI interface. */
352 		DSI_SetDpiConfig(config->base, &config->dpi_config, mdev->data_lanes,
353 						dsi_pixel_clk_freq, dphy_bit_clk_freq);
354 	}
355 
356 	imxrt_post_init_display_interface();
357 
358 	return 0;
359 }
360 
dsi_mcux_detach(const struct device * dev,uint8_t channel,const struct mipi_dsi_device * mdev)361 static int dsi_mcux_detach(const struct device *dev, uint8_t channel,
362 			   const struct mipi_dsi_device *mdev)
363 {
364 	const struct mcux_mipi_dsi_config *config = dev->config;
365 
366 	/* Enable DPHY auto power down */
367 	DSI_DeinitDphy(config->base);
368 	/* Fully power off DPHY */
369 	config->base->PD_DPHY = 0x1;
370 	/* Deinit MIPI */
371 	DSI_Deinit(config->base);
372 	/* Call IMX RT clock function to gate clocks and power at SOC level */
373 	imxrt_deinit_display_interface();
374 	return 0;
375 }
376 
377 
378 
dsi_mcux_transfer(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)379 static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
380 				 struct mipi_dsi_msg *msg)
381 {
382 	const struct mcux_mipi_dsi_config *config = dev->config;
383 	dsi_transfer_t dsi_xfer = {0};
384 	status_t status;
385 	int ret;
386 
387 	dsi_xfer.virtualChannel = channel;
388 	dsi_xfer.txDataSize = msg->tx_len;
389 	dsi_xfer.txData = msg->tx_buf;
390 	dsi_xfer.rxDataSize = msg->rx_len;
391 	dsi_xfer.rxData = msg->rx_buf;
392 	/* default to high speed unless told to use low power */
393 	dsi_xfer.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed;
394 
395 	switch (msg->type) {
396 	case MIPI_DSI_DCS_READ:
397 		LOG_ERR("DCS Read not yet implemented or used");
398 		return -ENOTSUP;
399 	case MIPI_DSI_DCS_SHORT_WRITE:
400 		dsi_xfer.sendDscCmd = true;
401 		dsi_xfer.dscCmd = msg->cmd;
402 		dsi_xfer.txDataType = kDSI_TxDataDcsShortWrNoParam;
403 		break;
404 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
405 		dsi_xfer.sendDscCmd = true;
406 		dsi_xfer.dscCmd = msg->cmd;
407 		dsi_xfer.txDataType = kDSI_TxDataDcsShortWrOneParam;
408 		break;
409 	case MIPI_DSI_DCS_LONG_WRITE:
410 		dsi_xfer.sendDscCmd = true;
411 		dsi_xfer.dscCmd = msg->cmd;
412 		dsi_xfer.txDataType = kDSI_TxDataDcsLongWr;
413 		if (msg->flags & MCUX_DSI_2L_FB_DATA) {
414 			/*
415 			 * Special case- transfer framebuffer data using
416 			 * SMARTDMA or non blocking DSI API. The framebuffer
417 			 * will also be color swapped, if enabled.
418 			 */
419 			ret = dsi_mcux_tx_color(dev, channel, msg);
420 			if (ret < 0) {
421 				LOG_ERR("Transmission failed");
422 				return -EIO;
423 			}
424 			return ret;
425 		}
426 		break;
427 	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
428 		dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam;
429 		break;
430 	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
431 		dsi_xfer.txDataType = kDSI_TxDataGenShortWrOneParam;
432 		break;
433 	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
434 		dsi_xfer.txDataType = kDSI_TxDataGenShortWrTwoParam;
435 		break;
436 	case MIPI_DSI_GENERIC_LONG_WRITE:
437 		dsi_xfer.txDataType = kDSI_TxDataGenLongWr;
438 		break;
439 	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
440 		__fallthrough;
441 	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
442 		__fallthrough;
443 	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
444 		LOG_ERR("Generic Read not yet implemented or used");
445 		return -ENOTSUP;
446 	default:
447 		LOG_ERR("Unsupported message type (%d)", msg->type);
448 		return -ENOTSUP;
449 	}
450 
451 	status = DSI_TransferBlocking(config->base, &dsi_xfer);
452 	if (status != kStatus_Success) {
453 		LOG_ERR("Transmission failed");
454 		return -EIO;
455 	}
456 
457 	if (msg->rx_len != 0) {
458 		/* Return rx_len on a read */
459 		return msg->rx_len;
460 	}
461 
462 	/* Return tx_len on a write */
463 	return msg->tx_len;
464 
465 }
466 
467 static DEVICE_API(mipi_dsi, dsi_mcux_api) = {
468 	.attach = dsi_mcux_attach,
469 	.detach = dsi_mcux_detach,
470 	.transfer = dsi_mcux_transfer,
471 };
472 
mcux_mipi_dsi_init(const struct device * dev)473 static int mcux_mipi_dsi_init(const struct device *dev)
474 {
475 	const struct mcux_mipi_dsi_config *config = dev->config;
476 	struct mcux_mipi_dsi_data *data = dev->data;
477 
478 #ifndef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
479 	/* Enable IRQ */
480 	config->irq_config_func(dev);
481 #endif
482 
483 	k_sem_init(&data->transfer_sem, 0, 1);
484 
485 	if (!device_is_ready(config->bit_clk_dev) ||
486 			!device_is_ready(config->esc_clk_dev) ||
487 			!device_is_ready(config->pixel_clk_dev)) {
488 		return -ENODEV;
489 	}
490 	return 0;
491 }
492 
493 #define MCUX_DSI_DPI_CONFIG(id)									\
494 	IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(id), nxp_lcdif),				\
495 	(.dpi_config = {									\
496 		.dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding),			\
497 		.pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet),				\
498 		.videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode),				\
499 		.bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode),				\
500 		.pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width),		\
501 		.panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height),			\
502 		.polarityFlags = (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),		\
503 					display_timings),  vsync_active) ?			\
504 					kDSI_DpiVsyncActiveHigh :				\
505 					kDSI_DpiVsyncActiveLow) |				\
506 				(DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),		\
507 					display_timings),  hsync_active) ?			\
508 					kDSI_DpiHsyncActiveHigh :				\
509 					kDSI_DpiHsyncActiveLow),				\
510 		.hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
511 					display_timings),  hfront_porch),			\
512 		.hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
513 					display_timings),  hback_porch),			\
514 		.hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
515 					display_timings),  hsync_len),				\
516 		.vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
517 					display_timings),  vfront_porch),			\
518 		.vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
519 					display_timings),  vback_porch),			\
520 	},))
521 
522 #define MCUX_MIPI_DSI_DEVICE(id)								\
523 	COND_CODE_1(CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA,						\
524 	(), (static void mipi_dsi_##n##_irq_config_func(const struct device *dev)		\
525 	{											\
526 		IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority),			\
527 			mipi_dsi_isr, DEVICE_DT_INST_GET(id), 0);				\
528 			irq_enable(DT_INST_IRQN(id));						\
529 	}))											\
530 												\
531 	static const struct mcux_mipi_dsi_config mipi_dsi_config_##id = {			\
532 		MCUX_DSI_DPI_CONFIG(id)								\
533 		COND_CODE_1(CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA,					\
534 		(.smart_dma = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(id, smartdma)),),		\
535 		(.irq_config_func = mipi_dsi_##n##_irq_config_func,))				\
536 		.base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id),				\
537 		.auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp),				\
538 		.noncontinuous_hs_clk = DT_INST_PROP(id, noncontinuous_hs_clk),			\
539 		.dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0),			\
540 		.bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)),		\
541 		.bit_clk_subsys =								\
542 			(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, dphy, name),	\
543 		.esc_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, esc)),		\
544 		.esc_clk_subsys =								\
545 			(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, esc, name),	\
546 		.pixel_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, pixel)),		\
547 		.pixel_clk_subsys =								\
548 			(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, pixel, name),	\
549 	};											\
550 												\
551 	static struct mcux_mipi_dsi_data mipi_dsi_data_##id;					\
552 	DEVICE_DT_INST_DEFINE(id,								\
553 			    &mcux_mipi_dsi_init,						\
554 			    NULL,								\
555 			    &mipi_dsi_data_##id,						\
556 			    &mipi_dsi_config_##id,						\
557 			    POST_KERNEL,							\
558 			    CONFIG_MIPI_DSI_INIT_PRIORITY,					\
559 			    &dsi_mcux_api);
560 
561 DT_INST_FOREACH_STATUS_OKAY(MCUX_MIPI_DSI_DEVICE)
562