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