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 bool prepared;
62
63 struct dentry *debugfs;
64 const struct st7703_panel_desc *desc;
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 int (*init_sequence)(struct st7703 *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 st7703 * ctx)80 static int jh057n_init_sequence(struct st7703 *ctx)
81 {
82 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
83
84 /*
85 * Init sequence was supplied by the panel vendor. Most of the commands
86 * resemble the ST7703 but the number of parameters often don't match
87 * so it's likely a clone.
88 */
89 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
90 0xF1, 0x12, 0x83);
91 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
92 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
93 0x00, 0x00);
94 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
95 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
96 0x00);
97 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
98 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
99 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
100 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
101 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
102 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
103 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
104 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
105 msleep(20);
106
107 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
108 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
109 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
110 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
111 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
112 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
113 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
114 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
115 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
116 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
118 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
119 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
121 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
122 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
123 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
126 0xA5, 0x00, 0x00, 0x00, 0x00);
127 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
128 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
129 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
130 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
131 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
132 0x11, 0x18);
133
134 return 0;
135 }
136
137 static const struct drm_display_mode jh057n00900_mode = {
138 .hdisplay = 720,
139 .hsync_start = 720 + 90,
140 .hsync_end = 720 + 90 + 20,
141 .htotal = 720 + 90 + 20 + 20,
142 .vdisplay = 1440,
143 .vsync_start = 1440 + 20,
144 .vsync_end = 1440 + 20 + 4,
145 .vtotal = 1440 + 20 + 4 + 12,
146 .clock = 75276,
147 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
148 .width_mm = 65,
149 .height_mm = 130,
150 };
151
152 static const struct st7703_panel_desc jh057n00900_panel_desc = {
153 .mode = &jh057n00900_mode,
154 .lanes = 4,
155 .mode_flags = MIPI_DSI_MODE_VIDEO |
156 MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
157 .format = MIPI_DSI_FMT_RGB888,
158 .init_sequence = jh057n_init_sequence,
159 };
160
xbd599_init_sequence(struct st7703 * ctx)161 static int xbd599_init_sequence(struct st7703 *ctx)
162 {
163 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
164
165 /*
166 * Init sequence was supplied by the panel vendor.
167 */
168
169 /* Magic sequence to unlock user commands below. */
170 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
171
172 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
173 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
174 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
175 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
176 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
177 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
178 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
179 /* The rest is undocumented in ST7703 datasheet */
180 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
182 0x4F, 0x11, 0x00, 0x00, 0x37);
183
184 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
185 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
186 0x22, /* DT = 15ms XDK_ECP = x2 */
187 0x20, /* PFM_DC_DIV = /1 */
188 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
189
190 /* RGB I/F porch timing */
191 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
192 0x10, /* VBP_RGB_GEN */
193 0x10, /* VFP_RGB_GEN */
194 0x05, /* DE_BP_RGB_GEN */
195 0x05, /* DE_FP_RGB_GEN */
196 /* The rest is undocumented in ST7703 datasheet */
197 0x03, 0xFF,
198 0x00, 0x00,
199 0x00, 0x00);
200
201 /* Source driving settings. */
202 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
203 0x73, /* N_POPON */
204 0x73, /* N_NOPON */
205 0x50, /* I_POPON */
206 0x50, /* I_NOPON */
207 0x00, /* SCR[31,24] */
208 0xC0, /* SCR[23,16] */
209 0x08, /* SCR[15,8] */
210 0x70, /* SCR[7,0] */
211 0x00 /* Undocumented */);
212
213 /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
214 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
215
216 /*
217 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
218 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
219 */
220 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
221
222 /* Zig-Zag Type C column inversion. */
223 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
224
225 /* Set display resolution. */
226 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
227 0xF0, /* NL = 240 */
228 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
229 * RESO_SEL = 720RGB
230 */
231 0xF0 /* WHITE_GND_EN = 1 (GND),
232 * WHITE_FRAME_SEL = 7 frames,
233 * ISC = 0 frames
234 */);
235
236 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
237 0x00, /* PNOEQ */
238 0x00, /* NNOEQ */
239 0x0B, /* PEQGND */
240 0x0B, /* NEQGND */
241 0x10, /* PEQVCI */
242 0x10, /* NEQVCI */
243 0x00, /* PEQVCI1 */
244 0x00, /* NEQVCI1 */
245 0x00, /* reserved */
246 0x00, /* reserved */
247 0xFF, /* reserved */
248 0x00, /* reserved */
249 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
250 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
251 * VEDIO_NO_CHECK_EN = 0
252 * ESD_WHITE_GND_EN = 0
253 * ESD_DET_TIME_SEL = 0 frames
254 */);
255
256 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
257
258 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
259 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
260 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
261 0x32, /* VRP */
262 0x32, /* VRN */
263 0x77, /* reserved */
264 0xF1, /* APS = 1 (small),
265 * VGL_DET_EN = 1, VGH_DET_EN = 1,
266 * VGL_TURBO = 1, VGH_TURBO = 1
267 */
268 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
269 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
270 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
271 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
272 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
273 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
274
275 /* Reference voltage. */
276 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
277 0x07, /* VREF_SEL = 4.2V */
278 0x07 /* NVREF_SEL = 4.2V */);
279 msleep(20);
280
281 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
282 0x2C, /* VCOMDC_F = -0.67V */
283 0x2C /* VCOMDC_B = -0.67V */);
284
285 /* Undocumented command. */
286 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
287
288 /* This command is to set forward GIP timing. */
289 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
290 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
291 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
292 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
293 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
294 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
295 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
296 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
298
299 /* This command is to set backward GIP timing. */
300 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
301 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
303 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
304 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
305 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
308 0xA5, 0x00, 0x00, 0x00, 0x00);
309
310 /* Adjust the gamma characteristics of the panel. */
311 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
312 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
313 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
314 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
315 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
316 0x12, 0x18);
317
318 return 0;
319 }
320
321 static const struct drm_display_mode xbd599_mode = {
322 .hdisplay = 720,
323 .hsync_start = 720 + 40,
324 .hsync_end = 720 + 40 + 40,
325 .htotal = 720 + 40 + 40 + 40,
326 .vdisplay = 1440,
327 .vsync_start = 1440 + 18,
328 .vsync_end = 1440 + 18 + 10,
329 .vtotal = 1440 + 18 + 10 + 17,
330 .clock = 69000,
331 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
332 .width_mm = 68,
333 .height_mm = 136,
334 };
335
336 static const struct st7703_panel_desc xbd599_desc = {
337 .mode = &xbd599_mode,
338 .lanes = 4,
339 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
340 .format = MIPI_DSI_FMT_RGB888,
341 .init_sequence = xbd599_init_sequence,
342 };
343
rg353v2_init_sequence(struct st7703 * ctx)344 static int rg353v2_init_sequence(struct st7703 *ctx)
345 {
346 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
347
348 /*
349 * Init sequence was supplied by the panel vendor.
350 */
351
352 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
353 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
354 0xda, 0x80);
355 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
356 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
357 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
358 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
359 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
360 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x92, 0x92);
361 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
362 0xf0, 0x63);
363 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
364 0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
366 0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
367 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);
368 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
369 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
370 0x00, 0x00, 0x12, 0x50, 0x00);
371 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
372 0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
373 0x33);
374 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
375 0x00, 0xff);
376 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
377 0x00, 0x00);
378 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
379 0x02);
380 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
381 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
382 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
383 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
384 0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
385 0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
386 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
387 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
388 0xc0, 0x10);
389 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
390 0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
391 0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
392 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
393 0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
394 0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
395 0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
396 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00);
398 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
399 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
401 0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
402 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
403 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 0x00);
407 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
408
409 return 0;
410 }
411
412 static const struct drm_display_mode rg353v2_mode = {
413 .hdisplay = 640,
414 .hsync_start = 640 + 40,
415 .hsync_end = 640 + 40 + 2,
416 .htotal = 640 + 40 + 2 + 80,
417 .vdisplay = 480,
418 .vsync_start = 480 + 18,
419 .vsync_end = 480 + 18 + 2,
420 .vtotal = 480 + 18 + 2 + 28,
421 .clock = 24150,
422 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
423 .width_mm = 70,
424 .height_mm = 57,
425 };
426
427 static const struct st7703_panel_desc rg353v2_desc = {
428 .mode = &rg353v2_mode,
429 .lanes = 4,
430 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
431 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
432 .format = MIPI_DSI_FMT_RGB888,
433 .init_sequence = rg353v2_init_sequence,
434 };
435
st7703_enable(struct drm_panel * panel)436 static int st7703_enable(struct drm_panel *panel)
437 {
438 struct st7703 *ctx = panel_to_st7703(panel);
439 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
440 int ret;
441
442 ret = ctx->desc->init_sequence(ctx);
443 if (ret < 0) {
444 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
445 return ret;
446 }
447
448 msleep(20);
449
450 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
451 if (ret < 0) {
452 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
453 return ret;
454 }
455
456 /* Panel is operational 120 msec after reset */
457 msleep(60);
458
459 ret = mipi_dsi_dcs_set_display_on(dsi);
460 if (ret)
461 return ret;
462
463 dev_dbg(ctx->dev, "Panel init sequence done\n");
464
465 return 0;
466 }
467
st7703_disable(struct drm_panel * panel)468 static int st7703_disable(struct drm_panel *panel)
469 {
470 struct st7703 *ctx = panel_to_st7703(panel);
471 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
472 int ret;
473
474 ret = mipi_dsi_dcs_set_display_off(dsi);
475 if (ret < 0)
476 dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
477
478 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
479 if (ret < 0)
480 dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
481
482 return 0;
483 }
484
st7703_unprepare(struct drm_panel * panel)485 static int st7703_unprepare(struct drm_panel *panel)
486 {
487 struct st7703 *ctx = panel_to_st7703(panel);
488
489 if (!ctx->prepared)
490 return 0;
491
492 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
493 regulator_disable(ctx->iovcc);
494 regulator_disable(ctx->vcc);
495 ctx->prepared = false;
496
497 return 0;
498 }
499
st7703_prepare(struct drm_panel * panel)500 static int st7703_prepare(struct drm_panel *panel)
501 {
502 struct st7703 *ctx = panel_to_st7703(panel);
503 int ret;
504
505 if (ctx->prepared)
506 return 0;
507
508 dev_dbg(ctx->dev, "Resetting the panel\n");
509 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
510
511 ret = regulator_enable(ctx->iovcc);
512 if (ret < 0) {
513 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
514 return ret;
515 }
516
517 ret = regulator_enable(ctx->vcc);
518 if (ret < 0) {
519 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
520 regulator_disable(ctx->iovcc);
521 return ret;
522 }
523
524 /* Give power supplies time to stabilize before deasserting reset. */
525 usleep_range(10000, 20000);
526
527 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
528 usleep_range(15000, 20000);
529
530 ctx->prepared = true;
531
532 return 0;
533 }
534
535 static const u32 mantix_bus_formats[] = {
536 MEDIA_BUS_FMT_RGB888_1X24,
537 };
538
st7703_get_modes(struct drm_panel * panel,struct drm_connector * connector)539 static int st7703_get_modes(struct drm_panel *panel,
540 struct drm_connector *connector)
541 {
542 struct st7703 *ctx = panel_to_st7703(panel);
543 struct drm_display_mode *mode;
544
545 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
546 if (!mode) {
547 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
548 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
549 drm_mode_vrefresh(ctx->desc->mode));
550 return -ENOMEM;
551 }
552
553 drm_mode_set_name(mode);
554
555 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
556 connector->display_info.width_mm = mode->width_mm;
557 connector->display_info.height_mm = mode->height_mm;
558 drm_mode_probed_add(connector, mode);
559
560 drm_display_info_set_bus_formats(&connector->display_info,
561 mantix_bus_formats,
562 ARRAY_SIZE(mantix_bus_formats));
563
564 return 1;
565 }
566
567 static const struct drm_panel_funcs st7703_drm_funcs = {
568 .disable = st7703_disable,
569 .unprepare = st7703_unprepare,
570 .prepare = st7703_prepare,
571 .enable = st7703_enable,
572 .get_modes = st7703_get_modes,
573 };
574
allpixelson_set(void * data,u64 val)575 static int allpixelson_set(void *data, u64 val)
576 {
577 struct st7703 *ctx = data;
578 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
579
580 dev_dbg(ctx->dev, "Setting all pixels on\n");
581 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
582 msleep(val * 1000);
583 /* Reset the panel to get video back */
584 drm_panel_disable(&ctx->panel);
585 drm_panel_unprepare(&ctx->panel);
586 drm_panel_prepare(&ctx->panel);
587 drm_panel_enable(&ctx->panel);
588
589 return 0;
590 }
591
592 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
593 allpixelson_set, "%llu\n");
594
st7703_debugfs_init(struct st7703 * ctx)595 static void st7703_debugfs_init(struct st7703 *ctx)
596 {
597 ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
598
599 debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
600 &allpixelson_fops);
601 }
602
st7703_debugfs_remove(struct st7703 * ctx)603 static void st7703_debugfs_remove(struct st7703 *ctx)
604 {
605 debugfs_remove_recursive(ctx->debugfs);
606 ctx->debugfs = NULL;
607 }
608
st7703_probe(struct mipi_dsi_device * dsi)609 static int st7703_probe(struct mipi_dsi_device *dsi)
610 {
611 struct device *dev = &dsi->dev;
612 struct st7703 *ctx;
613 int ret;
614
615 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
616 if (!ctx)
617 return -ENOMEM;
618
619 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
620 if (IS_ERR(ctx->reset_gpio))
621 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
622
623 mipi_dsi_set_drvdata(dsi, ctx);
624
625 ctx->dev = dev;
626 ctx->desc = of_device_get_match_data(dev);
627
628 dsi->mode_flags = ctx->desc->mode_flags;
629 dsi->format = ctx->desc->format;
630 dsi->lanes = ctx->desc->lanes;
631
632 ctx->vcc = devm_regulator_get(dev, "vcc");
633 if (IS_ERR(ctx->vcc))
634 return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
635
636 ctx->iovcc = devm_regulator_get(dev, "iovcc");
637 if (IS_ERR(ctx->iovcc))
638 return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
639 "Failed to request iovcc regulator\n");
640
641 drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
642 DRM_MODE_CONNECTOR_DSI);
643
644 ret = drm_panel_of_backlight(&ctx->panel);
645 if (ret)
646 return ret;
647
648 drm_panel_add(&ctx->panel);
649
650 ret = mipi_dsi_attach(dsi);
651 if (ret < 0) {
652 dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
653 drm_panel_remove(&ctx->panel);
654 return ret;
655 }
656
657 dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
658 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
659 drm_mode_vrefresh(ctx->desc->mode),
660 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
661
662 st7703_debugfs_init(ctx);
663 return 0;
664 }
665
st7703_shutdown(struct mipi_dsi_device * dsi)666 static void st7703_shutdown(struct mipi_dsi_device *dsi)
667 {
668 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
669 int ret;
670
671 ret = drm_panel_unprepare(&ctx->panel);
672 if (ret < 0)
673 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
674
675 ret = drm_panel_disable(&ctx->panel);
676 if (ret < 0)
677 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
678 }
679
st7703_remove(struct mipi_dsi_device * dsi)680 static void st7703_remove(struct mipi_dsi_device *dsi)
681 {
682 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
683 int ret;
684
685 st7703_shutdown(dsi);
686
687 ret = mipi_dsi_detach(dsi);
688 if (ret < 0)
689 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
690
691 drm_panel_remove(&ctx->panel);
692
693 st7703_debugfs_remove(ctx);
694 }
695
696 static const struct of_device_id st7703_of_match[] = {
697 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
698 { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
699 { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
700 { /* sentinel */ }
701 };
702 MODULE_DEVICE_TABLE(of, st7703_of_match);
703
704 static struct mipi_dsi_driver st7703_driver = {
705 .probe = st7703_probe,
706 .remove = st7703_remove,
707 .shutdown = st7703_shutdown,
708 .driver = {
709 .name = DRV_NAME,
710 .of_match_table = st7703_of_match,
711 },
712 };
713 module_mipi_dsi_driver(st7703_driver);
714
715 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
716 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
717 MODULE_LICENSE("GPL v2");
718