Loading...
Note: File does not exist in v3.1.
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
55struct 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
67struct 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
75static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
76{
77 return container_of(panel, struct st7703, panel);
78}
79
80static 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 msleep(20);
134
135 return 0;
136}
137
138static const struct drm_display_mode jh057n00900_mode = {
139 .hdisplay = 720,
140 .hsync_start = 720 + 90,
141 .hsync_end = 720 + 90 + 20,
142 .htotal = 720 + 90 + 20 + 20,
143 .vdisplay = 1440,
144 .vsync_start = 1440 + 20,
145 .vsync_end = 1440 + 20 + 4,
146 .vtotal = 1440 + 20 + 4 + 12,
147 .clock = 75276,
148 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
149 .width_mm = 65,
150 .height_mm = 130,
151};
152
153static const struct st7703_panel_desc jh057n00900_panel_desc = {
154 .mode = &jh057n00900_mode,
155 .lanes = 4,
156 .mode_flags = MIPI_DSI_MODE_VIDEO |
157 MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
158 .format = MIPI_DSI_FMT_RGB888,
159 .init_sequence = jh057n_init_sequence,
160};
161
162static int xbd599_init_sequence(struct st7703 *ctx)
163{
164 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
165
166 /*
167 * Init sequence was supplied by the panel vendor.
168 */
169
170 /* Magic sequence to unlock user commands below. */
171 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
172
173 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
174 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
175 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
176 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
177 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
178 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
179 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
180 /* The rest is undocumented in ST7703 datasheet */
181 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
183 0x4F, 0x11, 0x00, 0x00, 0x37);
184
185 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
186 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
187 0x22, /* DT = 15ms XDK_ECP = x2 */
188 0x20, /* PFM_DC_DIV = /1 */
189 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
190
191 /* RGB I/F porch timing */
192 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
193 0x10, /* VBP_RGB_GEN */
194 0x10, /* VFP_RGB_GEN */
195 0x05, /* DE_BP_RGB_GEN */
196 0x05, /* DE_FP_RGB_GEN */
197 /* The rest is undocumented in ST7703 datasheet */
198 0x03, 0xFF,
199 0x00, 0x00,
200 0x00, 0x00);
201
202 /* Source driving settings. */
203 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
204 0x73, /* N_POPON */
205 0x73, /* N_NOPON */
206 0x50, /* I_POPON */
207 0x50, /* I_NOPON */
208 0x00, /* SCR[31,24] */
209 0xC0, /* SCR[23,16] */
210 0x08, /* SCR[15,8] */
211 0x70, /* SCR[7,0] */
212 0x00 /* Undocumented */);
213
214 /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
215 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
216
217 /*
218 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
219 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
220 */
221 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
222
223 /* Zig-Zag Type C column inversion. */
224 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
225
226 /* Set display resolution. */
227 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
228 0xF0, /* NL = 240 */
229 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
230 * RESO_SEL = 720RGB
231 */
232 0xF0 /* WHITE_GND_EN = 1 (GND),
233 * WHITE_FRAME_SEL = 7 frames,
234 * ISC = 0 frames
235 */);
236
237 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
238 0x00, /* PNOEQ */
239 0x00, /* NNOEQ */
240 0x0B, /* PEQGND */
241 0x0B, /* NEQGND */
242 0x10, /* PEQVCI */
243 0x10, /* NEQVCI */
244 0x00, /* PEQVCI1 */
245 0x00, /* NEQVCI1 */
246 0x00, /* reserved */
247 0x00, /* reserved */
248 0xFF, /* reserved */
249 0x00, /* reserved */
250 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
251 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
252 * VEDIO_NO_CHECK_EN = 0
253 * ESD_WHITE_GND_EN = 0
254 * ESD_DET_TIME_SEL = 0 frames
255 */);
256
257 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
258
259 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
260 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
261 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
262 0x32, /* VRP */
263 0x32, /* VRN */
264 0x77, /* reserved */
265 0xF1, /* APS = 1 (small),
266 * VGL_DET_EN = 1, VGH_DET_EN = 1,
267 * VGL_TURBO = 1, VGH_TURBO = 1
268 */
269 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
270 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
271 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
272 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
273 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
274 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
275
276 /* Reference voltage. */
277 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
278 0x07, /* VREF_SEL = 4.2V */
279 0x07 /* NVREF_SEL = 4.2V */);
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
321static 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
336static 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
344static 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
412static 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
427static 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
436static int rgb30panel_init_sequence(struct st7703 *ctx)
437{
438 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
439
440 /* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
441
442 /*
443 * For some reason this specific panel must be taken out of sleep
444 * before the full init sequence, or else it will not display.
445 */
446 mipi_dsi_dcs_exit_sleep_mode(dsi);
447 msleep(250);
448
449 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
450 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
451 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
452 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
453 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
454 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
455 0x63);
456 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
457 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
458 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
459 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
460 0x00, 0x00, 0x12, 0x70, 0x00);
461 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46);
462 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
463 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
464 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
465 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
466 0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
467 0xc0, 0x10);
468 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
469 0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
470 0x33);
471 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
472 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x88, 0x88);
473 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
474 0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
475 0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
476 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
477 0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
478 0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
479 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x00);
482 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
483 0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
485 0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
486 0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
487 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
490 0x00);
491 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
492 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
493 0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
494 0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
495 0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
496
497 return 0;
498}
499
500static const struct drm_display_mode rgb30panel_mode = {
501 .hdisplay = 720,
502 .hsync_start = 720 + 45,
503 .hsync_end = 720 + 45 + 4,
504 .htotal = 720 + 45 + 4 + 45,
505 .vdisplay = 720,
506 .vsync_start = 720 + 15,
507 .vsync_end = 720 + 15 + 3,
508 .vtotal = 720 + 15 + 3 + 11,
509 .clock = 36570,
510 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
511 .width_mm = 76,
512 .height_mm = 76,
513};
514
515static const struct st7703_panel_desc rgb30panel_desc = {
516 .mode = &rgb30panel_mode,
517 .lanes = 4,
518 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
519 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
520 .format = MIPI_DSI_FMT_RGB888,
521 .init_sequence = rgb30panel_init_sequence,
522};
523
524static int st7703_enable(struct drm_panel *panel)
525{
526 struct st7703 *ctx = panel_to_st7703(panel);
527 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
528 int ret;
529
530 ret = ctx->desc->init_sequence(ctx);
531 if (ret < 0) {
532 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
533 return ret;
534 }
535
536 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
537 if (ret < 0) {
538 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
539 return ret;
540 }
541
542 /* It takes the controller 120 msec to wake up after sleep. */
543 msleep(120);
544
545 ret = mipi_dsi_dcs_set_display_on(dsi);
546 if (ret)
547 return ret;
548
549 dev_dbg(ctx->dev, "Panel init sequence done\n");
550
551 return 0;
552}
553
554static int st7703_disable(struct drm_panel *panel)
555{
556 struct st7703 *ctx = panel_to_st7703(panel);
557 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
558 int ret;
559
560 ret = mipi_dsi_dcs_set_display_off(dsi);
561 if (ret < 0)
562 dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
563
564 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
565 if (ret < 0)
566 dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
567
568 /* It takes the controller 120 msec to enter sleep mode. */
569 msleep(120);
570
571 return 0;
572}
573
574static int st7703_unprepare(struct drm_panel *panel)
575{
576 struct st7703 *ctx = panel_to_st7703(panel);
577
578 if (!ctx->prepared)
579 return 0;
580
581 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
582 regulator_disable(ctx->iovcc);
583 regulator_disable(ctx->vcc);
584 ctx->prepared = false;
585
586 return 0;
587}
588
589static int st7703_prepare(struct drm_panel *panel)
590{
591 struct st7703 *ctx = panel_to_st7703(panel);
592 int ret;
593
594 if (ctx->prepared)
595 return 0;
596
597 dev_dbg(ctx->dev, "Resetting the panel\n");
598 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
599
600 ret = regulator_enable(ctx->iovcc);
601 if (ret < 0) {
602 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
603 return ret;
604 }
605
606 ret = regulator_enable(ctx->vcc);
607 if (ret < 0) {
608 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
609 regulator_disable(ctx->iovcc);
610 return ret;
611 }
612
613 /* Give power supplies time to stabilize before deasserting reset. */
614 usleep_range(10000, 20000);
615
616 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
617 usleep_range(15000, 20000);
618
619 ctx->prepared = true;
620
621 return 0;
622}
623
624static const u32 mantix_bus_formats[] = {
625 MEDIA_BUS_FMT_RGB888_1X24,
626};
627
628static int st7703_get_modes(struct drm_panel *panel,
629 struct drm_connector *connector)
630{
631 struct st7703 *ctx = panel_to_st7703(panel);
632 struct drm_display_mode *mode;
633
634 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
635 if (!mode) {
636 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
637 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
638 drm_mode_vrefresh(ctx->desc->mode));
639 return -ENOMEM;
640 }
641
642 drm_mode_set_name(mode);
643
644 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
645 connector->display_info.width_mm = mode->width_mm;
646 connector->display_info.height_mm = mode->height_mm;
647 drm_mode_probed_add(connector, mode);
648
649 drm_display_info_set_bus_formats(&connector->display_info,
650 mantix_bus_formats,
651 ARRAY_SIZE(mantix_bus_formats));
652
653 return 1;
654}
655
656static const struct drm_panel_funcs st7703_drm_funcs = {
657 .disable = st7703_disable,
658 .unprepare = st7703_unprepare,
659 .prepare = st7703_prepare,
660 .enable = st7703_enable,
661 .get_modes = st7703_get_modes,
662};
663
664static int allpixelson_set(void *data, u64 val)
665{
666 struct st7703 *ctx = data;
667 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
668
669 dev_dbg(ctx->dev, "Setting all pixels on\n");
670 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
671 msleep(val * 1000);
672 /* Reset the panel to get video back */
673 drm_panel_disable(&ctx->panel);
674 drm_panel_unprepare(&ctx->panel);
675 drm_panel_prepare(&ctx->panel);
676 drm_panel_enable(&ctx->panel);
677
678 return 0;
679}
680
681DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
682 allpixelson_set, "%llu\n");
683
684static void st7703_debugfs_init(struct st7703 *ctx)
685{
686 ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
687
688 debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
689 &allpixelson_fops);
690}
691
692static void st7703_debugfs_remove(struct st7703 *ctx)
693{
694 debugfs_remove_recursive(ctx->debugfs);
695 ctx->debugfs = NULL;
696}
697
698static int st7703_probe(struct mipi_dsi_device *dsi)
699{
700 struct device *dev = &dsi->dev;
701 struct st7703 *ctx;
702 int ret;
703
704 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
705 if (!ctx)
706 return -ENOMEM;
707
708 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
709 if (IS_ERR(ctx->reset_gpio))
710 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
711
712 mipi_dsi_set_drvdata(dsi, ctx);
713
714 ctx->dev = dev;
715 ctx->desc = of_device_get_match_data(dev);
716
717 dsi->mode_flags = ctx->desc->mode_flags;
718 dsi->format = ctx->desc->format;
719 dsi->lanes = ctx->desc->lanes;
720
721 ctx->vcc = devm_regulator_get(dev, "vcc");
722 if (IS_ERR(ctx->vcc))
723 return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
724
725 ctx->iovcc = devm_regulator_get(dev, "iovcc");
726 if (IS_ERR(ctx->iovcc))
727 return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
728 "Failed to request iovcc regulator\n");
729
730 drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
731 DRM_MODE_CONNECTOR_DSI);
732
733 ret = drm_panel_of_backlight(&ctx->panel);
734 if (ret)
735 return ret;
736
737 drm_panel_add(&ctx->panel);
738
739 ret = mipi_dsi_attach(dsi);
740 if (ret < 0) {
741 dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
742 drm_panel_remove(&ctx->panel);
743 return ret;
744 }
745
746 dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
747 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
748 drm_mode_vrefresh(ctx->desc->mode),
749 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
750
751 st7703_debugfs_init(ctx);
752 return 0;
753}
754
755static void st7703_shutdown(struct mipi_dsi_device *dsi)
756{
757 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
758 int ret;
759
760 ret = drm_panel_unprepare(&ctx->panel);
761 if (ret < 0)
762 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
763
764 ret = drm_panel_disable(&ctx->panel);
765 if (ret < 0)
766 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
767}
768
769static void st7703_remove(struct mipi_dsi_device *dsi)
770{
771 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
772 int ret;
773
774 st7703_shutdown(dsi);
775
776 ret = mipi_dsi_detach(dsi);
777 if (ret < 0)
778 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
779
780 drm_panel_remove(&ctx->panel);
781
782 st7703_debugfs_remove(ctx);
783}
784
785static const struct of_device_id st7703_of_match[] = {
786 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
787 { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
788 { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
789 { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
790 { /* sentinel */ }
791};
792MODULE_DEVICE_TABLE(of, st7703_of_match);
793
794static struct mipi_dsi_driver st7703_driver = {
795 .probe = st7703_probe,
796 .remove = st7703_remove,
797 .shutdown = st7703_shutdown,
798 .driver = {
799 .name = DRV_NAME,
800 .of_match_table = st7703_of_match,
801 },
802};
803module_mipi_dsi_driver(st7703_driver);
804
805MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
806MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
807MODULE_LICENSE("GPL v2");