Linux Audio

Check our new training course

Loading...
v6.13.7
  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
 62	struct dentry *debugfs;
 63	const struct st7703_panel_desc *desc;
 64	enum drm_panel_orientation orientation;
 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	void (*init_sequence)(struct mipi_dsi_multi_context *dsi_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 void jh057n_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
 
 
 
 
 
 
 
 
 81{
 
 
 82	/*
 83	 * Init sequence was supplied by the panel vendor. Most of the commands
 84	 * resemble the ST7703 but the number of parameters often don't match
 85	 * so it's likely a clone.
 86	 */
 87	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC,
 88					 0xF1, 0x12, 0x83);
 89	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
 90					 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
 91					 0x00, 0x00);
 92	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
 93					 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
 94					 0x00);
 95	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
 96	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
 97	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
 98	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
 99	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
100					 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
101					 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
102	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x08, 0x08);
103	mipi_dsi_msleep(dsi_ctx, 20);
104
105	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
106	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
107	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
108					 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
109					 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
110					 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
111					 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
112					 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
113					 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
114					 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
116	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
117					 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118					 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
119					 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
120					 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
121					 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
122					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
124					 0xA5, 0x00, 0x00, 0x00, 0x00);
125	mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
126					 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
127					 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
128					 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
129					 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
130					 0x11, 0x18);
131	mipi_dsi_msleep(dsi_ctx, 20);
 
132}
133
134static const struct drm_display_mode jh057n00900_mode = {
135	.hdisplay    = 720,
136	.hsync_start = 720 + 90,
137	.hsync_end   = 720 + 90 + 20,
138	.htotal	     = 720 + 90 + 20 + 20,
139	.vdisplay    = 1440,
140	.vsync_start = 1440 + 20,
141	.vsync_end   = 1440 + 20 + 4,
142	.vtotal	     = 1440 + 20 + 4 + 12,
143	.clock	     = 75276,
144	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
145	.width_mm    = 65,
146	.height_mm   = 130,
147};
148
149static const struct st7703_panel_desc jh057n00900_panel_desc = {
150	.mode = &jh057n00900_mode,
151	.lanes = 4,
152	.mode_flags = MIPI_DSI_MODE_VIDEO |
153		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
154	.format = MIPI_DSI_FMT_RGB888,
155	.init_sequence = jh057n_init_sequence,
156};
157
158static void xbd599_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
 
 
 
 
 
 
 
 
 
159{
 
 
160	/*
161	 * Init sequence was supplied by the panel vendor.
162	 */
163
164	/* Magic sequence to unlock user commands below. */
165	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
166
167	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI,
168				     0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
169				     0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
170				     0x05, /* IHSRX = x6 (Low High Speed driving ability) */
171				     0xF9, /* TX_CLK_SEL = fDSICLK/16 */
172				     0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
173				     0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
174				     /* The rest is undocumented in ST7703 datasheet */
175				     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176				     0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
177				     0x4F, 0x11, 0x00, 0x00, 0x37);
178
179	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT,
180				     0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
181				     0x22, /* DT = 15ms XDK_ECP = x2 */
182				     0x20, /* PFM_DC_DIV = /1 */
183				     0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
184
185	/* RGB I/F porch timing */
186	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
187				     0x10, /* VBP_RGB_GEN */
188				     0x10, /* VFP_RGB_GEN */
189				     0x05, /* DE_BP_RGB_GEN */
190				     0x05, /* DE_FP_RGB_GEN */
191				     /* The rest is undocumented in ST7703 datasheet */
192				     0x03, 0xFF,
193				     0x00, 0x00,
194				     0x00, 0x00);
195
196	/* Source driving settings. */
197	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
198				     0x73, /* N_POPON */
199				     0x73, /* N_NOPON */
200				     0x50, /* I_POPON */
201				     0x50, /* I_NOPON */
202				     0x00, /* SCR[31,24] */
203				     0xC0, /* SCR[23,16] */
204				     0x08, /* SCR[15,8] */
205				     0x70, /* SCR[7,0] */
206				     0x00  /* Undocumented */);
207
208	/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
209	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
210
211	/*
212	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
213	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
214	 */
215	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
216
217	/* Zig-Zag Type C column inversion. */
218	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
219
220	/* Set display resolution. */
221	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP,
222				     0xF0, /* NL = 240 */
223				     0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
224					    * RESO_SEL = 720RGB
225					    */
226				     0xF0  /* WHITE_GND_EN = 1 (GND),
227					    * WHITE_FRAME_SEL = 7 frames,
228					    * ISC = 0 frames
229					    */);
230
231	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
232				     0x00, /* PNOEQ */
233				     0x00, /* NNOEQ */
234				     0x0B, /* PEQGND */
235				     0x0B, /* NEQGND */
236				     0x10, /* PEQVCI */
237				     0x10, /* NEQVCI */
238				     0x00, /* PEQVCI1 */
239				     0x00, /* NEQVCI1 */
240				     0x00, /* reserved */
241				     0x00, /* reserved */
242				     0xFF, /* reserved */
243				     0x00, /* reserved */
244				     0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
245				     0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
246					    * VEDIO_NO_CHECK_EN = 0
247					    * ESD_WHITE_GND_EN = 0
248					    * ESD_DET_TIME_SEL = 0 frames
249					    */);
250
251	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
252
253	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER,
254				     0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
255				     0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
256				     0x32, /* VRP  */
257				     0x32, /* VRN */
258				     0x77, /* reserved */
259				     0xF1, /* APS = 1 (small),
260					    * VGL_DET_EN = 1, VGH_DET_EN = 1,
261					    * VGL_TURBO = 1, VGH_TURBO = 1
262					    */
263				     0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
264				     0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
265				     0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
266				     0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
267				     0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
268				     0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
 
