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