xref: /linux/drivers/gpu/drm/panel/panel-sitronix-st7703.c (revision 2b109eccd80b660e58d4523e8b80ce11bc3e532e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for panels based on Sitronix ST7703 controller, such as:
4  *
5  * - Rocktech jh057n00900 5.5" MIPI-DSI panel
6  *
7  * Copyright (C) Purism SPC 2019
8  */
9 
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/module.h>
15 #include <linux/of.h>
16 #include <linux/regulator/consumer.h>
17 
18 #include <video/display_timing.h>
19 #include <video/mipi_display.h>
20 
21 #include <drm/drm_mipi_dsi.h>
22 #include <drm/drm_modes.h>
23 #include <drm/drm_panel.h>
24 
25 #define DRV_NAME "panel-sitronix-st7703"
26 
27 /* Manufacturer specific Commands send via DSI */
28 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
29 #define ST7703_CMD_ALL_PIXEL_ON	 0x23
30 #define ST7703_CMD_SETAPID	 0xB1
31 #define ST7703_CMD_SETDISP	 0xB2
32 #define ST7703_CMD_SETRGBIF	 0xB3
33 #define ST7703_CMD_SETCYC	 0xB4
34 #define ST7703_CMD_SETBGP	 0xB5
35 #define ST7703_CMD_SETVCOM	 0xB6
36 #define ST7703_CMD_SETOTP	 0xB7
37 #define ST7703_CMD_SETPOWER_EXT	 0xB8
38 #define ST7703_CMD_SETEXTC	 0xB9
39 #define ST7703_CMD_SETMIPI	 0xBA
40 #define ST7703_CMD_SETVDC	 0xBC
41 #define ST7703_CMD_UNKNOWN_BF	 0xBF
42 #define ST7703_CMD_SETSCR	 0xC0
43 #define ST7703_CMD_SETPOWER	 0xC1
44 #define ST7703_CMD_SETECO	 0xC6
45 #define ST7703_CMD_SETIO	 0xC7
46 #define ST7703_CMD_SETCABC	 0xC8
47 #define ST7703_CMD_SETPANEL	 0xCC
48 #define ST7703_CMD_SETGAMMA	 0xE0
49 #define ST7703_CMD_SETEQ	 0xE3
50 #define ST7703_CMD_SETGIP1	 0xE9
51 #define ST7703_CMD_SETGIP2	 0xEA
52 #define ST7703_CMD_UNKNOWN_EF	 0xEF
53 
54 struct st7703 {
55 	struct device *dev;
56 	struct drm_panel panel;
57 	struct gpio_desc *reset_gpio;
58 	struct regulator *vcc;
59 	struct regulator *iovcc;
60 
61 	struct dentry *debugfs;
62 	const struct st7703_panel_desc *desc;
63 	enum drm_panel_orientation orientation;
64 };
65 
66 struct st7703_panel_desc {
67 	const struct drm_display_mode *mode;
68 	unsigned int lanes;
69 	unsigned long mode_flags;
70 	enum mipi_dsi_pixel_format format;
71 	void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
72 };
73 
74 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
75 {
76 	return container_of(panel, struct st7703, panel);
77 }
78 
79 static void jh057n_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
80 {
81 	/*
82 	 * Init sequence was supplied by the panel vendor. Most of the commands
83 	 * resemble the ST7703 but the number of parameters often don't match
84 	 * so it's likely a clone.
85 	 */
86 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC,
87 					 0xF1, 0x12, 0x83);
88 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
89 					 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
90 					 0x00, 0x00);
91 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
92 					 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
93 					 0x00);
94 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
95 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
96 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
97 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
98 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
99 					 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
100 					 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
101 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x08, 0x08);
102 	mipi_dsi_msleep(dsi_ctx, 20);
103 
104 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
105 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
106 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
107 					 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
108 					 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
109 					 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
110 					 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
111 					 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
112 					 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
113 					 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
115 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
116 					 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 					 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
118 					 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
119 					 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
120 					 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
121 					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
123 					 0xA5, 0x00, 0x00, 0x00, 0x00);
124 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
125 					 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
126 					 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
127 					 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
128 					 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
129 					 0x11, 0x18);
130 	mipi_dsi_msleep(dsi_ctx, 20);
131 }
132 
133 static const struct drm_display_mode jh057n00900_mode = {
134 	.hdisplay    = 720,
135 	.hsync_start = 720 + 90,
136 	.hsync_end   = 720 + 90 + 20,
137 	.htotal	     = 720 + 90 + 20 + 20,
138 	.vdisplay    = 1440,
139 	.vsync_start = 1440 + 20,
140 	.vsync_end   = 1440 + 20 + 4,
141 	.vtotal	     = 1440 + 20 + 4 + 12,
142 	.clock	     = 75276,
143 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
144 	.width_mm    = 65,
145 	.height_mm   = 130,
146 };
147 
148 static const struct st7703_panel_desc jh057n00900_panel_desc = {
149 	.mode = &jh057n00900_mode,
150 	.lanes = 4,
151 	.mode_flags = MIPI_DSI_MODE_VIDEO |
152 		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
153 	.format = MIPI_DSI_FMT_RGB888,
154 	.init_sequence = jh057n_init_sequence,
155 };
156 
157 static void xbd599_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
158 {
159 	/*
160 	 * Init sequence was supplied by the panel vendor.
161 	 */
162 
163 	/* Magic sequence to unlock user commands below. */
164 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
165 
166 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI,
167 				     0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
168 				     0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
169 				     0x05, /* IHSRX = x6 (Low High Speed driving ability) */
170 				     0xF9, /* TX_CLK_SEL = fDSICLK/16 */
171 				     0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
172 				     0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
173 				     /* The rest is undocumented in ST7703 datasheet */
174 				     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 				     0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
176 				     0x4F, 0x11, 0x00, 0x00, 0x37);
177 
178 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT,
179 				     0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
180 				     0x22, /* DT = 15ms XDK_ECP = x2 */
181 				     0x20, /* PFM_DC_DIV = /1 */
182 				     0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
183 
184 	/* RGB I/F porch timing */
185 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
186 				     0x10, /* VBP_RGB_GEN */
187 				     0x10, /* VFP_RGB_GEN */
188 				     0x05, /* DE_BP_RGB_GEN */
189 				     0x05, /* DE_FP_RGB_GEN */
190 				     /* The rest is undocumented in ST7703 datasheet */
191 				     0x03, 0xFF,
192 				     0x00, 0x00,
193 				     0x00, 0x00);
194 
195 	/* Source driving settings. */
196 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
197 				     0x73, /* N_POPON */
198 				     0x73, /* N_NOPON */
199 				     0x50, /* I_POPON */
200 				     0x50, /* I_NOPON */
201 				     0x00, /* SCR[31,24] */
202 				     0xC0, /* SCR[23,16] */
203 				     0x08, /* SCR[15,8] */
204 				     0x70, /* SCR[7,0] */
205 				     0x00  /* Undocumented */);
206 
207 	/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
208 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
209 
210 	/*
211 	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
212 	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
213 	 */
214 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
215 
216 	/* Zig-Zag Type C column inversion. */
217 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
218 
219 	/* Set display resolution. */
220 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP,
221 				     0xF0, /* NL = 240 */
222 				     0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
223 					    * RESO_SEL = 720RGB
224 					    */
225 				     0xF0  /* WHITE_GND_EN = 1 (GND),
226 					    * WHITE_FRAME_SEL = 7 frames,
227 					    * ISC = 0 frames
228 					    */);
229 
230 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
231 				     0x00, /* PNOEQ */
232 				     0x00, /* NNOEQ */
233 				     0x0B, /* PEQGND */
234 				     0x0B, /* NEQGND */
235 				     0x10, /* PEQVCI */
236 				     0x10, /* NEQVCI */
237 				     0x00, /* PEQVCI1 */
238 				     0x00, /* NEQVCI1 */
239 				     0x00, /* reserved */
240 				     0x00, /* reserved */
241 				     0xFF, /* reserved */
242 				     0x00, /* reserved */
243 				     0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
244 				     0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
245 					    * VEDIO_NO_CHECK_EN = 0
246 					    * ESD_WHITE_GND_EN = 0
247 					    * ESD_DET_TIME_SEL = 0 frames
248 					    */);
249 
250 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
251 
252 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER,
253 				     0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
254 				     0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
255 				     0x32, /* VRP  */
256 				     0x32, /* VRN */
257 				     0x77, /* reserved */
258 				     0xF1, /* APS = 1 (small),
259 					    * VGL_DET_EN = 1, VGH_DET_EN = 1,
260 					    * VGL_TURBO = 1, VGH_TURBO = 1
261 					    */
262 				     0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
263 				     0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
264 				     0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
265 				     0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
266 				     0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
267 				     0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
268 
269 	/* Reference voltage. */
270 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP,
271 				     0x07, /* VREF_SEL = 4.2V */
272 				     0x07  /* NVREF_SEL = 4.2V */);
273 
274 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM,
275 				     0x2C, /* VCOMDC_F = -0.67V */
276 				     0x2C  /* VCOMDC_B = -0.67V */);
277 
278 	/* Undocumented command. */
279 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
280 
281 	/* This command is to set forward GIP timing. */
282 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
283 				     0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
284 				     0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
285 				     0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
286 				     0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
287 				     0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
288 				     0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
289 				     0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
291 
292 	/* This command is to set backward GIP timing. */
293 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
294 				     0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 				     0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
296 				     0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
297 				     0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
298 				     0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
299 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
301 				     0xA5, 0x00, 0x00, 0x00, 0x00);
302 
303 	/* Adjust the gamma characteristics of the panel. */
304 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
305 				     0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
306 				     0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
307 				     0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
308 				     0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
309 				     0x12, 0x18);
310 }
311 
312 static const struct drm_display_mode xbd599_mode = {
313 	.hdisplay    = 720,
314 	.hsync_start = 720 + 40,
315 	.hsync_end   = 720 + 40 + 40,
316 	.htotal	     = 720 + 40 + 40 + 40,
317 	.vdisplay    = 1440,
318 	.vsync_start = 1440 + 18,
319 	.vsync_end   = 1440 + 18 + 10,
320 	.vtotal	     = 1440 + 18 + 10 + 17,
321 	.clock	     = 69000,
322 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
323 	.width_mm    = 68,
324 	.height_mm   = 136,
325 };
326 
327 static const struct st7703_panel_desc xbd599_desc = {
328 	.mode = &xbd599_mode,
329 	.lanes = 4,
330 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
331 	.format = MIPI_DSI_FMT_RGB888,
332 	.init_sequence = xbd599_init_sequence,
333 };
334 
335 static void rg353v2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
336 {
337 	/*
338 	 * Init sequence was supplied by the panel vendor.
339 	 */
340 
341 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
342 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
343 				     0xda, 0x80);
344 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
345 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
346 				     0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
347 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
348 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
349 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x92, 0x92);
350 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
351 				     0xf0, 0x63);
352 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
353 				     0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
354 				     0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
355 				     0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
356 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
357 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
358 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
359 				     0x00, 0x00, 0x12, 0x50, 0x00);
360 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
361 				     0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
362 				     0x33);
363 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
364 				     0x00, 0xff);
365 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
366 				     0x00, 0x00);
367 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
368 				     0x02);
369 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
370 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
371 				     0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
372 				     0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
373 				     0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
374 				     0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
375 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
376 				     0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
377 				     0xc0, 0x10);
378 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
379 				     0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
380 				     0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
381 				     0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
382 				     0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
383 				     0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
384 				     0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
385 				     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 				     0x00, 0x00, 0x00);
387 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
388 				     0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 				     0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
390 				     0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
391 				     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
392 				     0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
393 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 				     0x00);
396 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
397 }
398 
399 static const struct drm_display_mode rg353v2_mode = {
400 	.hdisplay	= 640,
401 	.hsync_start	= 640 + 40,
402 	.hsync_end	= 640 + 40 + 2,
403 	.htotal		= 640 + 40 + 2 + 80,
404 	.vdisplay	= 480,
405 	.vsync_start	= 480 + 18,
406 	.vsync_end	= 480 + 18 + 2,
407 	.vtotal		= 480 + 18 + 2 + 28,
408 	.clock		= 24150,
409 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
410 	.width_mm	= 70,
411 	.height_mm	= 57,
412 };
413 
414 static const struct st7703_panel_desc rg353v2_desc = {
415 	.mode = &rg353v2_mode,
416 	.lanes = 4,
417 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
418 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
419 	.format = MIPI_DSI_FMT_RGB888,
420 	.init_sequence = rg353v2_init_sequence,
421 };
422 
423 static void rgb30panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
424 {
425 	/* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
426 
427 	/*
428 	 * For some reason this specific panel must be taken out of sleep
429 	 * before the full init sequence, or else it will not display.
430 	 */
431 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
432 	mipi_dsi_msleep(dsi_ctx, 250);
433 
434 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
435 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
436 				     0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
437 				     0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
438 				     0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
439 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
440 				     0x63);
441 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
442 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
443 				     0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
444 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
445 				     0x00, 0x00, 0x12, 0x70, 0x00);
446 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
447 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
448 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
449 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
450 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
451 				     0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
452 				     0xc0, 0x10);
453 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
454 				     0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
455 				     0x33);
456 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
457 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x88, 0x88);
458 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
459 				     0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
460 				     0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
461 				     0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
462 				     0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
463 				     0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
464 				     0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
465 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466 				     0x00, 0x00, 0x00);
467 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
468 				     0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
469 				     0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
470 				     0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
471 				     0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
472 				     0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
473 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474 				     0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
475 				     0x00);
476 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
477 				     0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
478 				     0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
479 				     0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
480 				     0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
481 }
482 
483 static const struct drm_display_mode rgb30panel_mode = {
484 	.hdisplay	= 720,
485 	.hsync_start	= 720 + 45,
486 	.hsync_end	= 720 + 45 + 4,
487 	.htotal		= 720 + 45 + 4 + 45,
488 	.vdisplay	= 720,
489 	.vsync_start	= 720 + 15,
490 	.vsync_end	= 720 + 15 + 3,
491 	.vtotal		= 720 + 15 + 3 + 11,
492 	.clock		= 36570,
493 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
494 	.width_mm	= 76,
495 	.height_mm	= 76,
496 };
497 
498 static const struct st7703_panel_desc rgb30panel_desc = {
499 	.mode = &rgb30panel_mode,
500 	.lanes = 4,
501 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
502 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
503 	.format = MIPI_DSI_FMT_RGB888,
504 	.init_sequence = rgb30panel_init_sequence,
505 };
506 
507 static void rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
508 {
509 	/* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
510 
511 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
512 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda,
513 				     0x80);
514 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30);
515 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
516 				     0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
517 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
518 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x04, 0x04);
519 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x78, 0x78);
520 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
521 				     0x63);
522 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
523 				     0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
524 				     0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
525 				     0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
526 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
527 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
528 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
529 				     0x00, 0x00, 0x12, 0x70, 0x00);
530 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32,
531 				     0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77,
532 				     0x77);
533 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
534 				     0x00, 0xff);
535 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
536 				     0x00, 0x00);
537 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
538 				     0x02);
539 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
540 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07,
541 				     0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e,
542 				     0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04,
543 				     0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b,
544 				     0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
545 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03,
546 				     0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80,
547 				     0xc0, 0x10);
548 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00,
549 				     0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86,
550 				     0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00,
551 				     0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
552 				     0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88,
553 				     0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88,
554 				     0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00,
555 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 				     0x00, 0x00, 0x00);
557 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00,
558 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 				     0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88,
560 				     0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88,
561 				     0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00,
562 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 				     0x00);
566 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
567 }
568 
569 static const struct drm_display_mode rgb10max3_panel_mode = {
570 	.hdisplay	= 720,
571 	.hsync_start	= 720 + 40,
572 	.hsync_end	= 720 + 40 + 10,
573 	.htotal		= 720 + 40 + 10 + 40,
574 	.vdisplay	= 1280,
575 	.vsync_start	= 1280 + 16,
576 	.vsync_end	= 1280 + 16 + 4,
577 	.vtotal		= 1280 + 16 + 4 + 14,
578 	.clock		= 63800,
579 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
580 	.width_mm	= 62,
581 	.height_mm	= 109,
582 };
583 
584 static const struct st7703_panel_desc rgb10max3_panel_desc = {
585 	.mode = &rgb10max3_panel_mode,
586 	.lanes = 4,
587 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
588 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
589 	.format = MIPI_DSI_FMT_RGB888,
590 	.init_sequence = rgb10max3_panel_init_sequence,
591 };
592 
593 static void gameforcechi_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
594 {
595 	/*
596 	 * Init sequence was supplied by the panel vendor. Panel will not
597 	 * respond to commands until it is brought out of sleep mode first.
598 	 */
599 
600 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
601 	mipi_dsi_msleep(dsi_ctx, 250);
602 
603 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
604 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x31, 0x81, 0x05, 0xf9,
605 				     0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
606 				     0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00,
607 				     0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37);
608 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25);
609 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
610 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a,
611 				     0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
612 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
613 				     0x00, 0x00, 0x08, 0x70, 0x00);
614 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
615 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
616 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
617 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0);
618 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
619 				     0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
620 				     0xc0, 0x10);
621 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e,
622 				     0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33,
623 				     0x33);
624 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x10, 0x10);
625 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x6c, 0x7c);
626 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0x08, 0x00, 0x0e, 0x00,
627 				     0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x10,
628 				     0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
629 				     0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
630 				     0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
631 				     0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
632 				     0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
633 				     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634 				     0x00, 0x00, 0x00);
635 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
636 				     0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 				     0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
638 				     0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 0x42,
639 				     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x10,
640 				     0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
641 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 				     0x00);
644 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0b,
645 				     0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 0x0b,
646 				     0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 0x07,
647 				     0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0xa0,
648 				     0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);
649 }
650 
651 static const struct drm_display_mode gameforcechi_mode = {
652 	.hdisplay	= 640,
653 	.hsync_start	= 640 + 40,
654 	.hsync_end	= 640 + 40 + 2,
655 	.htotal		= 640 + 40 + 2 + 80,
656 	.vdisplay	= 480,
657 	.vsync_start	= 480 + 17,
658 	.vsync_end	= 480 + 17 + 5,
659 	.vtotal		= 480 + 17 + 5 + 13,
660 	.clock		= 23546,
661 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
662 	.width_mm	= 71,
663 	.height_mm	= 53,
664 };
665 
666 static const struct st7703_panel_desc gameforcechi_desc = {
667 	.mode = &gameforcechi_mode,
668 	.lanes = 2,
669 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
670 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
671 	.format = MIPI_DSI_FMT_RGB888,
672 	.init_sequence = gameforcechi_init_sequence,
673 };
674 
675 static int st7703_enable(struct drm_panel *panel)
676 {
677 	struct st7703 *ctx = panel_to_st7703(panel);
678 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
679 	struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
680 
681 	ctx->desc->init_sequence(&dsi_ctx);
682 
683 	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
684 
685 	/* It takes the controller 120 msec to wake up after sleep. */
686 	mipi_dsi_msleep(&dsi_ctx, 120);
687 
688 	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
689 
690 	if (!dsi_ctx.accum_err)
691 		dev_dbg(ctx->dev, "Panel init sequence done\n");
692 
693 	return dsi_ctx.accum_err;
694 }
695 
696 static int st7703_disable(struct drm_panel *panel)
697 {
698 	struct st7703 *ctx = panel_to_st7703(panel);
699 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
700 	struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
701 
702 	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
703 
704 	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
705 
706 	/* It takes the controller 120 msec to enter sleep mode. */
707 	mipi_dsi_msleep(&dsi_ctx, 120);
708 
709 	return dsi_ctx.accum_err;
710 }
711 
712 static int st7703_unprepare(struct drm_panel *panel)
713 {
714 	struct st7703 *ctx = panel_to_st7703(panel);
715 
716 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
717 	regulator_disable(ctx->iovcc);
718 	regulator_disable(ctx->vcc);
719 
720 	return 0;
721 }
722 
723 static int st7703_prepare(struct drm_panel *panel)
724 {
725 	struct st7703 *ctx = panel_to_st7703(panel);
726 	int ret;
727 
728 	dev_dbg(ctx->dev, "Resetting the panel\n");
729 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
730 
731 	ret = regulator_enable(ctx->iovcc);
732 	if (ret < 0) {
733 		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
734 		return ret;
735 	}
736 
737 	ret = regulator_enable(ctx->vcc);
738 	if (ret < 0) {
739 		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
740 		regulator_disable(ctx->iovcc);
741 		return ret;
742 	}
743 
744 	/* Give power supplies time to stabilize before deasserting reset. */
745 	usleep_range(10000, 20000);
746 
747 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
748 	usleep_range(15000, 20000);
749 
750 	return 0;
751 }
752 
753 static const u32 mantix_bus_formats[] = {
754 	MEDIA_BUS_FMT_RGB888_1X24,
755 };
756 
757 static int st7703_get_modes(struct drm_panel *panel,
758 			    struct drm_connector *connector)
759 {
760 	struct st7703 *ctx = panel_to_st7703(panel);
761 	struct drm_display_mode *mode;
762 
763 	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
764 	if (!mode) {
765 		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
766 			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
767 			drm_mode_vrefresh(ctx->desc->mode));
768 		return -ENOMEM;
769 	}
770 
771 	drm_mode_set_name(mode);
772 
773 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
774 	connector->display_info.width_mm = mode->width_mm;
775 	connector->display_info.height_mm = mode->height_mm;
776 	drm_mode_probed_add(connector, mode);
777 
778 	drm_display_info_set_bus_formats(&connector->display_info,
779 					 mantix_bus_formats,
780 					 ARRAY_SIZE(mantix_bus_formats));
781 
782 	return 1;
783 }
784 
785 static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel)
786 {
787 	struct st7703 *st7703 = panel_to_st7703(panel);
788 
789 	return st7703->orientation;
790 }
791 
792 static const struct drm_panel_funcs st7703_drm_funcs = {
793 	.disable   = st7703_disable,
794 	.unprepare = st7703_unprepare,
795 	.prepare   = st7703_prepare,
796 	.enable	   = st7703_enable,
797 	.get_modes = st7703_get_modes,
798 	.get_orientation = st7703_get_orientation,
799 };
800 
801 static int allpixelson_set(void *data, u64 val)
802 {
803 	struct st7703 *ctx = data;
804 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
805 	struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
806 
807 	dev_dbg(ctx->dev, "Setting all pixels on\n");
808 	mipi_dsi_generic_write_seq_multi(&dsi_ctx, ST7703_CMD_ALL_PIXEL_ON);
809 	mipi_dsi_msleep(&dsi_ctx, val * 1000);
810 
811 	/*
812 	 * Reset the panel to get video back. NOTE: This isn't a
813 	 * particularly safe thing to do in general because it assumes
814 	 * that the screen was on to begin with, but this is just a
815 	 * debugfs file so it's not a huge deal.
816 	 */
817 	drm_panel_disable(&ctx->panel);
818 	drm_panel_unprepare(&ctx->panel);
819 	drm_panel_prepare(&ctx->panel);
820 	drm_panel_enable(&ctx->panel);
821 
822 	return dsi_ctx.accum_err;
823 }
824 
825 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
826 			allpixelson_set, "%llu\n");
827 
828 static void st7703_debugfs_init(struct st7703 *ctx)
829 {
830 	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
831 
832 	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
833 			    &allpixelson_fops);
834 }
835 
836 static void st7703_debugfs_remove(struct st7703 *ctx)
837 {
838 	debugfs_remove_recursive(ctx->debugfs);
839 	ctx->debugfs = NULL;
840 }
841 
842 static int st7703_probe(struct mipi_dsi_device *dsi)
843 {
844 	struct device *dev = &dsi->dev;
845 	struct st7703 *ctx;
846 	int ret;
847 
848 	ctx = devm_drm_panel_alloc(dev, struct st7703, panel,
849 				   &st7703_drm_funcs,
850 				   DRM_MODE_CONNECTOR_DSI);
851 	if (IS_ERR(ctx))
852 		return PTR_ERR(ctx);
853 
854 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
855 	if (IS_ERR(ctx->reset_gpio))
856 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
857 
858 	mipi_dsi_set_drvdata(dsi, ctx);
859 
860 	ctx->dev = dev;
861 	ctx->desc = of_device_get_match_data(dev);
862 
863 	dsi->mode_flags = ctx->desc->mode_flags;
864 	dsi->format = ctx->desc->format;
865 	dsi->lanes = ctx->desc->lanes;
866 
867 	ctx->vcc = devm_regulator_get(dev, "vcc");
868 	if (IS_ERR(ctx->vcc))
869 		return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
870 
871 	ctx->iovcc = devm_regulator_get(dev, "iovcc");
872 	if (IS_ERR(ctx->iovcc))
873 		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
874 				     "Failed to request iovcc regulator\n");
875 
876 	ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
877 	if (ret < 0)
878 		return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
879 
880 	ret = drm_panel_of_backlight(&ctx->panel);
881 	if (ret)
882 		return ret;
883 
884 	drm_panel_add(&ctx->panel);
885 
886 	ret = mipi_dsi_attach(dsi);
887 	if (ret < 0) {
888 		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
889 		drm_panel_remove(&ctx->panel);
890 		return ret;
891 	}
892 
893 	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
894 		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
895 		 drm_mode_vrefresh(ctx->desc->mode),
896 		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
897 
898 	st7703_debugfs_init(ctx);
899 	return 0;
900 }
901 
902 static void st7703_remove(struct mipi_dsi_device *dsi)
903 {
904 	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
905 	int ret;
906 
907 	ret = mipi_dsi_detach(dsi);
908 	if (ret < 0)
909 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
910 
911 	drm_panel_remove(&ctx->panel);
912 
913 	st7703_debugfs_remove(ctx);
914 }
915 
916 static const struct of_device_id st7703_of_match[] = {
917 	{ .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
918 	{ .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
919 	{ .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
920 	{ .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
921 	{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
922 	{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
923 	{ /* sentinel */ }
924 };
925 MODULE_DEVICE_TABLE(of, st7703_of_match);
926 
927 static struct mipi_dsi_driver st7703_driver = {
928 	.probe	= st7703_probe,
929 	.remove = st7703_remove,
930 	.driver = {
931 		.name = DRV_NAME,
932 		.of_match_table = st7703_of_match,
933 	},
934 };
935 module_mipi_dsi_driver(st7703_driver);
936 
937 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
938 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
939 MODULE_LICENSE("GPL v2");
940