1 /*
2  * Copyright 2023, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT himax_hx8394
8 
9 #include <zephyr/drivers/display.h>
10 #include <zephyr/drivers/mipi_dsi.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/logging/log.h>
14 
15 LOG_MODULE_REGISTER(hx8394, CONFIG_DISPLAY_LOG_LEVEL);
16 
17 struct hx8394_config {
18 	const struct device *mipi_dsi;
19 	const struct gpio_dt_spec reset_gpio;
20 	const struct gpio_dt_spec bl_gpio;
21 	uint8_t num_of_lanes;
22 	uint8_t pixel_format;
23 	uint16_t panel_width;
24 	uint16_t panel_height;
25 	uint8_t channel;
26 };
27 
28 /* MIPI DCS commands specific to this display driver */
29 #define HX8394_SETMIPI 0xBA
30 #define HX8394_MIPI_LPTX_BTA_READ BIT(6)
31 #define HX8394_MIPI_LP_CD_DIS BIT(5)
32 #define HX8394_MIPI_TA_6TL 0x3
33 #define HX8394_MIPI_DPHYCMD_LPRX_8NS 0x40
34 #define HX8394_MIPI_DPHYCMD_LPRX_66mV 0x10
35 #define HX8394_MIPI_DPHYCMD_LPTX_SRLIM 0x8
36 #define HX8394_MIPI_DPHYCMD_LDO_1_55V 0x60
37 #define HX8394_MIPI_DPHYCMD_HSRX_7X 0x8
38 #define HX8394_MIPI_DPHYCMD_HSRX_100OHM 0x2
39 #define HX8394_MIPI_DPHYCMD_LPCD_1X 0x1
40 
41 #define HX8394_SET_ADDRESS 0x36
42 #define HX8394_FLIP_HORIZONTAL BIT(1)
43 #define HX8394_FLIP_VERTICAL BIT(0)
44 
45 #define HX8394_SETPOWER 0xB1
46 #define HX8394_POWER_AP_1_0UA 0x8
47 #define HX8394_POWER_HX5186 0x40
48 #define HX8394_POWER_VRHP_4_8V 0x12
49 #define HX8394_POWER_VRHN_4_8V 0x12
50 #define HX8394_POWER_VPPS_8_25V 0x60
51 #define HX8394_POWER_XDK_X2 0x1
52 #define HX8394_POWER_VSP_FBOFF 0x8
53 #define HX8394_POWER_FS0_DIV_8 0x2
54 #define HX8394_POWER_CLK_OPT_VGH_HSYNC_RST 0x10
55 #define HX8394_POWER_CLK_OPT_VGL_HSYNC_RST 0x20
56 #define HX8394_POWER_FS2_DIV_192 0x4
57 #define HX8394_POWER_FS1_DIV_224 0x50
58 #define HX8394_POWER_BTP_5_55V 0x11
59 #define HX8394_POWER_VGH_RATIO_2VSPVSN 0x60
60 #define HX8394_POWER_BTN_5_55V 0x11
61 #define HX8394_POWER_VGL_RATIO_2VSPVSN 0x60
62 #define HX8394_POWER_VGHS_16V 0x57
63 #define HX8394_POWER_VGLS_12_4V 0x47
64 
65 #define HX8394_SETDISP 0xB2
66 #define HX8394_DISP_COL_INV 0x0
67 #define HX8394_DISP_MESSI_ENB 0x80
68 #define HX8394_DISP_NL_1280 0x64
69 #define HX8394_DISP_BP_14 0xC
70 #define HX8394_DISP_FP_15 0xD
71 #define HX8394_DISP_RTN_144 0x2F
72 
73 #define HX8394_SETCYC 0xB4
74 
75 #define HX8394_SETGIP0 0xD3
76 #define HX8394_GIP0_EQ_OPT_BOTH 0x0
77 #define HX8394_GIP0_EQ_HSYNC_NORMAL 0x0
78 #define HX8394_GIP0_EQ_VSEL_VSSA 0x0
79 #define HX8394_SHP_START_4 0x40
80 #define HX8394_SCP_WIDTH_7X_HSYNC 0x7
81 #define HX8394_CHR0_12X_HSYNC 0xA
82 #define HX8394_CHR1_18X_HSYNC 0x10
83 
84 #define HX8394_SETGIP1 0xD5
85 
86 #define HX8394_SETGIP2 0xD6
87 
88 #define HX8394_SETVCOM 0xB6
89 #define HX8394_VCMC_F_1_76V 0x92
90 #define HX8394_VCMC_B_1_76V 0x92
91 
92 #define HX8394_SETGAMMA 0xE0
93 
94 #define HX8394_SETPANEL 0xCC
95 #define HX8394_COLOR_BGR BIT(0)
96 #define HX8394_REV_PANEL BIT(1)
97 
98 #define HX8394_SETBANK 0xBD
99 
100 #define HX8394_SET_TEAR 0x35
101 #define HX8394_TEAR_VBLANK 0x0
102 
103 #define HX8394_SETEXTC 0xB9
104 #define HX8394_EXTC1_MAGIC 0xFF
105 #define HX8394_EXTC2_MAGIC 0x83
106 #define HX8394_EXTC3_MAGIC 0x94
107 
108 
109 const uint8_t enable_extension[] = {
110 	HX8394_SETEXTC,
111 	HX8394_EXTC1_MAGIC,
112 	HX8394_EXTC2_MAGIC,
113 	HX8394_EXTC3_MAGIC,
114 };
115 
116 const uint8_t address_config[] = {
117 	HX8394_SET_ADDRESS,
118 	HX8394_FLIP_HORIZONTAL
119 };
120 
121 const uint8_t power_config[] = {
122 	HX8394_SETPOWER,
123 	(HX8394_POWER_HX5186 | HX8394_POWER_AP_1_0UA),
124 	HX8394_POWER_VRHP_4_8V,
125 	(HX8394_POWER_VPPS_8_25V | HX8394_POWER_VRHN_4_8V),
126 	(HX8394_POWER_VSP_FBOFF | HX8394_POWER_XDK_X2),
127 	(HX8394_POWER_CLK_OPT_VGL_HSYNC_RST |
128 		    HX8394_POWER_CLK_OPT_VGH_HSYNC_RST |
129 		    HX8394_POWER_FS0_DIV_8),
130 	(HX8394_POWER_FS1_DIV_224 | HX8394_POWER_FS2_DIV_192),
131 	(HX8394_POWER_VGH_RATIO_2VSPVSN | HX8394_POWER_BTP_5_55V),
132 	(HX8394_POWER_VGL_RATIO_2VSPVSN | HX8394_POWER_BTN_5_55V),
133 	HX8394_POWER_VGHS_16V,
134 	HX8394_POWER_VGLS_12_4V
135 };
136 
137 const uint8_t line_config[] = {
138 	HX8394_SETDISP,
139 	HX8394_DISP_COL_INV,
140 	HX8394_DISP_MESSI_ENB,
141 	HX8394_DISP_NL_1280,
142 	HX8394_DISP_BP_14,
143 	HX8394_DISP_FP_15,
144 	HX8394_DISP_RTN_144
145 };
146 
147 const uint8_t cycle_config[] = {
148 	HX8394_SETCYC,
149 	0x73, /* SPON delay */
150 	0x74, /* SPOFF delay */
151 	0x73, /* CON delay */
152 	0x74, /* COFF delay */
153 	0x73, /* CON1 delay */
154 	0x74, /* COFF1 delay */
155 	0x1, /* EQON time */
156 	0xC, /* SON time */
157 	0x86, /* SOFF time */
158 	0x75, /* SAP1_P, SAP2 (1st and second stage op amp bias) */
159 	0x00, /* DX2 off, EQ off, EQ_MI off */
160 	0x3F, /* DX2 off period setting */
161 	0x73, /* SPON_MPU delay */
162 	0x74, /* SPOFF_MPU delay */
163 	0x73, /* CON_MPU delay */
164 	0x74, /* COFF_MPU delay */
165 	0x73, /* CON1_MPU delay */
166 	0x74, /* COFF1_MPU delay */
167 	0x1, /* EQON_MPU time */
168 	0xC, /* SON_MPU time */
169 	0x86 /* SOFF_MPU time */
170 };
171 
172 const uint8_t gip0_config[] = {
173 	HX8394_SETGIP0,
174 	(HX8394_GIP0_EQ_OPT_BOTH | HX8394_GIP0_EQ_HSYNC_NORMAL),
175 	HX8394_GIP0_EQ_VSEL_VSSA,
176 	0x7, /* EQ_DELAY_ON1 (in cycles of TCON CLK */
177 	0x7, /* EQ_DELAY_OFF1 (in cycles of TCON CLK */
178 	0x40, /* GPWR signal frequency (64x per frame) */
179 	0x7, /* GPWR signal non overlap timing (in cycles of TCON */
180 	0xC, /* GIP dummy clock for first CKV */
181 	0x00, /* GIP dummy clock for second CKV */
182 	/* Group delays. Sets start/end signal delay from VYSNC
183 	 * falling edge in multiples of HSYNC
184 	 */
185 	0x8, /* SHR0_2 = 8, SHR0_3 = 0 */
186 	0x10, /* SHR0_1 = 1, SHR0[11:8] = 0x0 */
187 	0x8, /* SHR0 = 0x8 */
188 	0x0, /* SHR0_GS[11:8]. Unset. */
189 	0x8, /* SHR0_GS = 0x8 */
190 	0x54, /* SHR1_3 = 0x5, SHR1_2 = 0x4 */
191 	0x15, /* SHR1_1 = 0x1, SHR1[11:8] = 0x5 */
192 	0xA, /* SHR1[7:0] = 0xA (SHR1 = 0x50A) */
193 	0x5, /* SHR1_GS[11:8] = 0x5 */
194 	0xA, /* SHR1_GS[7:0] = 0xA (SHR1_GS = 0x50A) */
195 	0x2, /* SHR2_3 = 0x0, SHR2_2 = 0x2 */
196 	0x15, /* SHR2_1 = 0x1, SHR2[11:8] = 0x5 */
197 	0x6, /* SHR2[7:0] = 0x6 (SHR2 = 0x506) */
198 	0x5, /* SHR2_GS[11:8] = 0x5 */
199 	0x6, /* SHR2_GS[7:0 = 0x6 (SHR2_GS = 0x506) */
200 	(HX8394_SHP_START_4 | HX8394_SCP_WIDTH_7X_HSYNC),
201 	0x44, /* SHP2 = 0x4, SHP1 = 0x4 */
202 	HX8394_CHR0_12X_HSYNC,
203 	HX8394_CHR0_12X_HSYNC,
204 	0x4B, /* CHP0 = 4x hsync, CCP0 = 0xB */
205 	HX8394_CHR1_18X_HSYNC,
206 	0x7, /* CHR1_GS = 9x hsync */
207 	0x7, /* CHP1 = 1x hsync, CCP1 = 0x7 */
208 	/* These parameters are not documented in datasheet */
209 	0xC,
210 	0x40
211 };
212 
213 const uint8_t gip1_config[] = {
214 	HX8394_SETGIP1,
215 	/* Select output clock sources
216 	 * See COSn_L/COSn_R values in datasheet
217 	 */
218 	0x1C, /* COS1_L */
219 	0x1C, /* COS1_R */
220 	0x1D, /* COS2_L */
221 	0x1D, /* COS2_R */
222 	0x00, /* COS3_L */
223 	0x01, /* COS3_R */
224 	0x02, /* COS4_L */
225 	0x03, /* COS4_R */
226 	0x04, /* COS5_L */
227 	0x05, /* COS5_R */
228 	0x06, /* COS6_L */
229 	0x07, /* COS6_R */
230 	0x08, /* COS7_L */
231 	0x09, /* COS7_R */
232 	0x0A, /* COS8_L */
233 	0x0B, /* COS8_R */
234 	0x24, /* COS9_L */
235 	0x25, /* COS9_R */
236 	0x18, /* COS10_L */
237 	0x18, /* COS10_R */
238 	0x26, /* COS11_L */
239 	0x27, /* COS11_R */
240 	0x18, /* COS12_L */
241 	0x18, /* COS12_R */
242 	0x18, /* COS13_L */
243 	0x18, /* COS13_R */
244 	0x18, /* COS14_L */
245 	0x18, /* COS14_R */
246 	0x18, /* COS15_L */
247 	0x18, /* COS15_R */
248 	0x18, /* COS16_L */
249 	0x18, /* COS16_R */
250 	0x18, /* COS17_L */
251 	0x18, /* COS17_R */
252 	0x18, /* COS18_L */
253 	0x18, /* COS18_R */
254 	0x18, /* COS19_L */
255 	0x18, /* COS19_R */
256 	0x20, /* COS20_L */
257 	0x21, /* COS20_R */
258 	0x18, /* COS21_L */
259 	0x18, /* COS21_R */
260 	0x18, /* COS22_L */
261 	0x18 /* COS22_R */
262 };
263 
264 const uint8_t gip2_config[] = {
265 	HX8394_SETGIP2,
266 	/* Select output clock sources for GS mode.
267 	 * See COSn_L_GS/COSn_R_GS values in datasheet
268 	 */
269 	0x1C, /* COS1_L_GS */
270 	0x1C, /* COS1_R_GS */
271 	0x1D, /* COS2_L_GS */
272 	0x1D, /* COS2_R_GS */
273 	0x07, /* COS3_L_GS */
274 	0x06, /* COS3_R_GS */
275 	0x05, /* COS4_L_GS */
276 	0x04, /* COS4_R_GS */
277 	0x03, /* COS5_L_GS */
278 	0x02, /* COS5_R_GS */
279 	0x01, /* COS6_L_GS */
280 	0x00, /* COS6_R_GS */
281 	0x0B, /* COS7_L_GS */
282 	0x0A, /* COS7_R_GS */
283 	0x09, /* COS8_L_GS */
284 	0x08, /* COS8_R_GS */
285 	0x21, /* COS9_L_GS */
286 	0x20, /* COS9_R_GS */
287 	0x18, /* COS10_L_GS */
288 	0x18, /* COS10_R_GS */
289 	0x27, /* COS11_L_GS */
290 	0x26, /* COS11_R_GS */
291 	0x18, /* COS12_L_GS */
292 	0x18, /* COS12_R_GS */
293 	0x18, /* COS13_L_GS */
294 	0x18, /* COS13_R_GS */
295 	0x18, /* COS14_L_GS */
296 	0x18, /* COS14_R_GS */
297 	0x18, /* COS15_L_GS */
298 	0x18, /* COS15_R_GS */
299 	0x18, /* COS16_L_GS */
300 	0x18, /* COS16_R_GS */
301 	0x18, /* COS17_L_GS */
302 	0x18, /* COS17_R_GS */
303 	0x18, /* COS18_L_GS */
304 	0x18, /* COS18_R_GS */
305 	0x18, /* COS19_L_GS */
306 	0x18, /* COS19_R_GS */
307 	0x25, /* COS20_L_GS */
308 	0x24, /* COS20_R_GS */
309 	0x18, /* COS21_L_GS */
310 	0x18, /* COS21_R_GS */
311 	0x18, /* COS22_L_GS */
312 	0x18  /* COS22_R_GS */
313 };
314 
315 const uint8_t vcom_config[] = {
316 	HX8394_SETVCOM,
317 	HX8394_VCMC_F_1_76V,
318 	HX8394_VCMC_B_1_76V
319 };
320 
321 const uint8_t gamma_config[] = {
322 	HX8394_SETGAMMA,
323 	0x00, /* VHP0 */
324 	0x0A, /* VHP1 */
325 	0x15, /* VHP2 */
326 	0x1B, /* VHP3 */
327 	0x1E, /* VHP4 */
328 	0x21, /* VHP5 */
329 	0x24, /* VHP6 */
330 	0x22, /* VHP7 */
331 	0x47, /* VMP0 */
332 	0x56, /* VMP1 */
333 	0x65, /* VMP2 */
334 	0x66, /* VMP3 */
335 	0x6E, /* VMP4 */
336 	0x82, /* VMP5 */
337 	0x88, /* VMP6 */
338 	0x8B, /* VMP7 */
339 	0x9A, /* VMP8 */
340 	0x9D, /* VMP9 */
341 	0x98, /* VMP10 */
342 	0xA8, /* VMP11 */
343 	0xB9, /* VMP12 */
344 	0x5D, /* VLP0 */
345 	0x5C, /* VLP1 */
346 	0x61, /* VLP2 */
347 	0x66, /* VLP3 */
348 	0x6A, /* VLP4 */
349 	0x6F, /* VLP5 */
350 	0x7F, /* VLP6 */
351 	0x7F, /* VLP7 */
352 	0x00, /* VHN0 */
353 	0x0A, /* VHN1 */
354 	0x15, /* VHN2 */
355 	0x1B, /* VHN3 */
356 	0x1E, /* VHN4 */
357 	0x21, /* VHN5 */
358 	0x24, /* VHN6 */
359 	0x22, /* VHN7 */
360 	0x47, /* VMN0 */
361 	0x56, /* VMN1 */
362 	0x65, /* VMN2 */
363 	0x65, /* VMN3 */
364 	0x6E, /* VMN4 */
365 	0x81, /* VMN5 */
366 	0x87, /* VMN6 */
367 	0x8B, /* VMN7 */
368 	0x98, /* VMN8 */
369 	0x9D, /* VMN9 */
370 	0x99, /* VMN10 */
371 	0xA8, /* VMN11 */
372 	0xBA, /* VMN12 */
373 	0x5D, /* VLN0 */
374 	0x5D, /* VLN1 */
375 	0x62, /* VLN2 */
376 	0x67, /* VLN3 */
377 	0x6B, /* VLN4 */
378 	0x72, /* VLN5 */
379 	0x7F, /* VLN6 */
380 	0x7F  /* VLN7 */
381 };
382 
383 const uint8_t hx8394_cmd1[] = {0xC0U, 0x1FU, 0x31U};
384 
385 const uint8_t panel_config[] = {
386 	HX8394_SETPANEL,
387 	(HX8394_COLOR_BGR | HX8394_REV_PANEL)
388 };
389 
390 const uint8_t hx8394_cmd2[] = {0xD4, 0x2};
391 
392 const uint8_t hx8394_bank2[] = {
393 	0xD8U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
394 	0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
395 	0xFFU
396 };
397 
398 const uint8_t hx8394_bank1[] = {0xB1U, 0x00U};
399 
400 const uint8_t hx8394_bank0[] = {
401 	0xBFU, 0x40U, 0x81U, 0x50U,
402 	0x00U, 0x1AU, 0xFCU, 0x01
403 };
404 
405 const uint8_t hx8394_cmd3[] = {0xC6U, 0xEDU};
406 
407 const uint8_t tear_config[] = {HX8394_SET_TEAR, HX8394_TEAR_VBLANK | 0x3};
408 
hx8394_write(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,const void * buf)409 static int hx8394_write(const struct device *dev, const uint16_t x,
410 			 const uint16_t y,
411 			 const struct display_buffer_descriptor *desc,
412 			 const void *buf)
413 {
414 	LOG_WRN("Write not supported, use LCD controller display driver");
415 	return 0;
416 }
417 
hx8394_read(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,void * buf)418 static int hx8394_read(const struct device *dev, const uint16_t x,
419 			const uint16_t y,
420 			const struct display_buffer_descriptor *desc,
421 			void *buf)
422 {
423 	LOG_WRN("Read not implemented");
424 	return -ENOTSUP;
425 }
426 
hx8394_get_framebuffer(const struct device * dev)427 static void *hx8394_get_framebuffer(const struct device *dev)
428 {
429 	LOG_WRN("Direct framebuffer access not implemented");
430 	return NULL;
431 }
432 
hx8394_blanking_off(const struct device * dev)433 static int hx8394_blanking_off(const struct device *dev)
434 {
435 	const struct hx8394_config *config = dev->config;
436 
437 	if (config->bl_gpio.port != NULL) {
438 		return gpio_pin_set_dt(&config->bl_gpio, 1);
439 	} else {
440 		return -ENOTSUP;
441 	}
442 }
443 
hx8394_blanking_on(const struct device * dev)444 static int hx8394_blanking_on(const struct device *dev)
445 {
446 	const struct hx8394_config *config = dev->config;
447 
448 	if (config->bl_gpio.port != NULL) {
449 		return gpio_pin_set_dt(&config->bl_gpio, 0);
450 	} else {
451 		return -ENOTSUP;
452 	}
453 }
454 
hx8394_set_brightness(const struct device * dev,const uint8_t brightness)455 static int hx8394_set_brightness(const struct device *dev,
456 				  const uint8_t brightness)
457 {
458 	LOG_WRN("Set brightness not implemented");
459 	return -ENOTSUP;
460 }
461 
hx8394_set_contrast(const struct device * dev,const uint8_t contrast)462 static int hx8394_set_contrast(const struct device *dev,
463 				const uint8_t contrast)
464 {
465 	LOG_WRN("Set contrast not implemented");
466 	return -ENOTSUP;
467 }
468 
hx8394_set_pixel_format(const struct device * dev,const enum display_pixel_format pixel_format)469 static int hx8394_set_pixel_format(const struct device *dev,
470 				    const enum display_pixel_format pixel_format)
471 {
472 	const struct hx8394_config *config = dev->config;
473 
474 	if (pixel_format == config->pixel_format) {
475 		return 0;
476 	}
477 	LOG_WRN("Pixel format change not implemented");
478 	return -ENOTSUP;
479 }
480 
hx8394_set_orientation(const struct device * dev,const enum display_orientation orientation)481 static int hx8394_set_orientation(const struct device *dev,
482 				   const enum display_orientation orientation)
483 {
484 	const struct hx8394_config *config = dev->config;
485 	uint8_t param[2] = {0};
486 
487 	/* Note- this simply flips the scan direction of the display
488 	 * driver. Can be useful if your application needs the display
489 	 * flipped on the X or Y axis
490 	 */
491 	param[0] = HX8394_SET_ADDRESS;
492 	switch (orientation) {
493 	case DISPLAY_ORIENTATION_NORMAL:
494 		/* Default orientation for this display flips image on x axis */
495 		param[1] = HX8394_FLIP_HORIZONTAL;
496 		break;
497 	case DISPLAY_ORIENTATION_ROTATED_90:
498 		param[1] = HX8394_FLIP_VERTICAL;
499 		break;
500 	case DISPLAY_ORIENTATION_ROTATED_180:
501 		param[1] = 0;
502 		break;
503 	case DISPLAY_ORIENTATION_ROTATED_270:
504 		param[1] = HX8394_FLIP_HORIZONTAL | HX8394_FLIP_VERTICAL;
505 		break;
506 	default:
507 		return -ENOTSUP;
508 	}
509 	return mipi_dsi_generic_write(config->mipi_dsi, config->channel, param, 2);
510 }
511 
hx8394_get_capabilities(const struct device * dev,struct display_capabilities * capabilities)512 static void hx8394_get_capabilities(const struct device *dev,
513 				     struct display_capabilities *capabilities)
514 {
515 	const struct hx8394_config *config = dev->config;
516 
517 	memset(capabilities, 0, sizeof(struct display_capabilities));
518 	capabilities->x_resolution = config->panel_width;
519 	capabilities->y_resolution = config->panel_height;
520 	capabilities->supported_pixel_formats = config->pixel_format;
521 	capabilities->current_pixel_format = config->pixel_format;
522 	capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL;
523 }
524 
525 static const struct display_driver_api hx8394_api = {
526 	.blanking_on = hx8394_blanking_on,
527 	.blanking_off = hx8394_blanking_off,
528 	.write = hx8394_write,
529 	.read = hx8394_read,
530 	.get_framebuffer = hx8394_get_framebuffer,
531 	.set_brightness = hx8394_set_brightness,
532 	.set_contrast = hx8394_set_contrast,
533 	.get_capabilities = hx8394_get_capabilities,
534 	.set_pixel_format = hx8394_set_pixel_format,
535 	.set_orientation = hx8394_set_orientation,
536 };
537 
hx8394_init(const struct device * dev)538 static int hx8394_init(const struct device *dev)
539 {
540 	const struct hx8394_config *config = dev->config;
541 	int ret;
542 	struct mipi_dsi_device mdev;
543 	uint8_t param[2];
544 	uint8_t setmipi[7] = {
545 		HX8394_SETMIPI,
546 		(HX8394_MIPI_LPTX_BTA_READ | HX8394_MIPI_LP_CD_DIS),
547 		HX8394_MIPI_TA_6TL,
548 		(HX8394_MIPI_DPHYCMD_LPRX_8NS |
549 		 HX8394_MIPI_DPHYCMD_LPRX_66mV |
550 		 HX8394_MIPI_DPHYCMD_LPTX_SRLIM),
551 		(HX8394_MIPI_DPHYCMD_LDO_1_55V |
552 		HX8394_MIPI_DPHYCMD_HSRX_7X |
553 		HX8394_MIPI_DPHYCMD_HSRX_100OHM |
554 		HX8394_MIPI_DPHYCMD_LPCD_1X),
555 		/* The remaining parameters here are not documented */
556 		0xB2U, 0xC0U};
557 
558 	mdev.data_lanes = config->num_of_lanes;
559 	mdev.pixfmt = config->pixel_format;
560 	/* HX8394 runs in video mode */
561 	mdev.mode_flags = MIPI_DSI_MODE_VIDEO;
562 
563 	ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev);
564 	if (ret < 0) {
565 		LOG_ERR("Could not attach to MIPI-DSI host");
566 		return ret;
567 	}
568 
569 	if (gpio_is_ready_dt(&config->reset_gpio)) {
570 		/* Regulator API will have supplied power to the display
571 		 * driver. Per datasheet, we must wait 1ms for the RESX
572 		 * pin to be valid.
573 		 */
574 		k_sleep(K_MSEC(1));
575 		/* Initialize reset GPIO */
576 		ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
577 		if (ret < 0) {
578 			return ret;
579 		}
580 		/* Pull reset GPIO low */
581 		gpio_pin_set_dt(&config->reset_gpio, 0);
582 		/* Datasheet says we must keep reset pin low at least 10us.
583 		 * hold it low for 1ms to be safe.
584 		 */
585 		k_sleep(K_MSEC(1));
586 		gpio_pin_set_dt(&config->reset_gpio, 1);
587 		/* Per datasheet, we must delay at least 50ms before first
588 		 * host command
589 		 */
590 		k_sleep(K_MSEC(50));
591 	}
592 	/* Enable extended commands */
593 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
594 			enable_extension, sizeof(enable_extension));
595 	if (ret < 0) {
596 		return ret;
597 	}
598 
599 	/* Set the number of lanes to DSISETUP0 parameter */
600 	setmipi[1] |= (config->num_of_lanes - 1);
601 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
602 				setmipi, sizeof(setmipi));
603 	if (ret < 0) {
604 		return ret;
605 	}
606 
607 	/* Set scan direction */
608 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
609 			address_config, sizeof(address_config));
610 	if (ret < 0) {
611 		return ret;
612 	}
613 
614 	/* Set voltage and current targets */
615 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
616 			power_config, sizeof(power_config));
617 	if (ret < 0) {
618 		return ret;
619 	}
620 
621 	/* Setup display line count and front/back porch size */
622 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
623 			line_config, sizeof(line_config));
624 	if (ret < 0) {
625 		return ret;
626 	}
627 
628 	/* Setup display cycle counts (in counts of TCON CLK) */
629 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
630 			cycle_config, sizeof(cycle_config));
631 	if (ret < 0) {
632 		return ret;
633 	}
634 
635 	/* Set group delay values */
636 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
637 			gip0_config, sizeof(gip0_config));
638 	if (ret < 0) {
639 		return ret;
640 	}
641 
642 
643 	/* Set group clock selections */
644 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
645 			gip1_config, sizeof(gip1_config));
646 	if (ret < 0) {
647 		return ret;
648 	}
649 
650 	/* Set group clock selections for GS mode */
651 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
652 			gip2_config, sizeof(gip2_config));
653 	if (ret < 0) {
654 		return ret;
655 	}
656 
657 	/* Delay for a moment before setting VCOM. It is not clear
658 	 * from the datasheet why this is required, but without this
659 	 * delay the panel stops responding to additional commands
660 	 */
661 	k_msleep(1);
662 	/* Set VCOM voltage config */
663 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
664 			vcom_config, sizeof(vcom_config));
665 	if (ret < 0) {
666 		return ret;
667 	}
668 
669 	/* Set manufacturer supplied gamma values */
670 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
671 			gamma_config, sizeof(gamma_config));
672 	if (ret < 0) {
673 		return ret;
674 	}
675 
676 	/* This command is not documented in datasheet, but is included
677 	 * in the display initialization done by MCUXpresso SDK
678 	 */
679 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
680 			hx8394_cmd1, sizeof(hx8394_cmd1));
681 	if (ret < 0) {
682 		return ret;
683 	}
684 
685 	/* Set panel to BGR mode, and reverse colors */
686 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
687 			panel_config, sizeof(panel_config));
688 	if (ret < 0) {
689 		return ret;
690 	}
691 
692 	/* This command is not documented in datasheet, but is included
693 	 * in the display initialization done by MCUXpresso SDK
694 	 */
695 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
696 			hx8394_cmd2, sizeof(hx8394_cmd2));
697 	if (ret < 0) {
698 		return ret;
699 	}
700 
701 	/* Write values to manufacturer register banks */
702 	param[0] = HX8394_SETBANK;
703 	param[1] = 0x2;
704 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
705 			param, 2);
706 	if (ret < 0) {
707 		return ret;
708 	}
709 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
710 			hx8394_bank2, sizeof(hx8394_bank2));
711 	if (ret < 0) {
712 		return ret;
713 	}
714 	param[1] = 0x0;
715 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
716 			param, 2);
717 	if (ret < 0) {
718 		return ret;
719 	}
720 	/* Select bank 1 */
721 	param[1] = 0x1;
722 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
723 			param, 2);
724 	if (ret < 0) {
725 		return ret;
726 	}
727 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
728 			hx8394_bank1, sizeof(hx8394_bank1));
729 	if (ret < 0) {
730 		return ret;
731 	}
732 	/* Select bank 0 */
733 	param[1] = 0x0;
734 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
735 			param, 2);
736 	if (ret < 0) {
737 		return ret;
738 	}
739 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
740 			hx8394_bank0, sizeof(hx8394_bank0));
741 	if (ret < 0) {
742 		return ret;
743 	}
744 
745 	/* This command is not documented in datasheet, but is included
746 	 * in the display initialization done by MCUXpresso SDK
747 	 */
748 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
749 			hx8394_cmd3, sizeof(hx8394_cmd3));
750 	if (ret < 0) {
751 		return ret;
752 	}
753 
754 	ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel,
755 			tear_config, sizeof(tear_config));
756 	if (ret < 0) {
757 		return ret;
758 	}
759 
760 	ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel,
761 				MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
762 	if (ret < 0) {
763 		return ret;
764 	}
765 	/* We must delay 120ms after exiting sleep mode per datasheet */
766 	k_sleep(K_MSEC(120));
767 	ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel,
768 				MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
769 
770 	if (config->bl_gpio.port != NULL) {
771 		ret = gpio_pin_configure_dt(&config->bl_gpio, GPIO_OUTPUT_ACTIVE);
772 		if (ret < 0) {
773 			LOG_ERR("Could not configure bl GPIO (%d)", ret);
774 			return ret;
775 		}
776 	}
777 
778 	return ret;
779 }
780 
781 #define HX8394_PANEL(id)							\
782 	static const struct hx8394_config hx8394_config_##id = {		\
783 		.mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(id)),			\
784 		.reset_gpio = GPIO_DT_SPEC_INST_GET_OR(id, reset_gpios, {0}),	\
785 		.bl_gpio = GPIO_DT_SPEC_INST_GET_OR(id, bl_gpios, {0}),		\
786 		.num_of_lanes = DT_INST_PROP_BY_IDX(id, data_lanes, 0),		\
787 		.pixel_format = DT_INST_PROP(id, pixel_format),			\
788 		.panel_width = DT_INST_PROP(id, width),				\
789 		.panel_height = DT_INST_PROP(id, height),			\
790 		.channel = DT_INST_REG_ADDR(id),				\
791 	};									\
792 	DEVICE_DT_INST_DEFINE(id,						\
793 			    &hx8394_init,					\
794 			    NULL,						\
795 			    NULL,						\
796 			    &hx8394_config_##id,				\
797 			    POST_KERNEL,					\
798 			    CONFIG_APPLICATION_INIT_PRIORITY,			\
799 			    &hx8394_api);
800 
801 DT_INST_FOREACH_STATUS_OKAY(HX8394_PANEL)
802