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