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 bool prepared; 62 63 struct dentry *debugfs; 64 const struct st7703_panel_desc *desc; 65 enum drm_panel_orientation orientation; 66 }; 67 68 struct 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 76 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel) 77 { 78 return container_of(panel, struct st7703, panel); 79 } 80 81 static 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 139 static 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 154 static 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 163 static 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 322 static 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 337 static 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 345 static 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 413 static 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 428 static 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 437 static 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 501 static 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 516 static 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 525 static 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 591 static 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 606 static 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 615 static int gameforcechi_init_sequence(struct st7703 *ctx) 616 { 617 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 618 619 /* 620 * Init sequence was supplied by the panel vendor. Panel will not 621 * respond to commands until it is brought out of sleep mode first. 622 */ 623 624 mipi_dsi_dcs_exit_sleep_mode(dsi); 625 msleep(250); 626 627 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83); 628 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x31, 0x81, 0x05, 0xf9, 629 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 630 0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 631 0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37); 632 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25); 633 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); 634 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a, 635 0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00); 636 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50, 637 0x00, 0x00, 0x08, 0x70, 0x00); 638 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46); 639 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b); 640 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); 641 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0); 642 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b, 643 0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 644 0xc0, 0x10); 645 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e, 646 0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33, 647 0x33); 648 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x10, 0x10); 649 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x6c, 0x7c); 650 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0x08, 0x00, 0x0e, 0x00, 651 0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x10, 652 0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00, 653 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 654 0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88, 655 0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35, 656 0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 657 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 658 0x00, 0x00, 0x00); 659 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02, 660 0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 661 0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88, 662 0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 0x42, 663 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x10, 664 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 667 0x00); 668 mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0b, 669 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 0x0b, 670 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 0x07, 671 0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0xa0, 672 0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18); 673 674 return 0; 675 } 676 677 static const struct drm_display_mode gameforcechi_mode = { 678 .hdisplay = 640, 679 .hsync_start = 640 + 40, 680 .hsync_end = 640 + 40 + 2, 681 .htotal = 640 + 40 + 2 + 80, 682 .vdisplay = 480, 683 .vsync_start = 480 + 17, 684 .vsync_end = 480 + 17 + 5, 685 .vtotal = 480 + 17 + 5 + 13, 686 .clock = 23546, 687 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 688 .width_mm = 71, 689 .height_mm = 53, 690 }; 691 692 static const struct st7703_panel_desc gameforcechi_desc = { 693 .mode = &gameforcechi_mode, 694 .lanes = 2, 695 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 696 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM, 697 .format = MIPI_DSI_FMT_RGB888, 698 .init_sequence = gameforcechi_init_sequence, 699 }; 700 701 static int st7703_enable(struct drm_panel *panel) 702 { 703 struct st7703 *ctx = panel_to_st7703(panel); 704 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 705 int ret; 706 707 ret = ctx->desc->init_sequence(ctx); 708 if (ret < 0) { 709 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); 710 return ret; 711 } 712 713 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 714 if (ret < 0) { 715 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); 716 return ret; 717 } 718 719 /* It takes the controller 120 msec to wake up after sleep. */ 720 msleep(120); 721 722 ret = mipi_dsi_dcs_set_display_on(dsi); 723 if (ret) 724 return ret; 725 726 dev_dbg(ctx->dev, "Panel init sequence done\n"); 727 728 return 0; 729 } 730 731 static int st7703_disable(struct drm_panel *panel) 732 { 733 struct st7703 *ctx = panel_to_st7703(panel); 734 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 735 int ret; 736 737 ret = mipi_dsi_dcs_set_display_off(dsi); 738 if (ret < 0) 739 dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret); 740 741 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 742 if (ret < 0) 743 dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); 744 745 /* It takes the controller 120 msec to enter sleep mode. */ 746 msleep(120); 747 748 return 0; 749 } 750 751 static int st7703_unprepare(struct drm_panel *panel) 752 { 753 struct st7703 *ctx = panel_to_st7703(panel); 754 755 if (!ctx->prepared) 756 return 0; 757 758 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 759 regulator_disable(ctx->iovcc); 760 regulator_disable(ctx->vcc); 761 ctx->prepared = false; 762 763 return 0; 764 } 765 766 static int st7703_prepare(struct drm_panel *panel) 767 { 768 struct st7703 *ctx = panel_to_st7703(panel); 769 int ret; 770 771 if (ctx->prepared) 772 return 0; 773 774 dev_dbg(ctx->dev, "Resetting the panel\n"); 775 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 776 777 ret = regulator_enable(ctx->iovcc); 778 if (ret < 0) { 779 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 780 return ret; 781 } 782 783 ret = regulator_enable(ctx->vcc); 784 if (ret < 0) { 785 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); 786 regulator_disable(ctx->iovcc); 787 return ret; 788 } 789 790 /* Give power supplies time to stabilize before deasserting reset. */ 791 usleep_range(10000, 20000); 792 793 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 794 usleep_range(15000, 20000); 795 796 ctx->prepared = true; 797 798 return 0; 799 } 800 801 static const u32 mantix_bus_formats[] = { 802 MEDIA_BUS_FMT_RGB888_1X24, 803 }; 804 805 static int st7703_get_modes(struct drm_panel *panel, 806 struct drm_connector *connector) 807 { 808 struct st7703 *ctx = panel_to_st7703(panel); 809 struct drm_display_mode *mode; 810 811 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); 812 if (!mode) { 813 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", 814 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 815 drm_mode_vrefresh(ctx->desc->mode)); 816 return -ENOMEM; 817 } 818 819 drm_mode_set_name(mode); 820 821 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 822 connector->display_info.width_mm = mode->width_mm; 823 connector->display_info.height_mm = mode->height_mm; 824 drm_mode_probed_add(connector, mode); 825 826 drm_display_info_set_bus_formats(&connector->display_info, 827 mantix_bus_formats, 828 ARRAY_SIZE(mantix_bus_formats)); 829 830 return 1; 831 } 832 833 static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel) 834 { 835 struct st7703 *st7703 = panel_to_st7703(panel); 836 837 return st7703->orientation; 838 } 839 840 static const struct drm_panel_funcs st7703_drm_funcs = { 841 .disable = st7703_disable, 842 .unprepare = st7703_unprepare, 843 .prepare = st7703_prepare, 844 .enable = st7703_enable, 845 .get_modes = st7703_get_modes, 846 .get_orientation = st7703_get_orientation, 847 }; 848 849 static int allpixelson_set(void *data, u64 val) 850 { 851 struct st7703 *ctx = data; 852 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 853 854 dev_dbg(ctx->dev, "Setting all pixels on\n"); 855 mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); 856 msleep(val * 1000); 857 /* Reset the panel to get video back */ 858 drm_panel_disable(&ctx->panel); 859 drm_panel_unprepare(&ctx->panel); 860 drm_panel_prepare(&ctx->panel); 861 drm_panel_enable(&ctx->panel); 862 863 return 0; 864 } 865 866 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL, 867 allpixelson_set, "%llu\n"); 868 869 static void st7703_debugfs_init(struct st7703 *ctx) 870 { 871 ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL); 872 873 debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx, 874 &allpixelson_fops); 875 } 876 877 static void st7703_debugfs_remove(struct st7703 *ctx) 878 { 879 debugfs_remove_recursive(ctx->debugfs); 880 ctx->debugfs = NULL; 881 } 882 883 static int st7703_probe(struct mipi_dsi_device *dsi) 884 { 885 struct device *dev = &dsi->dev; 886 struct st7703 *ctx; 887 int ret; 888 889 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 890 if (!ctx) 891 return -ENOMEM; 892 893 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 894 if (IS_ERR(ctx->reset_gpio)) 895 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n"); 896 897 mipi_dsi_set_drvdata(dsi, ctx); 898 899 ctx->dev = dev; 900 ctx->desc = of_device_get_match_data(dev); 901 902 dsi->mode_flags = ctx->desc->mode_flags; 903 dsi->format = ctx->desc->format; 904 dsi->lanes = ctx->desc->lanes; 905 906 ctx->vcc = devm_regulator_get(dev, "vcc"); 907 if (IS_ERR(ctx->vcc)) 908 return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n"); 909 910 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 911 if (IS_ERR(ctx->iovcc)) 912 return dev_err_probe(dev, PTR_ERR(ctx->iovcc), 913 "Failed to request iovcc regulator\n"); 914 915 ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation); 916 if (ret < 0) 917 return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n"); 918 919 drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs, 920 DRM_MODE_CONNECTOR_DSI); 921 922 ret = drm_panel_of_backlight(&ctx->panel); 923 if (ret) 924 return ret; 925 926 drm_panel_add(&ctx->panel); 927 928 ret = mipi_dsi_attach(dsi); 929 if (ret < 0) { 930 dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret); 931 drm_panel_remove(&ctx->panel); 932 return ret; 933 } 934 935 dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", 936 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 937 drm_mode_vrefresh(ctx->desc->mode), 938 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); 939 940 st7703_debugfs_init(ctx); 941 return 0; 942 } 943 944 static void st7703_shutdown(struct mipi_dsi_device *dsi) 945 { 946 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); 947 int ret; 948 949 ret = drm_panel_unprepare(&ctx->panel); 950 if (ret < 0) 951 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); 952 953 ret = drm_panel_disable(&ctx->panel); 954 if (ret < 0) 955 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); 956 } 957 958 static void st7703_remove(struct mipi_dsi_device *dsi) 959 { 960 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); 961 int ret; 962 963 st7703_shutdown(dsi); 964 965 ret = mipi_dsi_detach(dsi); 966 if (ret < 0) 967 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 968 969 drm_panel_remove(&ctx->panel); 970 971 st7703_debugfs_remove(ctx); 972 } 973 974 static const struct of_device_id st7703_of_match[] = { 975 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc }, 976 { .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc }, 977 { .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc }, 978 { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc }, 979 { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc }, 980 { .compatible = "xingbangda,xbd599", .data = &xbd599_desc }, 981 { /* sentinel */ } 982 }; 983 MODULE_DEVICE_TABLE(of, st7703_of_match); 984 985 static struct mipi_dsi_driver st7703_driver = { 986 .probe = st7703_probe, 987 .remove = st7703_remove, 988 .shutdown = st7703_shutdown, 989 .driver = { 990 .name = DRV_NAME, 991 .of_match_table = st7703_of_match, 992 }, 993 }; 994 module_mipi_dsi_driver(st7703_driver); 995 996 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>"); 997 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels"); 998 MODULE_LICENSE("GPL v2"); 999