269
270	/* Reference voltage. */
271	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP,
272				     0x07, /* VREF_SEL = 4.2V */
273				     0x07  /* NVREF_SEL = 4.2V */);
274
275	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM,
276				     0x2C, /* VCOMDC_F = -0.67V */
277				     0x2C  /* VCOMDC_B = -0.67V */);
 
278
279	/* Undocumented command. */
280	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
281
282	/* This command is to set forward GIP timing. */
283	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
284				     0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
285				     0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
286				     0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
287				     0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
288				     0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
289				     0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
290				     0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
292
293	/* This command is to set backward GIP timing. */
294	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
295				     0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296				     0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
297				     0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
298				     0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
299				     0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
300				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
302				     0xA5, 0x00, 0x00, 0x00, 0x00);
303
304	/* Adjust the gamma characteristics of the panel. */
305	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
306				     0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
307				     0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
308				     0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
309				     0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
310				     0x12, 0x18);
 
 
311}
312
313static const struct drm_display_mode xbd599_mode = {
314	.hdisplay    = 720,
315	.hsync_start = 720 + 40,
316	.hsync_end   = 720 + 40 + 40,
317	.htotal	     = 720 + 40 + 40 + 40,
318	.vdisplay    = 1440,
319	.vsync_start = 1440 + 18,
320	.vsync_end   = 1440 + 18 + 10,
321	.vtotal	     = 1440 + 18 + 10 + 17,
322	.clock	     = 69000,
323	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
324	.width_mm    = 68,
325	.height_mm   = 136,
326};
327
328static const struct st7703_panel_desc xbd599_desc = {
329	.mode = &xbd599_mode,
330	.lanes = 4,
331	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
332	.format = MIPI_DSI_FMT_RGB888,
333	.init_sequence = xbd599_init_sequence,
334};
335
336static void rg353v2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
337{
338	/*
339	 * Init sequence was supplied by the panel vendor.
340	 */
341
342	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
343	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
344				     0xda, 0x80);
345	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
346	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
347				     0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
348	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
349	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
350	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x92, 0x92);
351	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
352				     0xf0, 0x63);
353	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
354				     0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
355				     0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
356				     0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
357	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
358	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
359	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
360				     0x00, 0x00, 0x12, 0x50, 0x00);
361	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
362				     0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
363				     0x33);
364	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
365				     0x00, 0xff);
366	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
367				     0x00, 0x00);
368	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
369				     0x02);
370	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
371	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
372				     0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
373				     0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
374				     0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
375				     0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
376	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
377				     0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
378				     0xc0, 0x10);
379	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
380				     0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
381				     0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
382				     0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
383				     0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
384				     0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
385				     0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
386				     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387				     0x00, 0x00, 0x00);
388	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
389				     0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390				     0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
391				     0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
392				     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
393				     0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
394				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396				     0x00);
397	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
398}
399
400static const struct drm_display_mode rg353v2_mode = {
401	.hdisplay	= 640,
402	.hsync_start	= 640 + 40,
403	.hsync_end	= 640 + 40 + 2,
404	.htotal		= 640 + 40 + 2 + 80,
405	.vdisplay	= 480,
406	.vsync_start	= 480 + 18,
407	.vsync_end	= 480 + 18 + 2,
408	.vtotal		= 480 + 18 + 2 + 28,
409	.clock		= 24150,
410	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
411	.width_mm	= 70,
412	.height_mm	= 57,
413};
414
415static const struct st7703_panel_desc rg353v2_desc = {
416	.mode = &rg353v2_mode,
417	.lanes = 4,
418	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
419		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
420	.format = MIPI_DSI_FMT_RGB888,
421	.init_sequence = rg353v2_init_sequence,
422};
423
424static void rgb30panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
425{
426	/* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
427
428	/*
429	 * For some reason this specific panel must be taken out of sleep
430	 * before the full init sequence, or else it will not display.
431	 */
432	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
433	mipi_dsi_msleep(dsi_ctx, 250);
434
435	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
436	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
437				     0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
438				     0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
439				     0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
440	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
441				     0x63);
442	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
443	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
444				     0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
445	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
446				     0x00, 0x00, 0x12, 0x70, 0x00);
447	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
448	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
449	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
450	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
451	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
452				     0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
453				     0xc0, 0x10);
454	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
455				     0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
456				     0x33);
457	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
458	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x88, 0x88);
459	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
460				     0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
461				     0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
462				     0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
463				     0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
464				     0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
465				     0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
466				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467				     0x00, 0x00, 0x00);
468	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
469				     0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
470				     0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
471				     0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
472				     0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
473				     0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
474				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475				     0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
476				     0x00);
477	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
478				     0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
479				     0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
480				     0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
481				     0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
482}
483
484static const struct drm_display_mode rgb30panel_mode = {
485	.hdisplay	= 720,
486	.hsync_start	= 720 + 45,
487	.hsync_end	= 720 + 45 + 4,
488	.htotal		= 720 + 45 + 4 + 45,
489	.vdisplay	= 720,
490	.vsync_start	= 720 + 15,
491	.vsync_end	= 720 + 15 + 3,
492	.vtotal		= 720 + 15 + 3 + 11,
493	.clock		= 36570,
494	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
495	.width_mm	= 76,
496	.height_mm	= 76,
497};
498
499static const struct st7703_panel_desc rgb30panel_desc = {
500	.mode = &rgb30panel_mode,
501	.lanes = 4,
502	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
503		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
504	.format = MIPI_DSI_FMT_RGB888,
505	.init_sequence = rgb30panel_init_sequence,
506};
507
508static void rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
509{
510	/* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
511
512	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
513	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda,
514				     0x80);
515	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30);
516	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
517				     0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
518	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
519	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x04, 0x04);
520	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x78, 0x78);
521	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
522				     0x63);
523	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
524				     0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
525				     0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
526				     0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
527	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
528	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
529	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
530				     0x00, 0x00, 0x12, 0x70, 0x00);
531	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32,
532				     0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77,
533				     0x77);
534	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
535				     0x00, 0xff);
536	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
537				     0x00, 0x00);
538	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
539				     0x02);
540	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
541	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07,
542				     0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e,
543				     0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04,
544				     0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b,
545				     0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
546	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03,
547				     0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80,
548				     0xc0, 0x10);
549	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00,
550				     0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86,
551				     0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00,
552				     0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
553				     0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88,
554				     0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88,
555				     0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00,
556				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557				     0x00, 0x00, 0x00);
558	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00,
559				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560				     0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88,
561				     0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88,
562				     0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00,
563				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566				     0x00);
567	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
568}
569
570static const struct drm_display_mode rgb10max3_panel_mode = {
571	.hdisplay	= 720,
572	.hsync_start	= 720 + 40,
573	.hsync_end	= 720 + 40 + 10,
574	.htotal		= 720 + 40 + 10 + 40,
575	.vdisplay	= 1280,
576	.vsync_start	= 1280 + 16,
577	.vsync_end	= 1280 + 16 + 4,
578	.vtotal		= 1280 + 16 + 4 + 14,
579	.clock		= 63800,
580	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
581	.width_mm	= 62,
582	.height_mm	= 109,
583};
584
585static const struct st7703_panel_desc rgb10max3_panel_desc = {
586	.mode = &rgb10max3_panel_mode,
587	.lanes = 4,
588	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
589		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
590	.format = MIPI_DSI_FMT_RGB888,
591	.init_sequence = rgb10max3_panel_init_sequence,
592};
593
594static void gameforcechi_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
595{
596	/*
597	 * Init sequence was supplied by the panel vendor. Panel will not
598	 * respond to commands until it is brought out of sleep mode first.
599	 */
600
601	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
602	mipi_dsi_msleep(dsi_ctx, 250);
603
604	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
605	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x31, 0x81, 0x05, 0xf9,
606				     0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
607				     0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00,
608				     0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37);
609	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25);
610	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
611	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a,
612				     0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
613	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
614				     0x00, 0x00, 0x08, 0x70, 0x00);
615	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
616	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
617	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
618	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0);
619	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
620				     0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
621				     0xc0, 0x10);
622	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e,
623				     0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33,
624				     0x33);
625	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x10, 0x10);
626	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x6c, 0x7c);
627	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0x08, 0x00, 0x0e, 0x00,
628				     0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x10,
629				     0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
630				     0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
631				     0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
632				     0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
633				     0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
634				     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635				     0x00, 0x00, 0x00);
636	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
637				     0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638				     0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
639				     0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 0x42,
640				     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x10,
641				     0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
642				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644				     0x00);
645	mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0b,
646				     0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 0x0b,
647				     0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 0x07,
648				     0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0xa0,
649				     0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);
650}
651
652static const struct drm_display_mode gameforcechi_mode = {
653	.hdisplay	= 640,
654	.hsync_start	= 640 + 40,
655	.hsync_end	= 640 + 40 + 2,
656	.htotal		= 640 + 40 + 2 + 80,
657	.vdisplay	= 480,
658	.vsync_start	= 480 + 17,
659	.vsync_end	= 480 + 17 + 5,
660	.vtotal		= 480 + 17 + 5 + 13,
661	.clock		= 23546,
662	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
663	.width_mm	= 71,
664	.height_mm	= 53,
665};
666
667static const struct st7703_panel_desc gameforcechi_desc = {
668	.mode = &gameforcechi_mode,
669	.lanes = 2,
670	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
671		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
672	.format = MIPI_DSI_FMT_RGB888,
673	.init_sequence = gameforcechi_init_sequence,
674};
675
676static int st7703_enable(struct drm_panel *panel)
677{
678	struct st7703 *ctx = panel_to_st7703(panel);
679	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
680	struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
 
 
 
 
 
 
681
682	ctx->desc->init_sequence(&dsi_ctx);
683
684	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
 
 
 
 
685
686	/* It takes the controller 120 msec to wake up after sleep. */
687	mipi_dsi_msleep(&dsi_ctx, 120);
688
689	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
 
 
690
691	if (!dsi_ctx.accum_err)
692		dev_dbg(ctx->dev, "Panel init sequence done\n");
693
694	return dsi_ctx.accum_err;
695}
696
697static int st7703_disable(struct drm_panel *panel)
698{
699	struct st7703 *ctx = panel_to_st7703(panel);
700	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
701	struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
702
703	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
704
705	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
 
 
706
707	/* It takes the controller 120 msec to enter sleep mode. */
708	mipi_dsi_msleep(&dsi_ctx, 120);
 
709
710	return dsi_ctx.accum_err;
711}
712
713static int st7703_unprepare(struct drm_panel *panel)
714{
715	struct st7703 *ctx = panel_to_st7703(panel);
716
 
 
 
717	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
718	regulator_disable(ctx->iovcc);
719	regulator_disable(ctx->vcc);
 
720
721	return 0;
722}
723
724static int st7703_prepare(struct drm_panel *panel)
725{
726	struct st7703 *ctx = panel_to_st7703(panel);
727	int ret;
728
729	dev_dbg(ctx->dev, "Resetting the panel\n");
730	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
731
732	ret = regulator_enable(ctx->iovcc);
733	if (ret < 0) {
734		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
735		return ret;
736	}
737
 
738	ret = regulator_enable(ctx->vcc);
739	if (ret < 0) {
740		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
741		regulator_disable(ctx->iovcc);
742		return ret;
743	}
 
 
 
 
 
744
745	/* Give power supplies time to stabilize before deasserting reset. */
746	usleep_range(10000, 20000);
747
748	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
749	usleep_range(15000, 20000);
 
 
750
751	return 0;
752}
753
754static const u32 mantix_bus_formats[] = {
755	MEDIA_BUS_FMT_RGB888_1X24,
756};
 
