cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-sitronix-st7703.c (18484B)


      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_device.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_SETDISP	 0xB2
     32#define ST7703_CMD_SETRGBIF	 0xB3
     33#define ST7703_CMD_SETCYC	 0xB4
     34#define ST7703_CMD_SETBGP	 0xB5
     35#define ST7703_CMD_SETVCOM	 0xB6
     36#define ST7703_CMD_SETOTP	 0xB7
     37#define ST7703_CMD_SETPOWER_EXT	 0xB8
     38#define ST7703_CMD_SETEXTC	 0xB9
     39#define ST7703_CMD_SETMIPI	 0xBA
     40#define ST7703_CMD_SETVDC	 0xBC
     41#define ST7703_CMD_UNKNOWN_BF	 0xBF
     42#define ST7703_CMD_SETSCR	 0xC0
     43#define ST7703_CMD_SETPOWER	 0xC1
     44#define ST7703_CMD_SETPANEL	 0xCC
     45#define ST7703_CMD_UNKNOWN_C6	 0xC6
     46#define ST7703_CMD_SETGAMMA	 0xE0
     47#define ST7703_CMD_SETEQ	 0xE3
     48#define ST7703_CMD_SETGIP1	 0xE9
     49#define ST7703_CMD_SETGIP2	 0xEA
     50
     51struct st7703 {
     52	struct device *dev;
     53	struct drm_panel panel;
     54	struct gpio_desc *reset_gpio;
     55	struct regulator *vcc;
     56	struct regulator *iovcc;
     57	bool prepared;
     58
     59	struct dentry *debugfs;
     60	const struct st7703_panel_desc *desc;
     61};
     62
     63struct st7703_panel_desc {
     64	const struct drm_display_mode *mode;
     65	unsigned int lanes;
     66	unsigned long mode_flags;
     67	enum mipi_dsi_pixel_format format;
     68	int (*init_sequence)(struct st7703 *ctx);
     69};
     70
     71static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
     72{
     73	return container_of(panel, struct st7703, panel);
     74}
     75
     76#define dsi_generic_write_seq(dsi, seq...) do {				\
     77		static const u8 d[] = { seq };				\
     78		int ret;						\
     79		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
     80		if (ret < 0)						\
     81			return ret;					\
     82	} while (0)
     83
     84static int jh057n_init_sequence(struct st7703 *ctx)
     85{
     86	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
     87
     88	/*
     89	 * Init sequence was supplied by the panel vendor. Most of the commands
     90	 * resemble the ST7703 but the number of parameters often don't match
     91	 * so it's likely a clone.
     92	 */
     93	dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
     94			      0xF1, 0x12, 0x83);
     95	dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
     96			      0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
     97			      0x00, 0x00);
     98	dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
     99			      0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
    100			      0x00);
    101	dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
    102	dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
    103	dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
    104	dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
    105	dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
    106			      0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
    107			      0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
    108	dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
    109	msleep(20);
    110
    111	dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
    112	dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
    113	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
    114			      0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
    115			      0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
    116			      0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
    117			      0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
    118			      0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
    119			      0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
    120			      0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    121			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
    122	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
    123			      0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    124			      0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
    125			      0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
    126			      0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
    127			      0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
    128			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    129			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
    130			      0xA5, 0x00, 0x00, 0x00, 0x00);
    131	dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
    132			      0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
    133			      0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
    134			      0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
    135			      0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
    136			      0x11, 0x18);
    137
    138	return 0;
    139}
    140
    141static const struct drm_display_mode jh057n00900_mode = {
    142	.hdisplay    = 720,
    143	.hsync_start = 720 + 90,
    144	.hsync_end   = 720 + 90 + 20,
    145	.htotal	     = 720 + 90 + 20 + 20,
    146	.vdisplay    = 1440,
    147	.vsync_start = 1440 + 20,
    148	.vsync_end   = 1440 + 20 + 4,
    149	.vtotal	     = 1440 + 20 + 4 + 12,
    150	.clock	     = 75276,
    151	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
    152	.width_mm    = 65,
    153	.height_mm   = 130,
    154};
    155
    156static const struct st7703_panel_desc jh057n00900_panel_desc = {
    157	.mode = &jh057n00900_mode,
    158	.lanes = 4,
    159	.mode_flags = MIPI_DSI_MODE_VIDEO |
    160		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
    161	.format = MIPI_DSI_FMT_RGB888,
    162	.init_sequence = jh057n_init_sequence,
    163};
    164
    165#define dsi_dcs_write_seq(dsi, cmd, seq...) do {			\
    166		static const u8 d[] = { seq };				\
    167		int ret;						\
    168		ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));	\
    169		if (ret < 0)						\
    170			return ret;					\
    171	} while (0)
    172
    173
    174static int xbd599_init_sequence(struct st7703 *ctx)
    175{
    176	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
    177
    178	/*
    179	 * Init sequence was supplied by the panel vendor.
    180	 */
    181
    182	/* Magic sequence to unlock user commands below. */
    183	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
    184
    185	dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
    186			  0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
    187			  0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
    188			  0x05, /* IHSRX = x6 (Low High Speed driving ability) */
    189			  0xF9, /* TX_CLK_SEL = fDSICLK/16 */
    190			  0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
    191			  0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
    192			  /* The rest is undocumented in ST7703 datasheet */
    193			  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    194			  0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
    195			  0x4F, 0x11, 0x00, 0x00, 0x37);
    196
    197	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
    198			  0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
    199			  0x22, /* DT = 15ms XDK_ECP = x2 */
    200			  0x20, /* PFM_DC_DIV = /1 */
    201			  0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
    202
    203	/* RGB I/F porch timing */
    204	dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
    205			  0x10, /* VBP_RGB_GEN */
    206			  0x10, /* VFP_RGB_GEN */
    207			  0x05, /* DE_BP_RGB_GEN */
    208			  0x05, /* DE_FP_RGB_GEN */
    209			  /* The rest is undocumented in ST7703 datasheet */
    210			  0x03, 0xFF,
    211			  0x00, 0x00,
    212			  0x00, 0x00);
    213
    214	/* Source driving settings. */
    215	dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
    216			  0x73, /* N_POPON */
    217			  0x73, /* N_NOPON */
    218			  0x50, /* I_POPON */
    219			  0x50, /* I_NOPON */
    220			  0x00, /* SCR[31,24] */
    221			  0xC0, /* SCR[23,16] */
    222			  0x08, /* SCR[15,8] */
    223			  0x70, /* SCR[7,0] */
    224			  0x00  /* Undocumented */);
    225
    226	/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
    227	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
    228
    229	/*
    230	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
    231	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
    232	 */
    233	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
    234
    235	/* Zig-Zag Type C column inversion. */
    236	dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
    237
    238	/* Set display resolution. */
    239	dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
    240			  0xF0, /* NL = 240 */
    241			  0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
    242				 * RESO_SEL = 720RGB
    243				 */
    244			  0xF0  /* WHITE_GND_EN = 1 (GND),
    245				 * WHITE_FRAME_SEL = 7 frames,
    246				 * ISC = 0 frames
    247				 */);
    248
    249	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
    250			  0x00, /* PNOEQ */
    251			  0x00, /* NNOEQ */
    252			  0x0B, /* PEQGND */
    253			  0x0B, /* NEQGND */
    254			  0x10, /* PEQVCI */
    255			  0x10, /* NEQVCI */
    256			  0x00, /* PEQVCI1 */
    257			  0x00, /* NEQVCI1 */
    258			  0x00, /* reserved */
    259			  0x00, /* reserved */
    260			  0xFF, /* reserved */
    261			  0x00, /* reserved */
    262			  0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
    263			  0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
    264				 * VEDIO_NO_CHECK_EN = 0
    265				 * ESD_WHITE_GND_EN = 0
    266				 * ESD_DET_TIME_SEL = 0 frames
    267				 */);
    268
    269	/* Undocumented command. */
    270	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
    271
    272	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
    273			  0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
    274			  0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
    275			  0x32, /* VRP  */
    276			  0x32, /* VRN */
    277			  0x77, /* reserved */
    278			  0xF1, /* APS = 1 (small),
    279				 * VGL_DET_EN = 1, VGH_DET_EN = 1,
    280				 * VGL_TURBO = 1, VGH_TURBO = 1
    281				 */
    282			  0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
    283			  0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
    284			  0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
    285			  0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
    286			  0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
    287			  0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
    288
    289	/* Reference voltage. */
    290	dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
    291			  0x07, /* VREF_SEL = 4.2V */
    292			  0x07  /* NVREF_SEL = 4.2V */);
    293	msleep(20);
    294
    295	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
    296			  0x2C, /* VCOMDC_F = -0.67V */
    297			  0x2C  /* VCOMDC_B = -0.67V */);
    298
    299	/* Undocumented command. */
    300	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
    301
    302	/* This command is to set forward GIP timing. */
    303	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
    304			  0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
    305			  0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
    306			  0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
    307			  0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
    308			  0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
    309			  0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
    310			  0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    311			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
    312
    313	/* This command is to set backward GIP timing. */
    314	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
    315			  0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    316			  0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
    317			  0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
    318			  0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
    319			  0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
    320			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    321			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
    322			  0xA5, 0x00, 0x00, 0x00, 0x00);
    323
    324	/* Adjust the gamma characteristics of the panel. */
    325	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
    326			  0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
    327			  0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
    328			  0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
    329			  0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
    330			  0x12, 0x18);
    331
    332	return 0;
    333}
    334
    335static const struct drm_display_mode xbd599_mode = {
    336	.hdisplay    = 720,
    337	.hsync_start = 720 + 40,
    338	.hsync_end   = 720 + 40 + 40,
    339	.htotal	     = 720 + 40 + 40 + 40,
    340	.vdisplay    = 1440,
    341	.vsync_start = 1440 + 18,
    342	.vsync_end   = 1440 + 18 + 10,
    343	.vtotal	     = 1440 + 18 + 10 + 17,
    344	.clock	     = 69000,
    345	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
    346	.width_mm    = 68,
    347	.height_mm   = 136,
    348};
    349
    350static const struct st7703_panel_desc xbd599_desc = {
    351	.mode = &xbd599_mode,
    352	.lanes = 4,
    353	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
    354	.format = MIPI_DSI_FMT_RGB888,
    355	.init_sequence = xbd599_init_sequence,
    356};
    357
    358static int st7703_enable(struct drm_panel *panel)
    359{
    360	struct st7703 *ctx = panel_to_st7703(panel);
    361	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
    362	int ret;
    363
    364	ret = ctx->desc->init_sequence(ctx);
    365	if (ret < 0) {
    366		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
    367		return ret;
    368	}
    369
    370	msleep(20);
    371
    372	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
    373	if (ret < 0) {
    374		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
    375		return ret;
    376	}
    377
    378	/* Panel is operational 120 msec after reset */
    379	msleep(60);
    380
    381	ret = mipi_dsi_dcs_set_display_on(dsi);
    382	if (ret)
    383		return ret;
    384
    385	dev_dbg(ctx->dev, "Panel init sequence done\n");
    386
    387	return 0;
    388}
    389
    390static int st7703_disable(struct drm_panel *panel)
    391{
    392	struct st7703 *ctx = panel_to_st7703(panel);
    393	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
    394	int ret;
    395
    396	ret = mipi_dsi_dcs_set_display_off(dsi);
    397	if (ret < 0)
    398		dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
    399
    400	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
    401	if (ret < 0)
    402		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
    403
    404	return 0;
    405}
    406
    407static int st7703_unprepare(struct drm_panel *panel)
    408{
    409	struct st7703 *ctx = panel_to_st7703(panel);
    410
    411	if (!ctx->prepared)
    412		return 0;
    413
    414	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
    415	regulator_disable(ctx->iovcc);
    416	regulator_disable(ctx->vcc);
    417	ctx->prepared = false;
    418
    419	return 0;
    420}
    421
    422static int st7703_prepare(struct drm_panel *panel)
    423{
    424	struct st7703 *ctx = panel_to_st7703(panel);
    425	int ret;
    426
    427	if (ctx->prepared)
    428		return 0;
    429
    430	dev_dbg(ctx->dev, "Resetting the panel\n");
    431	ret = regulator_enable(ctx->vcc);
    432	if (ret < 0) {
    433		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
    434		return ret;
    435	}
    436	ret = regulator_enable(ctx->iovcc);
    437	if (ret < 0) {
    438		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
    439		goto disable_vcc;
    440	}
    441
    442	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
    443	usleep_range(20, 40);
    444	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
    445	msleep(20);
    446
    447	ctx->prepared = true;
    448
    449	return 0;
    450
    451disable_vcc:
    452	regulator_disable(ctx->vcc);
    453	return ret;
    454}
    455
    456static const u32 mantix_bus_formats[] = {
    457	MEDIA_BUS_FMT_RGB888_1X24,
    458};
    459
    460static int st7703_get_modes(struct drm_panel *panel,
    461			    struct drm_connector *connector)
    462{
    463	struct st7703 *ctx = panel_to_st7703(panel);
    464	struct drm_display_mode *mode;
    465
    466	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
    467	if (!mode) {
    468		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
    469			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
    470			drm_mode_vrefresh(ctx->desc->mode));
    471		return -ENOMEM;
    472	}
    473
    474	drm_mode_set_name(mode);
    475
    476	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    477	connector->display_info.width_mm = mode->width_mm;
    478	connector->display_info.height_mm = mode->height_mm;
    479	drm_mode_probed_add(connector, mode);
    480
    481	drm_display_info_set_bus_formats(&connector->display_info,
    482					 mantix_bus_formats,
    483					 ARRAY_SIZE(mantix_bus_formats));
    484
    485	return 1;
    486}
    487
    488static const struct drm_panel_funcs st7703_drm_funcs = {
    489	.disable   = st7703_disable,
    490	.unprepare = st7703_unprepare,
    491	.prepare   = st7703_prepare,
    492	.enable	   = st7703_enable,
    493	.get_modes = st7703_get_modes,
    494};
    495
    496static int allpixelson_set(void *data, u64 val)
    497{
    498	struct st7703 *ctx = data;
    499	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
    500
    501	dev_dbg(ctx->dev, "Setting all pixels on\n");
    502	dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
    503	msleep(val * 1000);
    504	/* Reset the panel to get video back */
    505	drm_panel_disable(&ctx->panel);
    506	drm_panel_unprepare(&ctx->panel);
    507	drm_panel_prepare(&ctx->panel);
    508	drm_panel_enable(&ctx->panel);
    509
    510	return 0;
    511}
    512
    513DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
    514			allpixelson_set, "%llu\n");
    515
    516static void st7703_debugfs_init(struct st7703 *ctx)
    517{
    518	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
    519
    520	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
    521			    &allpixelson_fops);
    522}
    523
    524static void st7703_debugfs_remove(struct st7703 *ctx)
    525{
    526	debugfs_remove_recursive(ctx->debugfs);
    527	ctx->debugfs = NULL;
    528}
    529
    530static int st7703_probe(struct mipi_dsi_device *dsi)
    531{
    532	struct device *dev = &dsi->dev;
    533	struct st7703 *ctx;
    534	int ret;
    535
    536	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    537	if (!ctx)
    538		return -ENOMEM;
    539
    540	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
    541	if (IS_ERR(ctx->reset_gpio))
    542		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
    543
    544	mipi_dsi_set_drvdata(dsi, ctx);
    545
    546	ctx->dev = dev;
    547	ctx->desc = of_device_get_match_data(dev);
    548
    549	dsi->mode_flags = ctx->desc->mode_flags;
    550	dsi->format = ctx->desc->format;
    551	dsi->lanes = ctx->desc->lanes;
    552
    553	ctx->vcc = devm_regulator_get(dev, "vcc");
    554	if (IS_ERR(ctx->vcc))
    555		return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
    556
    557	ctx->iovcc = devm_regulator_get(dev, "iovcc");
    558	if (IS_ERR(ctx->iovcc))
    559		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
    560				     "Failed to request iovcc regulator\n");
    561
    562	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
    563		       DRM_MODE_CONNECTOR_DSI);
    564
    565	ret = drm_panel_of_backlight(&ctx->panel);
    566	if (ret)
    567		return ret;
    568
    569	drm_panel_add(&ctx->panel);
    570
    571	ret = mipi_dsi_attach(dsi);
    572	if (ret < 0) {
    573		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
    574		drm_panel_remove(&ctx->panel);
    575		return ret;
    576	}
    577
    578	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
    579		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
    580		 drm_mode_vrefresh(ctx->desc->mode),
    581		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
    582
    583	st7703_debugfs_init(ctx);
    584	return 0;
    585}
    586
    587static void st7703_shutdown(struct mipi_dsi_device *dsi)
    588{
    589	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
    590	int ret;
    591
    592	ret = drm_panel_unprepare(&ctx->panel);
    593	if (ret < 0)
    594		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
    595
    596	ret = drm_panel_disable(&ctx->panel);
    597	if (ret < 0)
    598		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
    599}
    600
    601static int st7703_remove(struct mipi_dsi_device *dsi)
    602{
    603	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
    604	int ret;
    605
    606	st7703_shutdown(dsi);
    607
    608	ret = mipi_dsi_detach(dsi);
    609	if (ret < 0)
    610		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
    611
    612	drm_panel_remove(&ctx->panel);
    613
    614	st7703_debugfs_remove(ctx);
    615
    616	return 0;
    617}
    618
    619static const struct of_device_id st7703_of_match[] = {
    620	{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
    621	{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
    622	{ /* sentinel */ }
    623};
    624MODULE_DEVICE_TABLE(of, st7703_of_match);
    625
    626static struct mipi_dsi_driver st7703_driver = {
    627	.probe	= st7703_probe,
    628	.remove = st7703_remove,
    629	.shutdown = st7703_shutdown,
    630	.driver = {
    631		.name = DRV_NAME,
    632		.of_match_table = st7703_of_match,
    633	},
    634};
    635module_mipi_dsi_driver(st7703_driver);
    636
    637MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
    638MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
    639MODULE_LICENSE("GPL v2");