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