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