757
758static int st7703_get_modes(struct drm_panel *panel,
759			    struct drm_connector *connector)
760{
761	struct st7703 *ctx = panel_to_st7703(panel);
762	struct drm_display_mode *mode;
763
764	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
765	if (!mode) {
766		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
767			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
768			drm_mode_vrefresh(ctx->desc->mode));
769		return -ENOMEM;
770	}
771
772	drm_mode_set_name(mode);
773
774	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
775	connector->display_info.width_mm = mode->width_mm;
776	connector->display_info.height_mm = mode->height_mm;
777	drm_mode_probed_add(connector, mode);
778
779	drm_display_info_set_bus_formats(&connector->display_info,
780					 mantix_bus_formats,
781					 ARRAY_SIZE(mantix_bus_formats));
782
783	return 1;
784}
785
786static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel)
787{
788	struct st7703 *st7703 = panel_to_st7703(panel);
789
790	return st7703->orientation;
791}
792
793static const struct drm_panel_funcs st7703_drm_funcs = {
794	.disable   = st7703_disable,
795	.unprepare = st7703_unprepare,
796	.prepare   = st7703_prepare,
797	.enable	   = st7703_enable,
798	.get_modes = st7703_get_modes,
799	.get_orientation = st7703_get_orientation,
800};
801
802static int allpixelson_set(void *data, u64 val)
803{
804	struct st7703 *ctx = data;
805	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
806	struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
807
808	dev_dbg(ctx->dev, "Setting all pixels on\n");
809	mipi_dsi_generic_write_seq_multi(&dsi_ctx, ST7703_CMD_ALL_PIXEL_ON);
810	mipi_dsi_msleep(&dsi_ctx, val * 1000);
811
812	/*
813	 * Reset the panel to get video back. NOTE: This isn't a
814	 * particularly safe thing to do in general because it assumes
815	 * that the screen was on to begin with, but this is just a
816	 * debugfs file so it's not a huge deal.
817	 */
818	drm_panel_disable(&ctx->panel);
819	drm_panel_unprepare(&ctx->panel);
820	drm_panel_prepare(&ctx->panel);
821	drm_panel_enable(&ctx->panel);
822
823	return dsi_ctx.accum_err;
824}
825
826DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
827			allpixelson_set, "%llu\n");
828
829static void st7703_debugfs_init(struct st7703 *ctx)
830{
831	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
832
833	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
834			    &allpixelson_fops);
835}
836
837static void st7703_debugfs_remove(struct st7703 *ctx)
838{
839	debugfs_remove_recursive(ctx->debugfs);
840	ctx->debugfs = NULL;
841}
842
843static int st7703_probe(struct mipi_dsi_device *dsi)
844{
845	struct device *dev = &dsi->dev;
846	struct st7703 *ctx;
847	int ret;
848
849	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
850	if (!ctx)
851		return -ENOMEM;
852
853	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
854	if (IS_ERR(ctx->reset_gpio))
855		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
856
857	mipi_dsi_set_drvdata(dsi, ctx);
858
859	ctx->dev = dev;
860	ctx->desc = of_device_get_match_data(dev);
861
862	dsi->mode_flags = ctx->desc->mode_flags;
863	dsi->format = ctx->desc->format;
864	dsi->lanes = ctx->desc->lanes;
865
866	ctx->vcc = devm_regulator_get(dev, "vcc");
867	if (IS_ERR(ctx->vcc))
868		return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
869
870	ctx->iovcc = devm_regulator_get(dev, "iovcc");
871	if (IS_ERR(ctx->iovcc))
872		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
873				     "Failed to request iovcc regulator\n");
874
875	ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
876	if (ret < 0)
877		return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
878
879	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
880		       DRM_MODE_CONNECTOR_DSI);
881
882	ret = drm_panel_of_backlight(&ctx->panel);
883	if (ret)
884		return ret;
885
886	drm_panel_add(&ctx->panel);
887
888	ret = mipi_dsi_attach(dsi);
889	if (ret < 0) {
890		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
891		drm_panel_remove(&ctx->panel);
892		return ret;
893	}
894
895	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
896		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
897		 drm_mode_vrefresh(ctx->desc->mode),
898		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
899
900	st7703_debugfs_init(ctx);
901	return 0;
902}
903
904static void st7703_remove(struct mipi_dsi_device *dsi)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
905{
906	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
907	int ret;
908
 
 
909	ret = mipi_dsi_detach(dsi);
910	if (ret < 0)
911		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
912
913	drm_panel_remove(&ctx->panel);
914
915	st7703_debugfs_remove(ctx);
 
 
916}
917
918static const struct of_device_id st7703_of_match[] = {
919	{ .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
920	{ .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
921	{ .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
922	{ .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
923	{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
924	{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
925	{ /* sentinel */ }
926};
927MODULE_DEVICE_TABLE(of, st7703_of_match);
928
929static struct mipi_dsi_driver st7703_driver = {
930	.probe	= st7703_probe,
931	.remove = st7703_remove,
 
932	.driver = {
933		.name = DRV_NAME,
934		.of_match_table = st7703_of_match,
935	},
936};
937module_mipi_dsi_driver(st7703_driver);
938
939MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
940MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
941MODULE_LICENSE("GPL v2");
v5.14.15
  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_device.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_SETDISP	 0xB2
 32#define ST7703_CMD_SETRGBIF	 0xB3
 33#define ST7703_CMD_SETCYC	 0xB4
 34#define ST7703_CMD_SETBGP	 0xB5
 35#define ST7703_CMD_SETVCOM	 0xB6
 36#define ST7703_CMD_SETOTP	 0xB7
 37#define ST7703_CMD_SETPOWER_EXT	 0xB8
 38#define ST7703_CMD_SETEXTC	 0xB9
 39#define ST7703_CMD_SETMIPI	 0xBA
 40#define ST7703_CMD_SETVDC	 0xBC
 41#define ST7703_CMD_UNKNOWN_BF	 0xBF
 42#define ST7703_CMD_SETSCR	 0xC0
 43#define ST7703_CMD_SETPOWER	 0xC1
 
 
 
 44#define ST7703_CMD_SETPANEL	 0xCC
 45#define ST7703_CMD_UNKNOWN_C6	 0xC6
 46#define ST7703_CMD_SETGAMMA	 0xE0
 47#define ST7703_CMD_SETEQ	 0xE3
 48#define ST7703_CMD_SETGIP1	 0xE9
 49#define ST7703_CMD_SETGIP2	 0xEA
 
 50
 51struct st7703 {
 52	struct device *dev;
 53	struct drm_panel panel;
 54	struct gpio_desc *reset_gpio;
 55	struct regulator *vcc;
 56	struct regulator *iovcc;
 57	bool prepared;
 58
 59	struct dentry *debugfs;
 60	const struct st7703_panel_desc *desc;
 
 61};
 62
 63struct st7703_panel_desc {
 64	const struct drm_display_mode *mode;
 65	unsigned int lanes;
 66	unsigned long mode_flags;
 67	enum mipi_dsi_pixel_format format;
 68	int (*init_sequence)(struct st7703 *ctx);
 69};
 70
 71static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
 72{
 73	return container_of(panel, struct st7703, panel);
 74}
 75
 76#define dsi_generic_write_seq(dsi, seq...) do {				\
 77		static const u8 d[] = { seq };				\
 78		int ret;						\
 79		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
 80		if (ret < 0)						\
 81			return ret;					\
 82	} while (0)
 83
 84static int jh057n_init_sequence(struct st7703 *ctx)
 85{
 86	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 87
 88	/*
 89	 * Init sequence was supplied by the panel vendor. Most of the commands
 90	 * resemble the ST7703 but the number of parameters often don't match
 91	 * so it's likely a clone.
 92	 */
 93	dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
 94			      0xF1, 0x12, 0x83);
 95	dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
 96			      0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
 97			      0x00, 0x00);
 98	dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
 99			      0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
100			      0x00);
101	dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
102	dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
103	dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
104	dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
105	dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
106			      0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
107			      0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
108	dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
109	msleep(20);
110
111	dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
112	dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
113	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
114			      0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
115			      0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
116			      0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
117			      0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
118			      0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
119			      0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
120			      0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
122	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
123			      0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124			      0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
125			      0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
126			      0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
127			      0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
128			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
130			      0xA5, 0x00, 0x00, 0x00, 0x00);
131	dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
132			      0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
133			      0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
134			      0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
135			      0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
136			      0x11, 0x18);
137
138	return 0;
139}
140
141static const struct drm_display_mode jh057n00900_mode = {
142	.hdisplay    = 720,
143	.hsync_start = 720 + 90,
144	.hsync_end   = 720 + 90 + 20,
145	.htotal	     = 720 + 90 + 20 + 20,
146	.vdisplay    = 1440,
147	.vsync_start = 1440 + 20,
148	.vsync_end   = 1440 + 20 + 4,
149	.vtotal	     = 1440 + 20 + 4 + 12,
150	.clock	     = 75276,
151	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
152	.width_mm    = 65,
153	.height_mm   = 130,
154};
155
156static const struct st7703_panel_desc jh057n00900_panel_desc = {
157	.mode = &jh057n00900_mode,
158	.lanes = 4,
159	.mode_flags = MIPI_DSI_MODE_VIDEO |
160		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
161	.format = MIPI_DSI_FMT_RGB888,
162	.init_sequence = jh057n_init_sequence,
163};
164
165#define dsi_dcs_write_seq(dsi, cmd, seq...) do {			\
166		static const u8 d[] = { seq };				\
167		int ret;						\
168		ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));	\
169		if (ret < 0)						\
170			return ret;					\
171	} while (0)
172
173
174static int xbd599_init_sequence(struct st7703 *ctx)
175{
176	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
177
178	/*
179	 * Init sequence was supplied by the panel vendor.
180	 */
181
182	/* Magic sequence to unlock user commands below. */
183	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
184
185	dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
186			  0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
187			  0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
188			  0x05, /* IHSRX = x6 (Low High Speed driving ability) */
189			  0xF9, /* TX_CLK_SEL = fDSICLK/16 */
190			  0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
191			  0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
192			  /* The rest is undocumented in ST7703 datasheet */
193			  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194			  0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
195			  0x4F, 0x11, 0x00, 0x00, 0x37);
196
197	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
198			  0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
199			  0x22, /* DT = 15ms XDK_ECP = x2 */
200			  0x20, /* PFM_DC_DIV = /1 */
201			  0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
202
203	/* RGB I/F porch timing */
204	dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
205			  0x10, /* VBP_RGB_GEN */
206			  0x10, /* VFP_RGB_GEN */
207			  0x05, /* DE_BP_RGB_GEN */
208			  0x05, /* DE_FP_RGB_GEN */
209			  /* The rest is undocumented in ST7703 datasheet */
210			  0x03, 0xFF,
211			  0x00, 0x00,
212			  0x00, 0x00);
213
214	/* Source driving settings. */
215	dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
216			  0x73, /* N_POPON */
217			  0x73, /* N_NOPON */
218			  0x50, /* I_POPON */
219			  0x50, /* I_NOPON */
220			  0x00, /* SCR[31,24] */
221			  0xC0, /* SCR[23,16] */
222			  0x08, /* SCR[15,8] */
223			  0x70, /* SCR[7,0] */
224			  0x00  /* Undocumented */);
225
226	/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
227	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
228
229	/*
230	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
231	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
232	 */
233	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
234
235	/* Zig-Zag Type C column inversion. */
236	dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
237
238	/* Set display resolution. */
239	dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
240			  0xF0, /* NL = 240 */
241			  0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
242				 * RESO_SEL = 720RGB
243				 */
244			  0xF0  /* WHITE_GND_EN = 1 (GND),
245				 * WHITE_FRAME_SEL = 7 frames,
246				 * ISC = 0 frames
247				 */);
248
249	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
250			  0x00, /* PNOEQ */
251			  0x00, /* NNOEQ */
252			  0x0B, /* PEQGND */
253			  0x0B, /* NEQGND */
254			  0x10, /* PEQVCI */
255			  0x10, /* NEQVCI */
256			  0x00, /* PEQVCI1 */
257			  0x00, /* NEQVCI1 */
258			  0x00, /* reserved */
259			  0x00, /* reserved */
260			  0xFF, /* reserved */
261			  0x00, /* reserved */
262			  0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
263			  0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
264				 * VEDIO_NO_CHECK_EN = 0
265				 * ESD_WHITE_GND_EN = 0
266				 * ESD_DET_TIME_SEL = 0 frames
267				 */);
268
269	/* Undocumented command. */
270	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
271
272	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
273			  0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
274			  0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
275			  0x32, /* VRP  */
276			  0x32, /* VRN */
277			  0x77, /* reserved */
278			  0xF1, /* APS = 1 (small),
279				 * VGL_DET_EN = 1, VGH_DET_EN = 1,
280				 * VGL_TURBO = 1, VGH_TURBO = 1
281				 */
282			  0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
283			  0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
284			  0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
285			  0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
286			  0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
287			  0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
288
289	/* Reference voltage. */
290	dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
291			  0x07, /* VREF_SEL = 4.2V */
292			  0x07  /* NVREF_SEL = 4.2V */);
293	msleep(20);
294
295	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
296			  0x2C, /* VCOMDC_F = -0.67V */
297			  0x2C  /* VCOMDC_B = -0.67V */);
298
299	/* Undocumented command. */
300	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
301
302	/* This command is to set forward GIP timing. */
303	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
304			  0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
305			  0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
306			  0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
307			  0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
308			  0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
309			  0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
310			  0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
312
313	/* This command is to set backward GIP timing. */
314	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
315			  0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316			  0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
317			  0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
318			  0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
319			  0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
320			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
322			  0xA5, 0x00, 0x00, 0x00, 0x00);
323
324	/* Adjust the gamma characteristics of the panel. */
325	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
326			  0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
327			  0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
328			  0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
329			  0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
330			  0x12, 0x18);
331
332	return 0;
333}
334
335static const struct drm_display_mode xbd599_mode = {
336	.hdisplay    = 720,
337	.hsync_start = 720 + 40,
338	.hsync_end   = 720 + 40 + 40,
339	.htotal	     = 720 + 40 + 40 + 40,
340	.vdisplay    = 1440,
341	.vsync_start = 1440 + 18,
342	.vsync_end   = 1440 + 18 + 10,
343	.vtotal	     = 1440 + 18 + 10 + 17,
344	.clock	     = 69000,
345	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
346	.width_mm    = 68,
347	.height_mm   = 136,
348};
349
350static const struct st7703_panel_desc xbd599_desc = {
351	.mode = &xbd599_mode,
352	.lanes = 4,
353	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
354	.format = MIPI_DSI_FMT_RGB888,
355	.init_sequence = xbd599_init_sequence,
356};
357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358static int st7703_enable(struct drm_panel *panel)
359{
360	struct st7703 *ctx = panel_to_st7703(panel);
361	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
362	int ret;
363
364	ret = ctx->desc->init_sequence(ctx);
365	if (ret < 0) {
366		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
367		return ret;
368	}
369
370	msleep(20);
371
372	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
373	if (ret < 0) {
374		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
375		return ret;
376	}
377
378	/* Panel is operational 120 msec after reset */
379	msleep(60);
380
381	ret = mipi_dsi_dcs_set_display_on(dsi);
382	if (ret)
383		return ret;
384
385	dev_dbg(ctx->dev, "Panel init sequence done\n");
 
386
387	return 0;
388}
389
390static int st7703_disable(struct drm_panel *panel)
391{
392	struct st7703 *ctx = panel_to_st7703(panel);
393	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
394	int ret;
 
 
395
396	ret = mipi_dsi_dcs_set_display_off(dsi);
397	if (ret < 0)
398		dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
399
400	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
401	if (ret < 0)
402		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
403
404	return 0;
405}
406
407static int st7703_unprepare(struct drm_panel *panel)
408{
409	struct st7703 *ctx = panel_to_st7703(panel);
410
411	if (!ctx->prepared)
412		return 0;
413
414	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
415	regulator_disable(ctx->iovcc);
416	regulator_disable(ctx->vcc);
417	ctx->prepared = false;
418
419	return 0;
420}
421
422static int st7703_prepare(struct drm_panel *panel)
423{
424	struct st7703 *ctx = panel_to_st7703(panel);
425	int ret;
426
427	if (ctx->prepared)
428		return 0;
 
 
 
 
 
 
429
430	dev_dbg(ctx->dev, "Resetting the panel\n");
431	ret = regulator_enable(ctx->vcc);
432	if (ret < 0) {
433		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
 
434		return ret;
435	}
436	ret = regulator_enable(ctx->iovcc);
437	if (ret < 0) {
438		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
439		goto disable_vcc;
440	}
441
442	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
443	usleep_range(20, 40);
 
444	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
445	msleep(20);
446
447	ctx->prepared = true;
448
449	return 0;
 
450
451disable_vcc:
452	regulator_disable(ctx->vcc);
453	return ret;
454}
455
456static int st7703_get_modes(struct drm_panel *panel,
457			    struct drm_connector *connector)
458{
459	struct st7703 *ctx = panel_to_st7703(panel);
460	struct drm_display_mode *mode;
461
462	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
463	if (!mode) {
464		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
465			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
466			drm_mode_vrefresh(ctx->desc->mode));
467		return -ENOMEM;
468	}
469
470	drm_mode_set_name(mode);
471
472	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
473	connector->display_info.width_mm = mode->width_mm;
474	connector->display_info.height_mm = mode->height_mm;
475	drm_mode_probed_add(connector, mode);
476
 
 
 
 
477	return 1;
478}
479
 
 
 
 
 
 
 
