This panel has been tested with the RK3566 VOP2 MIPI-DSI on the
Powkiddy RGB30. Support for MIPI-DSI on Rockchip is not upstream yet,
but the panel can be used with other MIPI-DSI controllers as well.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 drivers/video/Kconfig                 |  13 +
 drivers/video/Makefile                |   1 +
 drivers/video/panel-sitronix-st7703.c | 903 ++++++++++++++++++++++++++
 3 files changed, 917 insertions(+)
 create mode 100644 drivers/video/panel-sitronix-st7703.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index b2eccd5db7fe..4605634bb581 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -202,6 +202,19 @@ config DRIVER_VIDEO_PANEL_SITRONIX_ST7789V
          Say Y here if you want to enable support for the Sitronix
          ST7789V controller for 240x320 LCD panels
 
+config DRIVER_VIDEO_PANEL_SITRONIX_ST7703
+       tristate "Sitronix ST7703 based MIPI touchscreen panels"
+       depends on OF
+       depends on DRIVER_VIDEO_MIPI_DSI
+       depends on DRIVER_VIDEO_BACKLIGHT
+       help
+         Say Y here if you want to enable support for Sitronix ST7703 based
+         panels, souch as Rocktech JH057N00900 MIPI DSI panel as e.g. used in
+         the Librem 5 devkit. It has a resolution of 720x1440 pixels, a built
+         in backlight and touch controller.
+         Touch input support is provided by the goodix driver and needs to be
+         selected separately.
+
 config DRIVER_VIDEO_PANEL_ORISETECH_OTM8009A
        tristate "Orise Technology otm8009a 480x800 dsi 2dl panel"
        depends on OF
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 470a5abaa450..8dfebe2be6a2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DRIVER_VIDEO_MIPI_DSI) += mipi_dsi.o
 obj-$(CONFIG_DRIVER_VIDEO_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
 obj-$(CONFIG_DRIVER_VIDEO_PANEL_MIPI_DBI) += panel-mipi-dbi.o
 obj-$(CONFIG_DRIVER_VIDEO_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
+obj-$(CONFIG_DRIVER_VIDEO_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o
 obj-$(CONFIG_DRIVER_VIDEO_PANEL_ORISETECH_OTM8009A) += 
panel-orisetech-otm8009a.o
 
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
diff --git a/drivers/video/panel-sitronix-st7703.c 
b/drivers/video/panel-sitronix-st7703.c
new file mode 100644
index 000000000000..a1c87c74bb6d
--- /dev/null
+++ b/drivers/video/panel-sitronix-st7703.c
@@ -0,0 +1,903 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for panels based on Sitronix ST7703 controller, souch as:
+ *
+ * - Rocktech jh057n00900 5.5" MIPI-DSI panel
+ *
+ * Copyright (C) Purism SPC 2019
+ */
+
+#include <clock.h>
+#include <linux/gpio/consumer.h>
+#include <video/media-bus-format.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <of.h>
+#include <of_device.h>
+#include <regulator.h>
+
+#include <video/vpl.h>
+#include <video/mipi_display.h>
+#include <video/mipi_dsi.h>
+#include <video/drm/drm_modes.h>
+#include <video/drm/drm_connector.h>
+#include <video/videomode.h>
+#include <video/backlight.h>
+
+#define DRV_NAME "panel-sitronix-st7703"
+
+/* Manufacturer specific Commands send via DSI */
+#define ST7703_CMD_ALL_PIXEL_OFF 0x22
+#define ST7703_CMD_ALL_PIXEL_ON         0x23
+#define ST7703_CMD_SETAPID      0xB1
+#define ST7703_CMD_SETDISP      0xB2
+#define ST7703_CMD_SETRGBIF     0xB3
+#define ST7703_CMD_SETCYC       0xB4
+#define ST7703_CMD_SETBGP       0xB5
+#define ST7703_CMD_SETVCOM      0xB6
+#define ST7703_CMD_SETOTP       0xB7
+#define ST7703_CMD_SETPOWER_EXT         0xB8
+#define ST7703_CMD_SETEXTC      0xB9
+#define ST7703_CMD_SETMIPI      0xBA
+#define ST7703_CMD_SETVDC       0xBC
+#define ST7703_CMD_UNKNOWN_BF   0xBF
+#define ST7703_CMD_SETSCR       0xC0
+#define ST7703_CMD_SETPOWER     0xC1
+#define ST7703_CMD_SETECO       0xC6
+#define ST7703_CMD_SETIO        0xC7
+#define ST7703_CMD_SETCABC      0xC8
+#define ST7703_CMD_SETPANEL     0xCC
+#define ST7703_CMD_SETGAMMA     0xE0
+#define ST7703_CMD_SETEQ        0xE3
+#define ST7703_CMD_SETGIP1      0xE9
+#define ST7703_CMD_SETGIP2      0xEA
+#define ST7703_CMD_UNKNOWN_EF   0xEF
+
+struct st7703 {
+       struct device *dev;
+       struct vpl vpl;
+       struct gpio_desc *reset_gpio;
+       struct regulator *vcc;
+       struct regulator *iovcc;
+       struct backlight_device *backlight;
+
+       const struct st7703_panel_desc *desc;
+       int allpixelson;
+};
+
+struct st7703_panel_desc {
+       const struct drm_display_mode *mode;
+       unsigned int lanes;
+       unsigned long mode_flags;
+       enum mipi_dsi_pixel_format format;
+       void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
+};
+
+static void jh057n_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       /*
+        * Init sequence was supplied by the panel vendor. Most of the commands
+        * resemble the ST7703 but the number of parameters often don't match
+        * so it's likely a clone.
+        */
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC,
+                                        0xF1, 0x12, 0x83);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
+                                        0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 
0x00, 0x00,
+                                        0x00, 0x00);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
+                                        0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 
0x08, 0x70,
+                                        0x00);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xF0, 
0x12, 0x30);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
+                                        0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 
0x00, 0x00,
+                                        0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x08, 
0x08);
+       mipi_dsi_mdelay(dsi_ctx, 20);
+
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x3F, 
0x3F);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 
0x11, 0x00);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
+                                        0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 
0xA5, 0x12,
+                                        0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 
0x27, 0x38,
+                                        0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 
0x0C, 0x00,
+                                        0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 
0x31, 0x88,
+                                        0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 
0x88, 0x64,
+                                        0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 
0x88, 0x88,
+                                        0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
+                                        0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 
0x02, 0x88,
+                                        0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 
0x88, 0x13,
+                                        0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 
0x88, 0x88,
+                                        0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 
0x02, 0x00,
+                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x30, 0x0A,
+                                        0xA5, 0x00, 0x00, 0x00, 0x00);
+       mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
+                                        0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 
0x41, 0x37,
+                                        0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 
0x10, 0x11,
+                                        0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 
0x3C, 0x41,
+                                        0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 
0x0F, 0x10,
+                                        0x11, 0x18);
+       mipi_dsi_mdelay(dsi_ctx, 20);
+}
+
+static const struct drm_display_mode jh057n00900_mode = {
+       .hdisplay    = 720,
+       .hsync_start = 720 + 90,
+       .hsync_end   = 720 + 90 + 20,
+       .htotal      = 720 + 90 + 20 + 20,
+       .vdisplay    = 1440,
+       .vsync_start = 1440 + 20,
+       .vsync_end   = 1440 + 20 + 4,
+       .vtotal      = 1440 + 20 + 4 + 12,
+       .clock       = 75276,
+       .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       .width_mm    = 65,
+       .height_mm   = 130,
+};
+
+static const struct st7703_panel_desc jh057n00900_panel_desc = {
+       .mode = &jh057n00900_mode,
+       .lanes = 4,
+       .mode_flags = MIPI_DSI_MODE_VIDEO |
+               MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
+       .format = MIPI_DSI_FMT_RGB888,
+       .init_sequence = jh057n_init_sequence,
+};
+
+static void xbd599_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       /*
+        * Init sequence was supplied by the panel vendor.
+        */
+
+       /* Magic sequence to unlock user commands below. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xF1, 0x12, 
0x83);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI,
+                                    0x33, /* VC_main = 0, Lane_Number = 3 (4 
lanes) */
+                                    0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 
Ohm */
+                                    0x05, /* IHSRX = x6 (Low High Speed 
driving ability) */
+                                    0xF9, /* TX_CLK_SEL = fDSICLK/16 */
+                                    0x0E, /* HFP_OSC (min. HFP number in DSI 
mode) */
+                                    0x0E, /* HBP_OSC (min. HBP number in DSI 
mode) */
+                                    /* The rest is undocumented in ST7703 
datasheet */
+                                    0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 
0x02,
+                                    0x4F, 0x11, 0x00, 0x00, 0x37);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT,
+                                    0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC 
*/
+                                    0x22, /* DT = 15ms XDK_ECP = x2 */
+                                    0x20, /* PFM_DC_DIV = /1 */
+                                    0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 
*/);
+
+       /* RGB I/F porch timing */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
+                                    0x10, /* VBP_RGB_GEN */
+                                    0x10, /* VFP_RGB_GEN */
+                                    0x05, /* DE_BP_RGB_GEN */
+                                    0x05, /* DE_FP_RGB_GEN */
+                                    /* The rest is undocumented in ST7703 
datasheet */
+                                    0x03, 0xFF,
+                                    0x00, 0x00,
+                                    0x00, 0x00);
+
+       /* Source driving settings. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
+                                    0x73, /* N_POPON */
+                                    0x73, /* N_NOPON */
+                                    0x50, /* I_POPON */
+                                    0x50, /* I_NOPON */
+                                    0x00, /* SCR[31,24] */
+                                    0xC0, /* SCR[23,16] */
+                                    0x08, /* SCR[15,8] */
+                                    0x70, /* SCR[7,0] */
+                                    0x00  /* Undocumented */);
+
+       /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
+
+       /*
+        * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
+        * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
+        */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
+
+       /* Zig-Zag Type C column inversion. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
+
+       /* Set display resolution. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP,
+                                    0xF0, /* NL = 240 */
+                                    0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
+                                           * RESO_SEL = 720RGB
+                                           */
+                                    0xF0  /* WHITE_GND_EN = 1 (GND),
+                                           * WHITE_FRAME_SEL = 7 frames,
+                                           * ISC = 0 frames
+                                           */);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
+                                    0x00, /* PNOEQ */
+                                    0x00, /* NNOEQ */
+                                    0x0B, /* PEQGND */
+                                    0x0B, /* NEQGND */
+                                    0x10, /* PEQVCI */
+                                    0x10, /* NEQVCI */
+                                    0x00, /* PEQVCI1 */
+                                    0x00, /* NEQVCI1 */
+                                    0x00, /* reserved */
+                                    0x00, /* reserved */
+                                    0xFF, /* reserved */
+                                    0x00, /* reserved */
+                                    0xC0, /* ESD_DET_DATA_WHITE = 1, 
ESD_WHITE_EN = 1 */
+                                    0x10  /* SLPIN_OPTION = 1 (no need vsync 
after sleep-in)
+                                           * VEDIO_NO_CHECK_EN = 0
+                                           * ESD_WHITE_GND_EN = 0
+                                           * ESD_DET_TIME_SEL = 0 frames
+                                           */);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x01, 0x00, 
0xFF, 0xFF, 0x00);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER,
+                                    0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = 
-11V */
+                                    0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
+                                    0x32, /* VRP  */
+                                    0x32, /* VRN */
+                                    0x77, /* reserved */
+                                    0xF1, /* APS = 1 (small),
+                                           * VGL_DET_EN = 1, VGH_DET_EN = 1,
+                                           * VGL_TURBO = 1, VGH_TURBO = 1
+                                           */
+                                    0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
+                                    0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
+                                    0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
+                                    0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
+                                    0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
+                                    0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) 
*/);
+
+       /* Reference voltage. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP,
+                                    0x07, /* VREF_SEL = 4.2V */
+                                    0x07  /* NVREF_SEL = 4.2V */);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM,
+                                    0x2C, /* VCOMDC_F = -0.67V */
+                                    0x2C  /* VCOMDC_B = -0.67V */);
+
+       /* Undocumented command. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 
0x11, 0x00);
+
+       /* This command is to set forward GIP timing. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
+                                    0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 
0x12,
+                                    0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 
0x38,
+                                    0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 
0x00,
+                                    0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 
0x88,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 
0x64,
+                                    0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 
0x88,
+                                    0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+       /* This command is to set backward GIP timing. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
+                                    0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 
0x88,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 
0x13,
+                                    0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 
0x88,
+                                    0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
0x0A,
+                                    0xA5, 0x00, 0x00, 0x00, 0x00);
+
+       /* Adjust the gamma characteristics of the panel. */
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
+                                    0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 
0x35,
+                                    0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 
0x12,
+                                    0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 
0x41,
+                                    0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 
0x12,
+                                    0x12, 0x18);
+}
+
+static const struct drm_display_mode xbd599_mode = {
+       .hdisplay    = 720,
+       .hsync_start = 720 + 40,
+       .hsync_end   = 720 + 40 + 40,
+       .htotal      = 720 + 40 + 40 + 40,
+       .vdisplay    = 1440,
+       .vsync_start = 1440 + 18,
+       .vsync_end   = 1440 + 18 + 10,
+       .vtotal      = 1440 + 18 + 10 + 17,
+       .clock       = 69000,
+       .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       .width_mm    = 68,
+       .height_mm   = 136,
+};
+
+static const struct st7703_panel_desc xbd599_desc = {
+       .mode = &xbd599_mode,
+       .lanes = 4,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
+       .format = MIPI_DSI_FMT_RGB888,
+       .init_sequence = xbd599_init_sequence,
+};
+
+static void rg353v2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       /*
+        * Init sequence was supplied by the panel vendor.
+        */
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 
0x83);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 
0x00,
+                                    0xda, 0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 
0x70);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 
0x28,
+                                    0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x92, 0x92);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 
0x22,
+                                    0xf0, 0x63);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 
0x05,
+                                    0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 
0x0a,
+                                    0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 
0x37);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 
0x11, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 
0x50, 0x50,
+                                    0x00, 0x00, 0x12, 0x50, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0xc0, 
0x32,
+                                    0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 
0x33,
+                                    0x33);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 
0xbf, 0xff,
+                                    0x00, 0xff);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 
0x0a, 0x00,
+                                    0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 
0x1e,
+                                    0x02);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 
0x0d,
+                                    0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 
0x0d,
+                                    0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 
0x07,
+                                    0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 
0x0c,
+                                    0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 
0x0b, 0x0b,
+                                    0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 
0x00,
+                                    0xc0, 0x10);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 
0x02, 0x00,
+                                    0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 
0x80,
+                                    0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 
0x00,
+                                    0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 
0x00,
+                                    0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 
0x88,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 
0x35,
+                                    0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 
0x00,
+                                    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 
0x82, 0x02,
+                                    0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 
0x88,
+                                    0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 
0x42,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 
0x00,
+                                    0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 
0xff, 0x01);
+}
+
+static const struct drm_display_mode rg353v2_mode = {
+       .hdisplay       = 640,
+       .hsync_start    = 640 + 40,
+       .hsync_end      = 640 + 40 + 2,
+       .htotal         = 640 + 40 + 2 + 80,
+       .vdisplay       = 480,
+       .vsync_start    = 480 + 18,
+       .vsync_end      = 480 + 18 + 2,
+       .vtotal         = 480 + 18 + 2 + 28,
+       .clock          = 24150,
+       .flags          = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       .width_mm       = 70,
+       .height_mm      = 57,
+};
+
+static const struct st7703_panel_desc rg353v2_desc = {
+       .mode = &rg353v2_mode,
+       .lanes = 4,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                     MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
+       .format = MIPI_DSI_FMT_RGB888,
+       .init_sequence = rg353v2_init_sequence,
+};
+
+static void rgb30panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       /* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
+
+       /*
+        * For some reason this specific panel must be taken out of sleep
+        * before the full init sequence, or else it will not display.
+        */
+       mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
+       mipi_dsi_mdelay(dsi_ctx, 250);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 
0x83);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 
0x05, 0xf9,
+                                    0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 
0x00,
+                                    0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 
0x22, 0xf0,
+                                    0x63);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 
0x11, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 
0x28,
+                                    0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 
0x50, 0x50,
+                                    0x00, 0x00, 0x12, 0x70, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x3c, 0x12, 
0x30);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 
0x0b, 0x0b,
+                                    0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 
0x00,
+                                    0xc0, 0x10);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x36, 0x00, 
0x32,
+                                    0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 
0x33,
+                                    0x33);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x88, 0x88);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 
0x0a, 0x10,
+                                    0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 
0x86,
+                                    0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 
0x00,
+                                    0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 
0x88,
+                                    0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 
0x57,
+                                    0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x96, 0x12, 
0x01, 0x01,
+                                    0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 
0x88,
+                                    0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 
0x20,
+                                    0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 
0x00,
+                                    0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 
0x00,
+                                    0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 
0x0f,
+                                    0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 
0x10,
+                                    0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 
0x0a,
+                                    0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 
0x0d,
+                                    0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
+}
+
+static const struct drm_display_mode rgb30panel_mode = {
+       .hdisplay       = 720,
+       .hsync_start    = 720 + 45,
+       .hsync_end      = 720 + 45 + 4,
+       .htotal         = 720 + 45 + 4 + 45,
+       .vdisplay       = 720,
+       .vsync_start    = 720 + 15,
+       .vsync_end      = 720 + 15 + 3,
+       .vtotal         = 720 + 15 + 3 + 11,
+       .clock          = 36570,
+       .flags          = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       .width_mm       = 76,
+       .height_mm      = 76,
+};
+
+static const struct st7703_panel_desc rgb30panel_desc = {
+       .mode = &rgb30panel_mode,
+       .lanes = 4,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                     MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
+       .format = MIPI_DSI_FMT_RGB888,
+       .init_sequence = rgb30panel_init_sequence,
+};
+
+static void rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context 
*dsi_ctx)
+{
+       /* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 
0x83);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 
0x00, 0xda,
+                                    0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xc8, 0x02, 
0x30);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 
0x28,
+                                    0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x04, 0x04);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x78, 0x78);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 
0x22, 0xf0,
+                                    0x63);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 
0x05, 0xf9,
+                                    0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 
0x00,
+                                    0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 
0x11, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 
0x50, 0x50,
+                                    0x00, 0x00, 0x12, 0x70, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x25, 0x00, 
0x32,
+                                    0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 
0x77,
+                                    0x77);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 
0xbf, 0xff,
+                                    0x00, 0xff);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 
0x0a, 0x00,
+                                    0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 
0x1e,
+                                    0x02);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x04, 
0x07,
+                                    0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 
0x0e,
+                                    0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 
0x04,
+                                    0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 
0x0b,
+                                    0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x03, 0x03, 
0x03, 0x03,
+                                    0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 
0x80,
+                                    0xc0, 0x10);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 
0x08, 0x00,
+                                    0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 
0x86,
+                                    0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 
0x00,
+                                    0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 
0x88,
+                                    0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 
0x88,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x1a, 
0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 
0x88,
+                                    0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 
0x88,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 
0xff, 0x01);
+}
+
+static const struct drm_display_mode rgb10max3_panel_mode = {
+       .hdisplay       = 720,
+       .hsync_start    = 720 + 40,
+       .hsync_end      = 720 + 40 + 10,
+       .htotal         = 720 + 40 + 10 + 40,
+       .vdisplay       = 1280,
+       .vsync_start    = 1280 + 16,
+       .vsync_end      = 1280 + 16 + 4,
+       .vtotal         = 1280 + 16 + 4 + 14,
+       .clock          = 63800,
+       .flags          = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       .width_mm       = 62,
+       .height_mm      = 109,
+};
+
+static const struct st7703_panel_desc rgb10max3_panel_desc = {
+       .mode = &rgb10max3_panel_mode,
+       .lanes = 4,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                     MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
+       .format = MIPI_DSI_FMT_RGB888,
+       .init_sequence = rgb10max3_panel_init_sequence,
+};
+
+static void gameforcechi_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       /*
+        * Init sequence was supplied by the panel vendor. Panel will not
+        * respond to commands until it is brought out of sleep mode first.
+        */
+
+       mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
+       mipi_dsi_mdelay(dsi_ctx, 250);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 
0x83);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x31, 0x81, 
0x05, 0xf9,
+                                    0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 
0x00,
+                                    0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 
0x11, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 
0x0a,
+                                    0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 
0x50, 0x50,
+                                    0x00, 0x00, 0x08, 0x70, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 
0xf0);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 
0x0b, 0x0b,
+                                    0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 
0x00,
+                                    0xc0, 0x10);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0x00, 
0x1e,
+                                    0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 
0x33,
+                                    0x33);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x10, 0x10);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x6c, 0x7c);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0x08, 0x00, 
0x0e, 0x00,
+                                    0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 
0x10,
+                                    0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 
0x00,
+                                    0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 
0x00,
+                                    0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 
0x88,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 
0x35,
+                                    0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 
0x00,
+                                    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 
0x82, 0x02,
+                                    0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 
0x88,
+                                    0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 
0x42,
+                                    0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 
0x10,
+                                    0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 
0x0b,
+                                    0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 
0x0b,
+                                    0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 
0x07,
+                                    0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 
0xa0,
+                                    0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);
+}
+
+static const struct drm_display_mode gameforcechi_mode = {
+       .hdisplay       = 640,
+       .hsync_start    = 640 + 40,
+       .hsync_end      = 640 + 40 + 2,
+       .htotal         = 640 + 40 + 2 + 80,
+       .vdisplay       = 480,
+       .vsync_start    = 480 + 17,
+       .vsync_end      = 480 + 17 + 5,
+       .vtotal         = 480 + 17 + 5 + 13,
+       .clock          = 23546,
+       .flags          = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       .width_mm       = 71,
+       .height_mm      = 53,
+};
+
+static const struct st7703_panel_desc gameforcechi_desc = {
+       .mode = &gameforcechi_mode,
+       .lanes = 2,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                     MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
+       .format = MIPI_DSI_FMT_RGB888,
+       .init_sequence = gameforcechi_init_sequence,
+};
+
+static int st7703_enable(struct st7703 *ctx)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
+
+       ctx->desc->init_sequence(&dsi_ctx);
+
+       mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+
+       /* It takes the controller 120 msec to wake up after sleep. */
+       mipi_dsi_mdelay(&dsi_ctx, 120);
+
+       mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+
+       if  (dsi_ctx.accum_err)
+               return dsi_ctx.accum_err;
+
+       dev_dbg(ctx->dev, "Panel init sequence done\n");
+       return backlight_enable(ctx->backlight);
+}
+
+static int st7703_disable(struct st7703 *ctx)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
+
+       backlight_disable(ctx->backlight);
+
+       mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+
+       mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+
+       /* It takes the controller 120 msec to enter sleep mode. */
+       mipi_dsi_mdelay(&dsi_ctx, 120);
+
+       return dsi_ctx.accum_err;
+}
+
+static int st7703_unprepare(struct st7703 *ctx)
+{
+
+       gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+       regulator_disable(ctx->iovcc);
+       regulator_disable(ctx->vcc);
+
+       return 0;
+}
+
+static int st7703_prepare(struct st7703 *ctx)
+{
+       int ret;
+
+       dev_dbg(ctx->dev, "Resetting the panel\n");
+       gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+       ret = regulator_enable(ctx->iovcc);
+       if (ret < 0) {
+               dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_enable(ctx->vcc);
+       if (ret < 0) {
+               dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
+               regulator_disable(ctx->iovcc);
+               return ret;
+       }
+
+       /* Give power supplies time to stabilize before deasserting reset. */
+       udelay(10000);
+
+       gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+       udelay(15000);
+
+       return 0;
+}
+
+static int st7703_get_modes(struct st7703 *ctx,
+                           struct display_timings *timings)
+{
+       struct fb_videomode *mode;
+
+       mode = xzalloc(sizeof(*mode));
+
+       drm_display_mode_to_fb_videomode(ctx->desc->mode, mode);
+
+       timings->modes = mode;
+       timings->num_modes = 1;
+
+       return 0;
+}
+
+static int st7703_allpixelson_set(struct param_d *param, void *priv)
+{
+       struct st7703 *ctx = priv;
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
+
+       dev_dbg(ctx->dev, "Setting all pixels %s\n",
+               ctx->allpixelson ? "on" : "off");
+
+       if (ctx->allpixelson)
+               mipi_dsi_generic_write_seq_multi(&dsi_ctx, 
ST7703_CMD_ALL_PIXEL_ON);
+       else
+               mipi_dsi_generic_write_seq_multi(&dsi_ctx, 
ST7703_CMD_ALL_PIXEL_OFF);
+
+       /*
+        * Reset the panel to get video back. NOTE: This isn't a
+        * particularly safe thing to do in general because it assumes
+        * that the screen was on to begin with, but this is just a
+        * debug parameter so it's not a huge deal.
+        */
+       st7703_disable(ctx);
+       st7703_unprepare(ctx);
+       st7703_prepare(ctx);
+       st7703_enable(ctx);
+
+       return dsi_ctx.accum_err;
+}
+
+static int st7703_ioctl(struct vpl *vpl, unsigned int port,
+                       unsigned int cmd, void *ptr)
+{
+       struct st7703 *ctx = container_of(vpl, struct st7703, vpl);
+
+       switch (cmd) {
+       case VPL_PREPARE:
+               return st7703_prepare(ctx);
+       case VPL_ENABLE:
+               return st7703_enable(ctx);
+       case VPL_DISABLE:
+               return st7703_disable(ctx);
+       case VPL_UNPREPARE:
+               return st7703_unprepare(ctx);
+       case VPL_GET_VIDEOMODES:
+               return st7703_get_modes(ctx, ptr);
+       case VPL_GET_BUS_FORMAT:
+               *(u32 *)ptr = MEDIA_BUS_FMT_RGB888_1X24;
+               return 0;
+       default:
+               return 0;
+       }
+}
+
+static int st7703_probe(struct mipi_dsi_device *dsi)
+{
+       struct device_node *backlight_node;
+       struct device *dev = &dsi->dev;
+       struct st7703 *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(ctx->reset_gpio))
+               return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to 
get reset gpio\n");
+
+       mipi_dsi_set_drvdata(dsi, ctx);
+
+       ctx->dev = dev;
+       ctx->desc = of_device_get_match_data(dev);
+
+       dsi->mode_flags = ctx->desc->mode_flags;
+       dsi->format = ctx->desc->format;
+       dsi->lanes = ctx->desc->lanes;
+
+       ctx->vcc = regulator_get(dev, "vcc");
+       if (IS_ERR(ctx->vcc))
+               return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request 
vcc regulator\n");
+
+       ctx->iovcc = regulator_get(dev, "iovcc");
+       if (IS_ERR(ctx->iovcc))
+               return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
+                                    "Failed to request iovcc regulator\n");
+
+       backlight_node = of_parse_phandle(dev->device_node, "backlight", 0);
+       if (backlight_node) {
+               ctx->backlight = of_backlight_find(backlight_node);
+               if (!ctx->backlight) {
+                       dev_err(dev, "Cannot find backlight\n");
+                       return -ENODEV;
+               }
+       }
+
+       ctx->vpl.node = dev->of_node;
+       ctx->vpl.ioctl = st7703_ioctl;
+
+       ret = vpl_register(&ctx->vpl);
+       if (ret)
+               return ret;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0) {
+               dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", 
ret);
+               return ret;
+       }
+
+       dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
+                ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+                drm_mode_vrefresh(ctx->desc->mode),
+                mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
+
+       dev_add_param_bool(dev, "allpixelson", st7703_allpixelson_set, NULL,
+                       &ctx->allpixelson, ctx);
+       return 0;
+}
+
+static const struct of_device_id st7703_of_match[] = {
+       { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
+       { .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
+       { .compatible = "powkiddy,rgb10max3-panel", .data = 
&rgb10max3_panel_desc },
+       { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
+       { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc 
},
+       { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, st7703_of_match);
+
+static struct mipi_dsi_driver st7703_driver = {
+       .probe  = st7703_probe,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = st7703_of_match,
+       },
+};
+module_mipi_dsi_driver(st7703_driver);
+
+MODULE_AUTHOR("Guido Günther <[email protected]>");
+MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
+MODULE_LICENSE("GPL v2");
-- 
2.47.3



Reply via email to