1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for panels based on Sitronix ST7703 controller, souch 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/mod_devicetable.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/regulator/consumer.h>
18 
19 #include <video/display_timing.h>
20 #include <video/mipi_display.h>
21 
22 #include <drm/drm_mipi_dsi.h>
23 #include <drm/drm_modes.h>
24 #include <drm/drm_panel.h>
25 
26 #define DRV_NAME "panel-sitronix-st7703"
27 
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
54 
55 struct st7703 {
56 	struct device *dev;
57 	struct drm_panel panel;
58 	struct gpio_desc *reset_gpio;
59 	struct regulator *vcc;
60 	struct regulator *iovcc;
61 
62 	struct dentry *debugfs;
63 	const struct st7703_panel_desc *desc;
64 	enum drm_panel_orientation orientation;
65 };
66 
67 struct st7703_panel_desc {
68 	const struct drm_display_mode *mode;
69 	unsigned int lanes;
70 	unsigned long mode_flags;
71 	enum mipi_dsi_pixel_format format;
72 	void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
73 };
74 
panel_to_st7703(struct drm_panel * panel)75 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
76 {
77 	return container_of(panel, struct st7703, panel);
78 }
79 
jh057n_init_sequence(struct mipi_dsi_multi_context * dsi_ctx)80 static void jh057n_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
81 {
82 	/*
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.
86 	 */
87 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC,
88 					 0xF1, 0x12, 0x83);
89 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
90 					 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
91 					 0x00, 0x00);
92 	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
93 					 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
94 					 0x00);
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);
104 
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,
130 					 0x11, 0x18);
131 	mipi_dsi_msleep(dsi_ctx, 20);
132 }
133 
134 static const struct drm_display_mode jh057n00900_mode = {
135 	.hdisplay    = 720,
136 	.hsync_start = 720 + 90,
137 	.hsync_end   = 720 + 90 + 20,
138 	.htotal	     = 720 + 90 + 20 + 20,
139 	.vdisplay    = 1440,
140 	.vsync_start = 1440 + 20,
141 	.vsync_end   = 1440 + 20 + 4,
142 	.vtotal	     = 1440 + 20 + 4 + 12,
143 	.clock	     = 75276,
144 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
145 	.width_mm    = 65,
146 	.height_mm   = 130,
147 };
148 
149 static const struct st7703_panel_desc jh057n00900_panel_desc = {
150 	.mode = &jh057n00900_mode,
151 	.lanes = 4,
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,
156 };
157 
xbd599_init_sequence(struct mipi_dsi_multi_context * dsi_ctx)158 static void xbd599_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
159 {
160 	/*
161 	 * Init sequence was supplied by the panel vendor.
162 	 */
163 
164 	/* Magic sequence to unlock user commands below. */
165 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
166 
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);
178 
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 */);
184 
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 */
192 				     0x03, 0xFF,
193 				     0x00, 0x00,
194 				     0x00, 0x00);
195 
196 	/* Source driving settings. */
197 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
198 				     0x73, /* N_POPON */
199 				     0x73, /* N_NOPON */
200 				     0x50, /* I_POPON */
201 				     0x50, /* I_NOPON */
202 				     0x00, /* SCR[31,24] */
203 				     0xC0, /* SCR[23,16] */
204 				     0x08, /* SCR[15,8] */
205 				     0x70, /* SCR[7,0] */
206 				     0x00  /* Undocumented */);
207 
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);
210 
211 	/*
212 	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
213 	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
214 	 */
215 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
216 
217 	/* Zig-Zag Type C column inversion. */
218 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
219 
220 	/* Set display resolution. */
221 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP,
222 				     0xF0, /* NL = 240 */
223 				     0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
224 					    * RESO_SEL = 720RGB
225 					    */
226 				     0xF0  /* WHITE_GND_EN = 1 (GND),
227 					    * WHITE_FRAME_SEL = 7 frames,
228 					    * ISC = 0 frames
229 					    */);
230 
231 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
232 				     0x00, /* PNOEQ */
233 				     0x00, /* NNOEQ */
234 				     0x0B, /* PEQGND */
235 				     0x0B, /* NEQGND */
236 				     0x10, /* PEQVCI */
237 				     0x10, /* NEQVCI */
238 				     0x00, /* PEQVCI1 */
239 				     0x00, /* NEQVCI1 */
240 				     0x00, /* reserved */
241 				     0x00, /* reserved */
242 				     0xFF, /* reserved */
243 				     0x00, /* reserved */
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
249 					    */);
250 
251 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
252 
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 */
256 				     0x32, /* VRP  */
257 				     0x32, /* VRN */
258 				     0x77, /* reserved */
259 				     0xF1, /* APS = 1 (small),
260 					    * VGL_DET_EN = 1, VGH_DET_EN = 1,
261 					    * VGL_TURBO = 1, VGH_TURBO = 1
262 					    */
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) */);
269 
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 */);
274 
275 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM,
276 				     0x2C, /* VCOMDC_F = -0.67V */
277 				     0x2C  /* VCOMDC_B = -0.67V */);
278 
279 	/* Undocumented command. */
280 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
281 
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);
292 
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);
303 
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,
310 				     0x12, 0x18);
311 }
312 
313 static const struct drm_display_mode xbd599_mode = {
314 	.hdisplay    = 720,
315 	.hsync_start = 720 + 40,
316 	.hsync_end   = 720 + 40 + 40,
317 	.htotal	     = 720 + 40 + 40 + 40,
318 	.vdisplay    = 1440,
319 	.vsync_start = 1440 + 18,
320 	.vsync_end   = 1440 + 18 + 10,
321 	.vtotal	     = 1440 + 18 + 10 + 17,
322 	.clock	     = 69000,
323 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
324 	.width_mm    = 68,
325 	.height_mm   = 136,
326 };
327 
328 static const struct st7703_panel_desc xbd599_desc = {
329 	.mode = &xbd599_mode,
330 	.lanes = 4,
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,
334 };
335 
rg353v2_init_sequence(struct mipi_dsi_multi_context * dsi_ctx)336 static void rg353v2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
337 {
338 	/*
339 	 * Init sequence was supplied by the panel vendor.
340 	 */
341 
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,
344 				     0xda, 0x80);
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,
352 				     0xf0, 0x63);
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,
363 				     0x33);
364 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
365 				     0x00, 0xff);
366 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
367 				     0x00, 0x00);
368 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
369 				     0x02);
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,
378 				     0xc0, 0x10);
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,
387 				     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,
396 				     0x00);
397 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
398 }
399 
400 static const struct drm_display_mode rg353v2_mode = {
401 	.hdisplay	= 640,
402 	.hsync_start	= 640 + 40,
403 	.hsync_end	= 640 + 40 + 2,
404 	.htotal		= 640 + 40 + 2 + 80,
405 	.vdisplay	= 480,
406 	.vsync_start	= 480 + 18,
407 	.vsync_end	= 480 + 18 + 2,
408 	.vtotal		= 480 + 18 + 2 + 28,
409 	.clock		= 24150,
410 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
411 	.width_mm	= 70,
412 	.height_mm	= 57,
413 };
414 
415 static const struct st7703_panel_desc rg353v2_desc = {
416 	.mode = &rg353v2_mode,
417 	.lanes = 4,
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,
422 };
423 
rgb30panel_init_sequence(struct mipi_dsi_multi_context * dsi_ctx)424 static void rgb30panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
425 {
426 	/* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
427 
428 	/*
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.
431 	 */
432 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
433 	mipi_dsi_msleep(dsi_ctx, 250);
434 
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,
441 				     0x63);
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,
453 				     0xc0, 0x10);
454 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
455 				     0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
456 				     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,
467 				     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,
476 				     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);
482 }
483 
484 static const struct drm_display_mode rgb30panel_mode = {
485 	.hdisplay	= 720,
486 	.hsync_start	= 720 + 45,
487 	.hsync_end	= 720 + 45 + 4,
488 	.htotal		= 720 + 45 + 4 + 45,
489 	.vdisplay	= 720,
490 	.vsync_start	= 720 + 15,
491 	.vsync_end	= 720 + 15 + 3,
492 	.vtotal		= 720 + 15 + 3 + 11,
493 	.clock		= 36570,
494 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
495 	.width_mm	= 76,
496 	.height_mm	= 76,
497 };
498 
499 static const struct st7703_panel_desc rgb30panel_desc = {
500 	.mode = &rgb30panel_mode,
501 	.lanes = 4,
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,
506 };
507 
rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context * dsi_ctx)508 static void rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
509 {
510 	/* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
511 
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,
514 				     0x80);
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,
522 				     0x63);
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,
533 				     0x77);
534 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
535 				     0x00, 0xff);
536 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
537 				     0x00, 0x00);
538 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
539 				     0x02);
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,
548 				     0xc0, 0x10);
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,
557 				     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,
566 				     0x00);
567 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
568 }
569 
570 static const struct drm_display_mode rgb10max3_panel_mode = {
571 	.hdisplay	= 720,
572 	.hsync_start	= 720 + 40,
573 	.hsync_end	= 720 + 40 + 10,
574 	.htotal		= 720 + 40 + 10 + 40,
575 	.vdisplay	= 1280,
576 	.vsync_start	= 1280 + 16,
577 	.vsync_end	= 1280 + 16 + 4,
578 	.vtotal		= 1280 + 16 + 4 + 14,
579 	.clock		= 63800,
580 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
581 	.width_mm	= 62,
582 	.height_mm	= 109,
583 };
584 
585 static const struct st7703_panel_desc rgb10max3_panel_desc = {
586 	.mode = &rgb10max3_panel_mode,
587 	.lanes = 4,
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,
592 };
593 
gameforcechi_init_sequence(struct mipi_dsi_multi_context * dsi_ctx)594 static void gameforcechi_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
595 {
596 	/*
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.
599 	 */
600 
601 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
602 	mipi_dsi_msleep(dsi_ctx, 250);
603 
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,
621 				     0xc0, 0x10);
622 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e,
623 				     0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33,
624 				     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,
635 				     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,
644 				     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);
650 }
651 
652 static const struct drm_display_mode gameforcechi_mode = {
653 	.hdisplay	= 640,
654 	.hsync_start	= 640 + 40,
655 	.hsync_end	= 640 + 40 + 2,
656 	.htotal		= 640 + 40 + 2 + 80,
657 	.vdisplay	= 480,
658 	.vsync_start	= 480 + 17,
659 	.vsync_end	= 480 + 17 + 5,
660 	.vtotal		= 480 + 17 + 5 + 13,
661 	.clock		= 23546,
662 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
663 	.width_mm	= 71,
664 	.height_mm	= 53,
665 };
666 
667 static const struct st7703_panel_desc gameforcechi_desc = {
668 	.mode = &gameforcechi_mode,
669 	.lanes = 2,
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,
674 };
675 
st7703_enable(struct drm_panel * panel)676 static int st7703_enable(struct drm_panel *panel)
677 {
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};
681 
682 	ctx->desc->init_sequence(&dsi_ctx);
683 
684 	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
685 
686 	/* It takes the controller 120 msec to wake up after sleep. */
687 	mipi_dsi_msleep(&dsi_ctx, 120);
688 
689 	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
690 
691 	if (!dsi_ctx.accum_err)
692 		dev_dbg(ctx->dev, "Panel init sequence done\n");
693 
694 	return dsi_ctx.accum_err;
695 }
696 
st7703_disable(struct drm_panel * panel)697 static int st7703_disable(struct drm_panel *panel)
698 {
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};
702 
703 	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
704 
705 	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
706 
707 	/* It takes the controller 120 msec to enter sleep mode. */
708 	mipi_dsi_msleep(&dsi_ctx, 120);
709 
710 	return dsi_ctx.accum_err;
711 }
712 
st7703_unprepare(struct drm_panel * panel)713 static int st7703_unprepare(struct drm_panel *panel)
714 {
715 	struct st7703 *ctx = panel_to_st7703(panel);
716 
717 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
718 	regulator_disable(ctx->iovcc);
719 	regulator_disable(ctx->vcc);
720 
721 	return 0;
722 }
723 
st7703_prepare(struct drm_panel * panel)724 static int st7703_prepare(struct drm_panel *panel)
725 {
726 	struct st7703 *ctx = panel_to_st7703(panel);
727 	int ret;
728 
729 	dev_dbg(ctx->dev, "Resetting the panel\n");
730 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
731 
732 	ret = regulator_enable(ctx->iovcc);
733 	if (ret < 0) {
734 		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
735 		return ret;
736 	}
737 
738 	ret = regulator_enable(ctx->vcc);
739 	if (ret < 0) {
740 		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
741 		regulator_disable(ctx->iovcc);
742 		return ret;
743 	}
744 
745 	/* Give power supplies time to stabilize before deasserting reset. */
746 	usleep_range(10000, 20000);
747 
748 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
749 	usleep_range(15000, 20000);
750 
751 	return 0;
752 }
753 
754 static const u32 mantix_bus_formats[] = {
755 	MEDIA_BUS_FMT_RGB888_1X24,
756 };
757 
st7703_get_modes(struct drm_panel * panel,struct drm_connector * connector)758 static int st7703_get_modes(struct drm_panel *panel,
759 			    struct drm_connector *connector)
760 {
761 	struct st7703 *ctx = panel_to_st7703(panel);
762 	struct drm_display_mode *mode;
763 
764 	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
765 	if (!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));
769 		return -ENOMEM;
770 	}
771 
772 	drm_mode_set_name(mode);
773 
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);
778 
779 	drm_display_info_set_bus_formats(&connector->display_info,
780 					 mantix_bus_formats,
781 					 ARRAY_SIZE(mantix_bus_formats));
782 
783 	return 1;
784 }
785 
st7703_get_orientation(struct drm_panel * panel)786 static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel)
787 {
788 	struct st7703 *st7703 = panel_to_st7703(panel);
789 
790 	return st7703->orientation;
791 }
792 
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,
800 };
801 
allpixelson_set(void * data,u64 val)802 static int allpixelson_set(void *data, u64 val)
803 {
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};
807 
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);
811 
812 	/*
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.
817 	 */
818 	drm_panel_disable(&ctx->panel);
819 	drm_panel_unprepare(&ctx->panel);
820 	drm_panel_prepare(&ctx->panel);
821 	drm_panel_enable(&ctx->panel);
822 
823 	return dsi_ctx.accum_err;
824 }
825 
826 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
827 			allpixelson_set, "%llu\n");
828 
st7703_debugfs_init(struct st7703 * ctx)829 static void st7703_debugfs_init(struct st7703 *ctx)
830 {
831 	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
832 
833 	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
834 			    &allpixelson_fops);
835 }
836 
st7703_debugfs_remove(struct st7703 * ctx)837 static void st7703_debugfs_remove(struct st7703 *ctx)
838 {
839 	debugfs_remove_recursive(ctx->debugfs);
840 	ctx->debugfs = NULL;
841 }
842 
st7703_probe(struct mipi_dsi_device * dsi)843 static int st7703_probe(struct mipi_dsi_device *dsi)
844 {
845 	struct device *dev = &dsi->dev;
846 	struct st7703 *ctx;
847 	int ret;
848 
849 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
850 	if (!ctx)
851 		return -ENOMEM;
852 
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");
856 
857 	mipi_dsi_set_drvdata(dsi, ctx);
858 
859 	ctx->dev = dev;
860 	ctx->desc = of_device_get_match_data(dev);
861 
862 	dsi->mode_flags = ctx->desc->mode_flags;
863 	dsi->format = ctx->desc->format;
864 	dsi->lanes = ctx->desc->lanes;
865 
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");
869 
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");
874 
875 	ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
876 	if (ret < 0)
877 		return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
878 
879 	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
880 		       DRM_MODE_CONNECTOR_DSI);
881 
882 	ret = drm_panel_of_backlight(&ctx->panel);
883 	if (ret)
884 		return ret;
885 
886 	drm_panel_add(&ctx->panel);
887 
888 	ret = mipi_dsi_attach(dsi);
889 	if (ret < 0) {
890 		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
891 		drm_panel_remove(&ctx->panel);
892 		return ret;
893 	}
894 
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);
899 
900 	st7703_debugfs_init(ctx);
901 	return 0;
902 }
903 
st7703_remove(struct mipi_dsi_device * dsi)904 static void st7703_remove(struct mipi_dsi_device *dsi)
905 {
906 	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
907 	int ret;
908 
909 	ret = mipi_dsi_detach(dsi);
910 	if (ret < 0)
911 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
912 
913 	drm_panel_remove(&ctx->panel);
914 
915 	st7703_debugfs_remove(ctx);
916 }
917 
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 },
925 	{ /* sentinel */ }
926 };
927 MODULE_DEVICE_TABLE(of, st7703_of_match);
928 
929 static struct mipi_dsi_driver st7703_driver = {
930 	.probe	= st7703_probe,
931 	.remove = st7703_remove,
932 	.driver = {
933 		.name = DRV_NAME,
934 		.of_match_table = st7703_of_match,
935 	},
936 };
937 module_mipi_dsi_driver(st7703_driver);
938 
939 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
940 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
941 MODULE_LICENSE("GPL v2");
942