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