1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for panels based on Sitronix ST7703 controller, souch as:
5 * - Rocktech jh057n00900 5.5" MIPI-DSI panel
7 * Copyright (C) Purism SPC 2019
10 #include <linux/debugfs.h>
11 #include <linux/delay.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/media-bus-format.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/module.h>
17 #include <linux/regulator/consumer.h>
19 #include <video/display_timing.h>
20 #include <video/mipi_display.h>
22 #include <drm/drm_mipi_dsi.h>
23 #include <drm/drm_modes.h>
24 #include <drm/drm_panel.h>
26 #define DRV_NAME "panel-sitronix-st7703"
28 /* Manufacturer specific Commands send via DSI */
29 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
30 #define ST7703_CMD_ALL_PIXEL_ON 0x23
31 #define ST7703_CMD_SETAPID 0xB1
32 #define ST7703_CMD_SETDISP 0xB2
33 #define ST7703_CMD_SETRGBIF 0xB3
34 #define ST7703_CMD_SETCYC 0xB4
35 #define ST7703_CMD_SETBGP 0xB5
36 #define ST7703_CMD_SETVCOM 0xB6
37 #define ST7703_CMD_SETOTP 0xB7
38 #define ST7703_CMD_SETPOWER_EXT 0xB8
39 #define ST7703_CMD_SETEXTC 0xB9
40 #define ST7703_CMD_SETMIPI 0xBA
41 #define ST7703_CMD_SETVDC 0xBC
42 #define ST7703_CMD_UNKNOWN_BF 0xBF
43 #define ST7703_CMD_SETSCR 0xC0
44 #define ST7703_CMD_SETPOWER 0xC1
45 #define ST7703_CMD_SETECO 0xC6
46 #define ST7703_CMD_SETIO 0xC7
47 #define ST7703_CMD_SETCABC 0xC8
48 #define ST7703_CMD_SETPANEL 0xCC
49 #define ST7703_CMD_SETGAMMA 0xE0
50 #define ST7703_CMD_SETEQ 0xE3
51 #define ST7703_CMD_SETGIP1 0xE9
52 #define ST7703_CMD_SETGIP2 0xEA
53 #define ST7703_CMD_UNKNOWN_EF 0xEF
57 struct drm_panel panel;
58 struct gpio_desc *reset_gpio;
59 struct regulator *vcc;
60 struct regulator *iovcc;
62 struct dentry *debugfs;
63 const struct st7703_panel_desc *desc;
64 enum drm_panel_orientation orientation;
67 struct st7703_panel_desc {
68 const struct drm_display_mode *mode;
70 unsigned long mode_flags;
71 enum mipi_dsi_pixel_format format;
72 void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
75 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
77 return container_of(panel, struct st7703, panel);
80 static void jh057n_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
83 * Init sequence was supplied by the panel vendor. Most of the commands
84 * resemble the ST7703 but the number of parameters often don't match
85 * so it's likely a clone.
87 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC,
89 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
90 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
92 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
93 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
95 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
96 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
97 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
98 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
99 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
100 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
101 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
102 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x08, 0x08);
103 mipi_dsi_msleep(dsi_ctx, 20);
105 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
106 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
107 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
108 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
109 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
110 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
111 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
112 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
113 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
114 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
116 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
117 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
119 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
120 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
121 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
124 0xA5, 0x00, 0x00, 0x00, 0x00);
125 mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
126 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
127 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
128 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
129 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
131 mipi_dsi_msleep(dsi_ctx, 20);
134 static const struct drm_display_mode jh057n00900_mode = {
136 .hsync_start = 720 + 90,
137 .hsync_end = 720 + 90 + 20,
138 .htotal = 720 + 90 + 20 + 20,
140 .vsync_start = 1440 + 20,
141 .vsync_end = 1440 + 20 + 4,
142 .vtotal = 1440 + 20 + 4 + 12,
144 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
149 static const struct st7703_panel_desc jh057n00900_panel_desc = {
150 .mode = &jh057n00900_mode,
152 .mode_flags = MIPI_DSI_MODE_VIDEO |
153 MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
154 .format = MIPI_DSI_FMT_RGB888,
155 .init_sequence = jh057n_init_sequence,
158 static void xbd599_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
161 * Init sequence was supplied by the panel vendor.
164 /* Magic sequence to unlock user commands below. */
165 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
167 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI,
168 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
169 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
170 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
171 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
172 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
173 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
174 /* The rest is undocumented in ST7703 datasheet */
175 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
177 0x4F, 0x11, 0x00, 0x00, 0x37);
179 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT,
180 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
181 0x22, /* DT = 15ms XDK_ECP = x2 */
182 0x20, /* PFM_DC_DIV = /1 */
183 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
185 /* RGB I/F porch timing */
186 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
187 0x10, /* VBP_RGB_GEN */
188 0x10, /* VFP_RGB_GEN */
189 0x05, /* DE_BP_RGB_GEN */
190 0x05, /* DE_FP_RGB_GEN */
191 /* The rest is undocumented in ST7703 datasheet */
196 /* Source driving settings. */
197 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
202 0x00, /* SCR[31,24] */
203 0xC0, /* SCR[23,16] */
204 0x08, /* SCR[15,8] */
206 0x00 /* Undocumented */);
208 /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
209 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
212 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
213 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
215 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
217 /* Zig-Zag Type C column inversion. */
218 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
220 /* Set display resolution. */
221 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP,
223 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
226 0xF0 /* WHITE_GND_EN = 1 (GND),
227 * WHITE_FRAME_SEL = 7 frames,
231 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
244 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
245 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
246 * VEDIO_NO_CHECK_EN = 0
247 * ESD_WHITE_GND_EN = 0
248 * ESD_DET_TIME_SEL = 0 frames
251 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
253 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER,
254 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
255 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
259 0xF1, /* APS = 1 (small),
260 * VGL_DET_EN = 1, VGH_DET_EN = 1,
261 * VGL_TURBO = 1, VGH_TURBO = 1
263 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
264 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
265 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
266 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
267 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
268 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
270 /* Reference voltage. */
271 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP,
272 0x07, /* VREF_SEL = 4.2V */
273 0x07 /* NVREF_SEL = 4.2V */);
275 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM,
276 0x2C, /* VCOMDC_F = -0.67V */
277 0x2C /* VCOMDC_B = -0.67V */);
279 /* Undocumented command. */
280 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
282 /* This command is to set forward GIP timing. */
283 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
284 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
285 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
286 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
287 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
288 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
289 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
290 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
293 /* This command is to set backward GIP timing. */
294 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
295 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
297 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
298 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
299 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
302 0xA5, 0x00, 0x00, 0x00, 0x00);
304 /* Adjust the gamma characteristics of the panel. */
305 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
306 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
307 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
308 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
309 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
313 static const struct drm_display_mode xbd599_mode = {
315 .hsync_start = 720 + 40,
316 .hsync_end = 720 + 40 + 40,
317 .htotal = 720 + 40 + 40 + 40,
319 .vsync_start = 1440 + 18,
320 .vsync_end = 1440 + 18 + 10,
321 .vtotal = 1440 + 18 + 10 + 17,
323 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
328 static const struct st7703_panel_desc xbd599_desc = {
329 .mode = &xbd599_mode,
331 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
332 .format = MIPI_DSI_FMT_RGB888,
333 .init_sequence = xbd599_init_sequence,
336 static void rg353v2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
339 * Init sequence was supplied by the panel vendor.
342 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
343 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
345 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
346 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
347 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
348 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
349 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
350 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x92, 0x92);
351 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
353 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
354 0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
356 0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
357 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
358 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
359 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
360 0x00, 0x00, 0x12, 0x50, 0x00);
361 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
362 0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
364 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
366 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
368 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
370 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
371 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
372 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
373 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
374 0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
375 0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
376 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
377 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
379 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
380 0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
381 0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
382 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
383 0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
384 0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
385 0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
386 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
389 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
391 0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
392 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
393 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
400 static const struct drm_display_mode rg353v2_mode = {
402 .hsync_start = 640 + 40,
403 .hsync_end = 640 + 40 + 2,
404 .htotal = 640 + 40 + 2 + 80,
406 .vsync_start = 480 + 18,
407 .vsync_end = 480 + 18 + 2,
408 .vtotal = 480 + 18 + 2 + 28,
410 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
415 static const struct st7703_panel_desc rg353v2_desc = {
416 .mode = &rg353v2_mode,
418 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
419 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
420 .format = MIPI_DSI_FMT_RGB888,
421 .init_sequence = rg353v2_init_sequence,
424 static void rgb30panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
426 /* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
429 * For some reason this specific panel must be taken out of sleep
430 * before the full init sequence, or else it will not display.
432 mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
433 mipi_dsi_msleep(dsi_ctx, 250);
435 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
436 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
437 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
438 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
439 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
440 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
442 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
443 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
444 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
445 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
446 0x00, 0x00, 0x12, 0x70, 0x00);
447 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
448 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
449 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
450 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
451 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
452 0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
454 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
455 0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
457 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
458 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x88, 0x88);
459 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
460 0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
461 0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
462 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
463 0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
464 0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
465 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
469 0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
470 0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
471 0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
472 0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
473 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
477 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
478 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
479 0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
480 0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
481 0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
484 static const struct drm_display_mode rgb30panel_mode = {
486 .hsync_start = 720 + 45,
487 .hsync_end = 720 + 45 + 4,
488 .htotal = 720 + 45 + 4 + 45,
490 .vsync_start = 720 + 15,
491 .vsync_end = 720 + 15 + 3,
492 .vtotal = 720 + 15 + 3 + 11,
494 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
499 static const struct st7703_panel_desc rgb30panel_desc = {
500 .mode = &rgb30panel_mode,
502 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
503 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
504 .format = MIPI_DSI_FMT_RGB888,
505 .init_sequence = rgb30panel_init_sequence,
508 static void rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
510 /* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
512 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
513 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda,
515 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30);
516 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
517 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
518 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
519 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x04, 0x04);
520 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x78, 0x78);
521 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
523 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
524 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
525 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
526 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
527 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
528 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
529 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
530 0x00, 0x00, 0x12, 0x70, 0x00);
531 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32,
532 0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77,
534 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
536 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
538 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
540 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
541 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07,
542 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e,
543 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04,
544 0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b,
545 0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
546 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03,
547 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80,
549 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00,
550 0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86,
551 0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00,
552 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
553 0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88,
554 0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88,
555 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88,
561 0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88,
562 0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
570 static const struct drm_display_mode rgb10max3_panel_mode = {
572 .hsync_start = 720 + 40,
573 .hsync_end = 720 + 40 + 10,
574 .htotal = 720 + 40 + 10 + 40,
576 .vsync_start = 1280 + 16,
577 .vsync_end = 1280 + 16 + 4,
578 .vtotal = 1280 + 16 + 4 + 14,
580 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
585 static const struct st7703_panel_desc rgb10max3_panel_desc = {
586 .mode = &rgb10max3_panel_mode,
588 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
589 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
590 .format = MIPI_DSI_FMT_RGB888,
591 .init_sequence = rgb10max3_panel_init_sequence,
594 static void gameforcechi_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
597 * Init sequence was supplied by the panel vendor. Panel will not
598 * respond to commands until it is brought out of sleep mode first.
601 mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
602 mipi_dsi_msleep(dsi_ctx, 250);
604 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
605 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x31, 0x81, 0x05, 0xf9,
606 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00,
608 0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37);
609 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25);
610 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
611 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a,
612 0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
613 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
614 0x00, 0x00, 0x08, 0x70, 0x00);
615 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
616 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
617 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
618 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0);
619 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
620 0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
622 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e,
623 0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33,
625 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x10, 0x10);
626 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x6c, 0x7c);
627 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0x08, 0x00, 0x0e, 0x00,
628 0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x10,
629 0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
630 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
631 0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
632 0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
633 0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
634 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
637 0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
639 0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 0x42,
640 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x10,
641 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0b,
646 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 0x0b,
647 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 0x07,
648 0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0xa0,
649 0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);
652 static const struct drm_display_mode gameforcechi_mode = {
654 .hsync_start = 640 + 40,
655 .hsync_end = 640 + 40 + 2,
656 .htotal = 640 + 40 + 2 + 80,
658 .vsync_start = 480 + 17,
659 .vsync_end = 480 + 17 + 5,
660 .vtotal = 480 + 17 + 5 + 13,
662 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
667 static const struct st7703_panel_desc gameforcechi_desc = {
668 .mode = &gameforcechi_mode,
670 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
671 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
672 .format = MIPI_DSI_FMT_RGB888,
673 .init_sequence = gameforcechi_init_sequence,
676 static int st7703_enable(struct drm_panel *panel)
678 struct st7703 *ctx = panel_to_st7703(panel);
679 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
680 struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
682 ctx->desc->init_sequence(&dsi_ctx);
684 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
686 /* It takes the controller 120 msec to wake up after sleep. */
687 mipi_dsi_msleep(&dsi_ctx, 120);
689 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
691 if (!dsi_ctx.accum_err)
692 dev_dbg(ctx->dev, "Panel init sequence done\n");
694 return dsi_ctx.accum_err;
697 static int st7703_disable(struct drm_panel *panel)
699 struct st7703 *ctx = panel_to_st7703(panel);
700 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
701 struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
703 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
705 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
707 /* It takes the controller 120 msec to enter sleep mode. */
708 mipi_dsi_msleep(&dsi_ctx, 120);
710 return dsi_ctx.accum_err;
713 static int st7703_unprepare(struct drm_panel *panel)
715 struct st7703 *ctx = panel_to_st7703(panel);
717 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
718 regulator_disable(ctx->iovcc);
719 regulator_disable(ctx->vcc);
724 static int st7703_prepare(struct drm_panel *panel)
726 struct st7703 *ctx = panel_to_st7703(panel);
729 dev_dbg(ctx->dev, "Resetting the panel\n");
730 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
732 ret = regulator_enable(ctx->iovcc);
734 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
738 ret = regulator_enable(ctx->vcc);
740 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
741 regulator_disable(ctx->iovcc);
745 /* Give power supplies time to stabilize before deasserting reset. */
746 usleep_range(10000, 20000);
748 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
749 usleep_range(15000, 20000);
754 static const u32 mantix_bus_formats[] = {
755 MEDIA_BUS_FMT_RGB888_1X24,
758 static int st7703_get_modes(struct drm_panel *panel,
759 struct drm_connector *connector)
761 struct st7703 *ctx = panel_to_st7703(panel);
762 struct drm_display_mode *mode;
764 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
766 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
767 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
768 drm_mode_vrefresh(ctx->desc->mode));
772 drm_mode_set_name(mode);
774 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
775 connector->display_info.width_mm = mode->width_mm;
776 connector->display_info.height_mm = mode->height_mm;
777 drm_mode_probed_add(connector, mode);
779 drm_display_info_set_bus_formats(&connector->display_info,
781 ARRAY_SIZE(mantix_bus_formats));
786 static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel)
788 struct st7703 *st7703 = panel_to_st7703(panel);
790 return st7703->orientation;
793 static const struct drm_panel_funcs st7703_drm_funcs = {
794 .disable = st7703_disable,
795 .unprepare = st7703_unprepare,
796 .prepare = st7703_prepare,
797 .enable = st7703_enable,
798 .get_modes = st7703_get_modes,
799 .get_orientation = st7703_get_orientation,
802 static int allpixelson_set(void *data, u64 val)
804 struct st7703 *ctx = data;
805 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
806 struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
808 dev_dbg(ctx->dev, "Setting all pixels on\n");
809 mipi_dsi_generic_write_seq_multi(&dsi_ctx, ST7703_CMD_ALL_PIXEL_ON);
810 mipi_dsi_msleep(&dsi_ctx, val * 1000);
813 * Reset the panel to get video back. NOTE: This isn't a
814 * particularly safe thing to do in general because it assumes
815 * that the screen was on to begin with, but this is just a
816 * debugfs file so it's not a huge deal.
818 drm_panel_disable(&ctx->panel);
819 drm_panel_unprepare(&ctx->panel);
820 drm_panel_prepare(&ctx->panel);
821 drm_panel_enable(&ctx->panel);
823 return dsi_ctx.accum_err;
826 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
827 allpixelson_set, "%llu\n");
829 static void st7703_debugfs_init(struct st7703 *ctx)
831 ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
833 debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
837 static void st7703_debugfs_remove(struct st7703 *ctx)
839 debugfs_remove_recursive(ctx->debugfs);
843 static int st7703_probe(struct mipi_dsi_device *dsi)
845 struct device *dev = &dsi->dev;
849 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
853 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
854 if (IS_ERR(ctx->reset_gpio))
855 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
857 mipi_dsi_set_drvdata(dsi, ctx);
860 ctx->desc = of_device_get_match_data(dev);
862 dsi->mode_flags = ctx->desc->mode_flags;
863 dsi->format = ctx->desc->format;
864 dsi->lanes = ctx->desc->lanes;
866 ctx->vcc = devm_regulator_get(dev, "vcc");
867 if (IS_ERR(ctx->vcc))
868 return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
870 ctx->iovcc = devm_regulator_get(dev, "iovcc");
871 if (IS_ERR(ctx->iovcc))
872 return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
873 "Failed to request iovcc regulator\n");
875 ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
877 return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
879 drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
880 DRM_MODE_CONNECTOR_DSI);
882 ret = drm_panel_of_backlight(&ctx->panel);
886 drm_panel_add(&ctx->panel);
888 ret = mipi_dsi_attach(dsi);
890 dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
891 drm_panel_remove(&ctx->panel);
895 dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
896 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
897 drm_mode_vrefresh(ctx->desc->mode),
898 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
900 st7703_debugfs_init(ctx);
904 static void st7703_remove(struct mipi_dsi_device *dsi)
906 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
909 ret = mipi_dsi_detach(dsi);
911 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
913 drm_panel_remove(&ctx->panel);
915 st7703_debugfs_remove(ctx);
918 static const struct of_device_id st7703_of_match[] = {
919 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
920 { .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
921 { .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
922 { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
923 { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
924 { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
927 MODULE_DEVICE_TABLE(of, st7703_of_match);
929 static struct mipi_dsi_driver st7703_driver = {
930 .probe = st7703_probe,
931 .remove = st7703_remove,
934 .of_match_table = st7703_of_match,
937 module_mipi_dsi_driver(st7703_driver);
940 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
941 MODULE_LICENSE("GPL v2");