Linux Audio

Check our new training course

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");