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
134	return 0;
135}
136
137static 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
152static 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
161static 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
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 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
468static 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
485static 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
500static 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
535static const u32 mantix_bus_formats[] = {
536	MEDIA_BUS_FMT_RGB888_1X24,
537};
538
539static 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
567static 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
575static 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
592DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
593			allpixelson_set, "%llu\n");
594
595static 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
603static void st7703_debugfs_remove(struct st7703 *ctx)
604{
605	debugfs_remove_recursive(ctx->debugfs);
606	ctx->debugfs = NULL;
607}
608
609static 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
666static 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
680static 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
696static 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};
702MODULE_DEVICE_TABLE(of, st7703_of_match);
703
704static 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};
713module_mipi_dsi_driver(st7703_driver);
714
715MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
716MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
717MODULE_LICENSE("GPL v2");
718