480static const struct drm_panel_funcs st7703_drm_funcs = {
481	.disable   = st7703_disable,
482	.unprepare = st7703_unprepare,
483	.prepare   = st7703_prepare,
484	.enable	   = st7703_enable,
485	.get_modes = st7703_get_modes,
 
486};
487
488static int allpixelson_set(void *data, u64 val)
489{
490	struct st7703 *ctx = data;
491	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 
492
493	dev_dbg(ctx->dev, "Setting all pixels on\n");
494	dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
495	msleep(val * 1000);
496	/* Reset the panel to get video back */
 
 
 
 
 
 
497	drm_panel_disable(&ctx->panel);
498	drm_panel_unprepare(&ctx->panel);
499	drm_panel_prepare(&ctx->panel);
500	drm_panel_enable(&ctx->panel);
501
502	return 0;
503}
504
505DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
506			allpixelson_set, "%llu\n");
507
508static void st7703_debugfs_init(struct st7703 *ctx)
509{
510	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
511
512	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
513			    &allpixelson_fops);
514}
515
516static void st7703_debugfs_remove(struct st7703 *ctx)
517{
518	debugfs_remove_recursive(ctx->debugfs);
519	ctx->debugfs = NULL;
520}
521
522static int st7703_probe(struct mipi_dsi_device *dsi)
523{
524	struct device *dev = &dsi->dev;
525	struct st7703 *ctx;
526	int ret;
527
528	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
529	if (!ctx)
530		return -ENOMEM;
531
532	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
533	if (IS_ERR(ctx->reset_gpio))
534		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
535
536	mipi_dsi_set_drvdata(dsi, ctx);
537
538	ctx->dev = dev;
539	ctx->desc = of_device_get_match_data(dev);
540
541	dsi->mode_flags = ctx->desc->mode_flags;
542	dsi->format = ctx->desc->format;
543	dsi->lanes = ctx->desc->lanes;
544
545	ctx->vcc = devm_regulator_get(dev, "vcc");
546	if (IS_ERR(ctx->vcc))
547		return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
548
549	ctx->iovcc = devm_regulator_get(dev, "iovcc");
550	if (IS_ERR(ctx->iovcc))
551		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
552				     "Failed to request iovcc regulator\n");
553
 
 
 
 
554	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
555		       DRM_MODE_CONNECTOR_DSI);
556
557	ret = drm_panel_of_backlight(&ctx->panel);
558	if (ret)
559		return ret;
560
561	drm_panel_add(&ctx->panel);
562
563	ret = mipi_dsi_attach(dsi);
564	if (ret < 0) {
565		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
566		drm_panel_remove(&ctx->panel);
567		return ret;
568	}
569
570	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
571		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
572		 drm_mode_vrefresh(ctx->desc->mode),
573		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
574
575	st7703_debugfs_init(ctx);
576	return 0;
577}
578
579static void st7703_shutdown(struct mipi_dsi_device *dsi)
580{
581	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
582	int ret;
583
584	ret = drm_panel_unprepare(&ctx->panel);
585	if (ret < 0)
586		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
587
588	ret = drm_panel_disable(&ctx->panel);
589	if (ret < 0)
590		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
591}
592
593static int st7703_remove(struct mipi_dsi_device *dsi)
594{
595	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
596	int ret;
597
598	st7703_shutdown(dsi);
599
600	ret = mipi_dsi_detach(dsi);
601	if (ret < 0)
602		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
603
604	drm_panel_remove(&ctx->panel);
605
606	st7703_debugfs_remove(ctx);
607
608	return 0;
609}
610
611static const struct of_device_id st7703_of_match[] = {
 
 
 
 
612	{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
613	{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
614	{ /* sentinel */ }
615};
616MODULE_DEVICE_TABLE(of, st7703_of_match);
617
618static struct mipi_dsi_driver st7703_driver = {
619	.probe	= st7703_probe,
620	.remove = st7703_remove,
621	.shutdown = st7703_shutdown,
622	.driver = {
623		.name = DRV_NAME,
624		.of_match_table = st7703_of_match,
625	},
626};
627module_mipi_dsi_driver(st7703_driver);
628
629MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
630MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
631MODULE_LICENSE("GPL v2");