xref: /linux/drivers/gpu/drm/panel/panel-himax-hx8394.c (revision fb7399cf2d0b33825b8039f95c45395c7deba25c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for panels based on Himax HX8394 controller, such as:
4  *
5  * - HannStar HSD060BHW4 5.99" MIPI-DSI panel
6  *
7  * Copyright (C) 2021 Kamil Trzciński
8  *
9  * Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c
10  * Copyright (C) Purism SPC 2019
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/media-bus-format.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/regulator/consumer.h>
20 
21 #include <video/mipi_display.h>
22 
23 #include <drm/drm_mipi_dsi.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_panel.h>
26 
27 #define DRV_NAME "panel-himax-hx8394"
28 
29 /* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */
30 #define HX8394_CMD_SETSEQUENCE	  0xb0
31 #define HX8394_CMD_SETPOWER	  0xb1
32 #define HX8394_CMD_SETDISP	  0xb2
33 #define HX8394_CMD_SETCYC	  0xb4
34 #define HX8394_CMD_SETVCOM	  0xb6
35 #define HX8394_CMD_SETTE	  0xb7
36 #define HX8394_CMD_SETSENSOR	  0xb8
37 #define HX8394_CMD_SETEXTC	  0xb9
38 #define HX8394_CMD_SETMIPI	  0xba
39 #define HX8394_CMD_SETOTP	  0xbb
40 #define HX8394_CMD_SETREGBANK	  0xbd
41 #define HX8394_CMD_UNKNOWN5	  0xbf
42 #define HX8394_CMD_UNKNOWN1	  0xc0
43 #define HX8394_CMD_SETDGCLUT	  0xc1
44 #define HX8394_CMD_SETID	  0xc3
45 #define HX8394_CMD_SETDDB	  0xc4
46 #define HX8394_CMD_UNKNOWN2	  0xc6
47 #define HX8394_CMD_SETCABC	  0xc9
48 #define HX8394_CMD_SETCABCGAIN	  0xca
49 #define HX8394_CMD_SETPANEL	  0xcc
50 #define HX8394_CMD_SETOFFSET	  0xd2
51 #define HX8394_CMD_SETGIP0	  0xd3
52 #define HX8394_CMD_UNKNOWN3	  0xd4
53 #define HX8394_CMD_SETGIP1	  0xd5
54 #define HX8394_CMD_SETGIP2	  0xd6
55 #define HX8394_CMD_SETGPO	  0xd6
56 #define HX8394_CMD_UNKNOWN4	  0xd8
57 #define HX8394_CMD_SETSCALING	  0xdd
58 #define HX8394_CMD_SETIDLE	  0xdf
59 #define HX8394_CMD_SETGAMMA	  0xe0
60 #define HX8394_CMD_SETCHEMODE_DYN 0xe4
61 #define HX8394_CMD_SETCHE	  0xe5
62 #define HX8394_CMD_SETCESEL	  0xe6
63 #define HX8394_CMD_SET_SP_CMD	  0xe9
64 #define HX8394_CMD_SETREADINDEX	  0xfe
65 #define HX8394_CMD_GETSPIREAD	  0xff
66 
67 struct hx8394 {
68 	struct device *dev;
69 	struct drm_panel panel;
70 	struct gpio_desc *reset_gpio;
71 	struct regulator *vcc;
72 	struct regulator *iovcc;
73 	enum drm_panel_orientation orientation;
74 
75 	const struct hx8394_panel_desc *desc;
76 };
77 
78 struct hx8394_panel_desc {
79 	const struct drm_display_mode *mode;
80 	unsigned int lanes;
81 	unsigned long mode_flags;
82 	enum mipi_dsi_pixel_format format;
83 	void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
84 };
85 
86 static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
87 {
88 	return container_of(panel, struct hx8394, panel);
89 }
90 
91 static void hsd060bhw4_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
92 {
93 	/* 5.19.8 SETEXTC: Set extension command (B9h) */
94 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
95 				     0xff, 0x83, 0x94);
96 
97 	/* 5.19.2 SETPOWER: Set power (B1h) */
98 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
99 				     0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
100 
101 	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
102 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI,
103 				     0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
104 
105 	/* 5.19.3 SETDISP: Set display related register (B2h) */
106 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
107 				     0x00, 0x80, 0x78, 0x0c, 0x07);
108 
109 	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
110 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
111 				     0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55,
112 				     0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c,
113 				     0x7c);
114 
115 	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
116 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
117 				     0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10,
118 				     0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00,
119 				     0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00,
120 				     0x00, 0x0c, 0x40);
121 
122 	/* 5.19.20 Set GIP Option1 (D5h) */
123 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
124 				     0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01,
125 				     0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18,
126 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
127 				     0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
128 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
129 
130 	/* 5.19.21 Set GIP Option2 (D6h) */
131 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
132 				     0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06,
133 				     0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18,
134 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
135 				     0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
136 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
137 
138 	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
139 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
140 				     0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f,
141 				     0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a,
142 				     0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00,
143 				     0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31,
144 				     0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f,
145 				     0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b,
146 				     0x4a, 0x4c, 0x4b, 0x7f);
147 
148 	/* 5.19.17 SETPANEL (CCh) */
149 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
150 				     0x0b);
151 
152 	/* Unknown command, not listed in the HX8394-F datasheet */
153 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1,
154 				     0x1f, 0x31);
155 
156 	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
157 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
158 				     0x7d, 0x7d);
159 
160 	/* Unknown command, not listed in the HX8394-F datasheet */
161 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
162 				     0x02);
163 
164 	/* 5.19.11 Set register bank (BDh) */
165 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
166 				     0x01);
167 
168 	/* 5.19.2 SETPOWER: Set power (B1h) */
169 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
170 				     0x00);
171 
172 	/* 5.19.11 Set register bank (BDh) */
173 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
174 				     0x00);
175 
176 	/* Unknown command, not listed in the HX8394-F datasheet */
177 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
178 				     0xed);
179 }
180 
181 static const struct drm_display_mode hsd060bhw4_mode = {
182 	.hdisplay    = 720,
183 	.hsync_start = 720 + 40,
184 	.hsync_end   = 720 + 40 + 46,
185 	.htotal	     = 720 + 40 + 46 + 40,
186 	.vdisplay    = 1440,
187 	.vsync_start = 1440 + 9,
188 	.vsync_end   = 1440 + 9 + 7,
189 	.vtotal	     = 1440 + 9 + 7 + 7,
190 	.clock	     = 74250,
191 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
192 	.width_mm    = 68,
193 	.height_mm   = 136,
194 };
195 
196 static const struct hx8394_panel_desc hsd060bhw4_desc = {
197 	.mode = &hsd060bhw4_mode,
198 	.lanes = 4,
199 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
200 	.format = MIPI_DSI_FMT_RGB888,
201 	.init_sequence = hsd060bhw4_init_sequence,
202 };
203 
204 static void powkiddy_x55_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
205 {
206 	/* 5.19.8 SETEXTC: Set extension command (B9h) */
207 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
208 				     0xff, 0x83, 0x94);
209 
210 	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
211 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI,
212 				     0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
213 
214 	/* 5.19.2 SETPOWER: Set power (B1h) */
215 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
216 				     0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47);
217 
218 	/* 5.19.3 SETDISP: Set display related register (B2h) */
219 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
220 				     0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f);
221 
222 	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
223 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
224 				     0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75,
225 				     0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c,
226 				     0x86);
227 
228 	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
229 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
230 				     0x6e, 0x6e);
231 
232 	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
233 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
234 				     0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10,
235 				     0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15,
236 				     0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07,
237 				     0x07, 0x0c, 0x40);
238 
239 	/* 5.19.20 Set GIP Option1 (D5h) */
240 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
241 				     0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
242 				     0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18,
243 				     0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
244 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21,
245 				     0x18, 0x18, 0x18, 0x18);
246 
247 	/* 5.19.21 Set GIP Option2 (D6h) */
248 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
249 				     0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
250 				     0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18,
251 				     0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
252 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24,
253 				     0x18, 0x18, 0x18, 0x18);
254 
255 	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
256 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
257 				     0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56,
258 				     0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8,
259 				     0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00,
260 				     0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65,
261 				     0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba,
262 				     0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f);
263 
264 	/* Unknown command, not listed in the HX8394-F datasheet */
265 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1,
266 				     0x1f, 0x31);
267 
268 	/* 5.19.17 SETPANEL (CCh) */
269 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
270 				     0x0b);
271 
272 	/* Unknown command, not listed in the HX8394-F datasheet */
273 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
274 				     0x02);
275 
276 	/* 5.19.11 Set register bank (BDh) */
277 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
278 				     0x02);
279 
280 	/* Unknown command, not listed in the HX8394-F datasheet */
281 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
282 				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
283 				     0xff, 0xff);
284 
285 	/* 5.19.11 Set register bank (BDh) */
286 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
287 				     0x00);
288 
289 	/* 5.19.11 Set register bank (BDh) */
290 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
291 				     0x01);
292 
293 	/* 5.19.2 SETPOWER: Set power (B1h) */
294 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
295 				     0x00);
296 
297 	/* 5.19.11 Set register bank (BDh) */
298 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
299 				     0x00);
300 
301 	/* Unknown command, not listed in the HX8394-F datasheet */
302 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN5,
303 				     0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01);
304 
305 	/* Unknown command, not listed in the HX8394-F datasheet */
306 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2,
307 				     0xed);
308 }
309 
310 static const struct drm_display_mode powkiddy_x55_mode = {
311 	.hdisplay	= 720,
312 	.hsync_start	= 720 + 44,
313 	.hsync_end	= 720 + 44 + 20,
314 	.htotal		= 720 + 44 + 20 + 20,
315 	.vdisplay	= 1280,
316 	.vsync_start	= 1280 + 12,
317 	.vsync_end	= 1280 + 12 + 10,
318 	.vtotal		= 1280 + 12 + 10 + 10,
319 	.clock		= 63290,
320 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
321 	.width_mm	= 67,
322 	.height_mm	= 121,
323 };
324 
325 static const struct hx8394_panel_desc powkiddy_x55_desc = {
326 	.mode = &powkiddy_x55_mode,
327 	.lanes = 4,
328 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
329 		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
330 	.format = MIPI_DSI_FMT_RGB888,
331 	.init_sequence = powkiddy_x55_init_sequence,
332 };
333 
334 static void mchp_ac40t08a_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
335 {
336 	/* DCS commands do not seem to be sent correclty without this delay */
337 	mipi_dsi_msleep(dsi_ctx, 20);
338 
339 	/* 5.19.8 SETEXTC: Set extension command (B9h) */
340 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
341 				     0xff, 0x83, 0x94);
342 
343 	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
344 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI,
345 				     0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
346 
347 	/* 5.19.2 SETPOWER: Set power (B1h) */
348 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
349 				     0x48, 0x12, 0x72, 0x09, 0x32, 0x54,
350 				     0x71, 0x71, 0x57, 0x47);
351 
352 	/* 5.19.3 SETDISP: Set display related register (B2h) */
353 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
354 				     0x00, 0x80, 0x64, 0x0c, 0x0d, 0x2f);
355 
356 	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
357 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
358 				     0x73, 0x74, 0x73, 0x74, 0x73, 0x74,
359 				     0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f,
360 				     0x73, 0x74, 0x73, 0x74, 0x73, 0x74,
361 				     0x01, 0x0c, 0x86);
362 
363 	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
364 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
365 				     0x6e, 0x6e);
366 
367 	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
368 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
369 				     0x00, 0x00, 0x07, 0x07, 0x40, 0x07,
370 				     0x0c, 0x00, 0x08, 0x10, 0x08, 0x00,
371 				     0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a,
372 				     0x02, 0x15, 0x06, 0x05, 0x06, 0x47,
373 				     0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07,
374 				     0x07, 0x0c, 0x40);
375 
376 	/* 5.19.20 Set GIP Option1 (D5h) */
377 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
378 				     0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01,
379 				     0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
380 				     0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25,
381 				     0x18, 0x18, 0x26, 0x27, 0x18, 0x18,
382 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
383 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
384 				     0x18, 0x18, 0x20, 0x21, 0x18, 0x18,
385 				     0x18, 0x18);
386 
387 	/* 5.19.21 Set GIP Option2 (D6h) */
388 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
389 				     0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06,
390 				     0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
391 				     0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20,
392 				     0x18, 0x18, 0x27, 0x26, 0x18, 0x18,
393 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
394 				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
395 				     0x18, 0x18, 0x25, 0x24, 0x18, 0x18,
396 				     0x18, 0x18);
397 
398 	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
399 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
400 				     0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21,
401 				     0x24, 0x22, 0x47, 0x56, 0x65, 0x66,
402 				     0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d,
403 				     0x98, 0xa8, 0xb9, 0x5d, 0x5c, 0x61,
404 				     0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00,
405 				     0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24,
406 				     0x22, 0x47, 0x56, 0x65, 0x65, 0x6e,
407 				     0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99,
408 				     0xa8, 0xba, 0x5d, 0x5d, 0x62, 0x67,
409 				     0x6b, 0x72, 0x7f, 0x7f);
410 
411 	/* Unknown command, not listed in the HX8394-F datasheet (C0H) */
412 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1,
413 				     0x1f, 0x73);
414 
415 	/* Set CABC control (C9h)*/
416 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCABC,
417 				     0x76, 0x00, 0x30);
418 
419 	/* 5.19.17 SETPANEL (CCh) */
420 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
421 				     0x0b);
422 
423 	/* Unknown command, not listed in the HX8394-F datasheet (D4h) */
424 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
425 				     0x02);
426 
427 	/* 5.19.11 Set register bank (BDh) */
428 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
429 				     0x02);
430 
431 	/* 5.19.11 Set register bank (D8h) */
432 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
433 				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
434 				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
435 
436 	/* 5.19.11 Set register bank (BDh) */
437 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
438 				     0x00);
439 
440 	/* 5.19.11 Set register bank (BDh) */
441 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
442 				     0x01);
443 
444 	/* 5.19.2 SETPOWER: Set power (B1h) */
445 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
446 				     0x00);
447 
448 	/* 5.19.11 Set register bank (BDh) */
449 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
450 				     0x00);
451 
452 	/* Unknown command, not listed in the HX8394-F datasheet (C6h) */
453 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2,
454 				     0xed);
455 }
456 
457 static const struct drm_display_mode mchp_ac40t08a_mode = {
458 	.hdisplay    = 720,
459 	.hsync_start = 720 + 12,
460 	.hsync_end   = 720 + 12 + 24,
461 	.htotal	     = 720 + 12 + 12 + 24,
462 	.vdisplay    = 1280,
463 	.vsync_start = 1280 + 13,
464 	.vsync_end   = 1280 + 14,
465 	.vtotal	     = 1280 + 14 + 13,
466 	.clock	     = 60226,
467 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
468 	.width_mm    = 76,
469 	.height_mm   = 132,
470 };
471 
472 static const struct hx8394_panel_desc mchp_ac40t08a_desc = {
473 	.mode = &mchp_ac40t08a_mode,
474 	.lanes = 4,
475 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
476 	.format = MIPI_DSI_FMT_RGB888,
477 	.init_sequence = mchp_ac40t08a_init_sequence,
478 };
479 
480 static int hx8394_enable(struct drm_panel *panel)
481 {
482 	struct hx8394 *ctx = panel_to_hx8394(panel);
483 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
484 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
485 	int ret;
486 
487 	ctx->desc->init_sequence(&dsi_ctx);
488 
489 	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
490 
491 	if (dsi_ctx.accum_err)
492 		return dsi_ctx.accum_err;
493 	/* Panel is operational 120 msec after reset */
494 	msleep(120);
495 
496 	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
497 	if (dsi_ctx.accum_err)
498 		goto sleep_in;
499 
500 	return 0;
501 
502 sleep_in:
503 	ret = dsi_ctx.accum_err;
504 	dsi_ctx.accum_err = 0;
505 
506 	/* This will probably fail, but let's try orderly power off anyway. */
507 	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
508 	mipi_dsi_msleep(&dsi_ctx, 50);
509 
510 	return ret;
511 }
512 
513 static int hx8394_disable(struct drm_panel *panel)
514 {
515 	struct hx8394 *ctx = panel_to_hx8394(panel);
516 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
517 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
518 
519 	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
520 	mipi_dsi_msleep(&dsi_ctx, 50); /* about 3 frames */
521 
522 	return dsi_ctx.accum_err;
523 }
524 
525 static int hx8394_unprepare(struct drm_panel *panel)
526 {
527 	struct hx8394 *ctx = panel_to_hx8394(panel);
528 
529 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
530 
531 	regulator_disable(ctx->iovcc);
532 	regulator_disable(ctx->vcc);
533 
534 	return 0;
535 }
536 
537 static int hx8394_prepare(struct drm_panel *panel)
538 {
539 	struct hx8394 *ctx = panel_to_hx8394(panel);
540 	int ret;
541 
542 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
543 
544 	ret = regulator_enable(ctx->vcc);
545 	if (ret) {
546 		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
547 		return ret;
548 	}
549 
550 	ret = regulator_enable(ctx->iovcc);
551 	if (ret) {
552 		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
553 		goto disable_vcc;
554 	}
555 
556 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
557 
558 	msleep(180);
559 
560 	return 0;
561 
562 disable_vcc:
563 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
564 	regulator_disable(ctx->vcc);
565 	return ret;
566 }
567 
568 static int hx8394_get_modes(struct drm_panel *panel,
569 			    struct drm_connector *connector)
570 {
571 	struct hx8394 *ctx = panel_to_hx8394(panel);
572 	struct drm_display_mode *mode;
573 
574 	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
575 	if (!mode) {
576 		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
577 			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
578 			drm_mode_vrefresh(ctx->desc->mode));
579 		return -ENOMEM;
580 	}
581 
582 	drm_mode_set_name(mode);
583 
584 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
585 	connector->display_info.width_mm = mode->width_mm;
586 	connector->display_info.height_mm = mode->height_mm;
587 	drm_mode_probed_add(connector, mode);
588 
589 	return 1;
590 }
591 
592 static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel)
593 {
594 	struct hx8394 *ctx = panel_to_hx8394(panel);
595 
596 	return ctx->orientation;
597 }
598 
599 static const struct drm_panel_funcs hx8394_drm_funcs = {
600 	.disable   = hx8394_disable,
601 	.unprepare = hx8394_unprepare,
602 	.prepare   = hx8394_prepare,
603 	.enable	   = hx8394_enable,
604 	.get_modes = hx8394_get_modes,
605 	.get_orientation = hx8394_get_orientation,
606 };
607 
608 static int hx8394_probe(struct mipi_dsi_device *dsi)
609 {
610 	struct device *dev = &dsi->dev;
611 	struct hx8394 *ctx;
612 	int ret;
613 
614 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
615 	if (!ctx)
616 		return -ENOMEM;
617 
618 	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
619 	if (IS_ERR(ctx->reset_gpio))
620 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
621 				     "Failed to get reset gpio\n");
622 
623 	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
624 	if (ret < 0) {
625 		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
626 		return ret;
627 	}
628 
629 	mipi_dsi_set_drvdata(dsi, ctx);
630 
631 	ctx->dev = dev;
632 	ctx->desc = of_device_get_match_data(dev);
633 
634 	dsi->mode_flags = ctx->desc->mode_flags;
635 	dsi->format = ctx->desc->format;
636 	dsi->lanes = ctx->desc->lanes;
637 
638 	ctx->vcc = devm_regulator_get(dev, "vcc");
639 	if (IS_ERR(ctx->vcc))
640 		return dev_err_probe(dev, PTR_ERR(ctx->vcc),
641 				     "Failed to request vcc regulator\n");
642 
643 	ctx->iovcc = devm_regulator_get(dev, "iovcc");
644 	if (IS_ERR(ctx->iovcc))
645 		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
646 				     "Failed to request iovcc regulator\n");
647 
648 	drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs,
649 		       DRM_MODE_CONNECTOR_DSI);
650 
651 	ret = drm_panel_of_backlight(&ctx->panel);
652 	if (ret)
653 		return ret;
654 
655 	drm_panel_add(&ctx->panel);
656 
657 	ret = mipi_dsi_attach(dsi);
658 	if (ret < 0) {
659 		dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
660 		drm_panel_remove(&ctx->panel);
661 		return ret;
662 	}
663 
664 	dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
665 		ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
666 		drm_mode_vrefresh(ctx->desc->mode),
667 		mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
668 
669 	return 0;
670 }
671 
672 static void hx8394_remove(struct mipi_dsi_device *dsi)
673 {
674 	struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
675 	int ret;
676 
677 	ret = mipi_dsi_detach(dsi);
678 	if (ret < 0)
679 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
680 
681 	drm_panel_remove(&ctx->panel);
682 }
683 
684 static const struct of_device_id hx8394_of_match[] = {
685 	{ .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
686 	{ .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc },
687 	{ .compatible = "microchip,ac40t08a-mipi-panel", .data = &mchp_ac40t08a_desc },
688 	{ /* sentinel */ }
689 };
690 MODULE_DEVICE_TABLE(of, hx8394_of_match);
691 
692 static struct mipi_dsi_driver hx8394_driver = {
693 	.probe	= hx8394_probe,
694 	.remove = hx8394_remove,
695 	.driver = {
696 		.name = DRV_NAME,
697 		.of_match_table = hx8394_of_match,
698 	},
699 };
700 module_mipi_dsi_driver(hx8394_driver);
701 
702 MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
703 MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
704 MODULE_LICENSE("GPL");
705