Hi everyone
I am having issues with CM4 when sending commands via DSI1 to a ST7703 controlled LCD (3,5" 640x480).
In 80% of the cases the LCD is initialized properly and works for days without any issue, but in 20% initializing does not work properly (LCD stays dark and I see errors regarding DSI-communication in dmesg).
I am building a Yocto Poky (Scarthgap) based system, using latest RPI 6.6 kernel (6.6.58).
I took the original panel-sitronix-st7703.c and added my init-codes and accordingly the compatible strings.
The rpi bootfiles stamp is 20240319.
Tested on two different HW-setups with many different CM4s connected:
1.) CM4 IO-Board (with intermediate PCB to match the pinning. Overall length from CM4IO to LCD controller 130mm)
2.) My custom-made board (impedance-controlled, pair- and inter-pair-length matched). Overall length of the FFC (from board-connector to LCD controller): 50mm. For EMC I added common mode chokes to DSI clock and data lines (Murata P0NSC900HL2L / DLP0NSN900HL2L / DLM0NSN900HY2 / DLM0NSM900HY2) that work properly on way faster HDMI implementations.
Tested with two different ST7703 LCDs:
1.) Startek KD035VGFID251 (.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM)
2.) TSONT H35C302-00W (custom made; .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM)
I do NOT think that the electrical connection is the problem, as the situation does not get worse when adding additional 500mm standard (no impedance matching!!) FFC!
I see the following problems during initialization (no matter if it is a power-cycle or the "reboot" command) of the panel (I added some additional output to the driver to see which functions are called):
1.)Sometimes it is looking like this, but this just means that sending of a command AFTER the init code does not work, so to me thats the same failure as above...:2.)3.) After being properly initialized a blanking/unblanking via the console ALWAYS FAILS (not only in 20% of all cases!!) like this (note that also in this case RESET and LP11 is OK before sending init code - thus I do not really understand the different behaviour to a "reboot" command which fails just "seldom"):
echo 2 > /sys/class/graphics/fb0/blankecho 0 > /sys/class/graphics/fb0/blankRESET-signal and entering LP11 before releasing RESET looks OK (Pic is taken after cold-start; #1=D0_P. #2=D0_N, DigitalChannel D0=RESET): Overlay:My driver, I deleted all unnecessary functions to keep it small...
I am curious why video-data is shown properly over days but sending commands does sometimes fail...
AND why it does not fail at the very first command sent (would be 0xB9 IIRC), but at a (random) command during the whole init sequence ..
Any help to where to look at is appreciated - THANKS in advance!
I am having issues with CM4 when sending commands via DSI1 to a ST7703 controlled LCD (3,5" 640x480).
In 80% of the cases the LCD is initialized properly and works for days without any issue, but in 20% initializing does not work properly (LCD stays dark and I see errors regarding DSI-communication in dmesg).
I am building a Yocto Poky (Scarthgap) based system, using latest RPI 6.6 kernel (6.6.58).
I took the original panel-sitronix-st7703.c and added my init-codes and accordingly the compatible strings.
The rpi bootfiles stamp is 20240319.
Tested on two different HW-setups with many different CM4s connected:
1.) CM4 IO-Board (with intermediate PCB to match the pinning. Overall length from CM4IO to LCD controller 130mm)
2.) My custom-made board (impedance-controlled, pair- and inter-pair-length matched). Overall length of the FFC (from board-connector to LCD controller): 50mm. For EMC I added common mode chokes to DSI clock and data lines (Murata P0NSC900HL2L / DLP0NSN900HL2L / DLM0NSN900HY2 / DLM0NSM900HY2) that work properly on way faster HDMI implementations.
Tested with two different ST7703 LCDs:
1.) Startek KD035VGFID251 (.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM)
2.) TSONT H35C302-00W (custom made; .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM)
I do NOT think that the electrical connection is the problem, as the situation does not get worse when adding additional 500mm standard (no impedance matching!!) FFC!
I see the following problems during initialization (no matter if it is a power-cycle or the "reboot" command) of the panel (I added some additional output to the driver to see which functions are called):
1.)
Code:
[ 3.698613] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_probe ...[ 3.698661] panel-sitronix-st7703 fe700000.dsi.0: supply vcc not found, using dummy regulator[ 3.698751] panel-sitronix-st7703 fe700000.dsi.0: supply iovcc not found, using dummy regulator[ 4.003699] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_prepare ...[ 4.042555] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_enable ...[ 4.042566] panel-sitronix-st7703 fe700000.dsi.0: Sending init code for TSONT H35C302_00W ...[ 4.547329] panel-sitronix-st7703 fe700000.dsi.0: sending command 0xe9 failed: -110[ 4.547343] panel-sitronix-st7703 fe700000.dsi.0: Panel init sequence failed: -110[ 4.597282] panel-sitronix-st7703 fe700000.dsi.0: 640x480@60 24bpp dsi 2dl - ready
Code:
[ 3.881886] panel-sitronix-st7703 fe700000.dsi.0: Sending init code for TSONT H35C302_00W ...[ 4.476200] panel-sitronix-st7703 fe700000.dsi.0: Failed to exit sleep mode: -110[ 4.526171] panel-sitronix-st7703 fe700000.dsi.0: 640x480@60 24bpp dsi 2dl - ready
Code:
[ 4.087125] panel-sitronix-st7703 fe700000.dsi.0: Sending init code for TSONT H35C302_00W ...[ 4.592052] [drm:vc4_dsi_host_transfer] *ERROR* DSI transfer failed whilst in HS mode stat: 0x00020803[ 4.592086] panel-sitronix-st7703 fe700000.dsi.0: sending command 0xb4 failed: -110[ 4.592100] panel-sitronix-st7703 fe700000.dsi.0: Panel init sequence failed: -110[ 4.662052] panel-sitronix-st7703 fe700000.dsi.0: 640x480@60 24bpp dsi 2dl - ready
echo 2 > /sys/class/graphics/fb0/blank
Code:
[ 27.051655] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_disable ...[ 27.182124] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_unprepare ...
Code:
[ 34.402469] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_prepare ...[ 34.447529] panel-sitronix-st7703 fe700000.dsi.0: Called st7703_enable ...[ 34.447539] panel-sitronix-st7703 fe700000.dsi.0: Sending init code for TSONT H35C302_00W ...[ 34.952123] [drm:vc4_dsi_host_transfer] *ERROR* DSI transfer failed whilst in HS mode stat: 0x05020003[ 34.952155] panel-sitronix-st7703 fe700000.dsi.0: sending command 0xba failed: -110[ 34.952169] panel-sitronix-st7703 fe700000.dsi.0: Panel init sequence failed: -110
Code:
dts-v1/;/plugin/;/ { compatible = "brcm,bcm2835"; fragment@0 { target = <&dsi1>; __overlay__ { #address-cells = <1>; #size-cells = <0>; status = "okay"; port { dsi_out: endpoint { remote-endpoint = <&panel_in>; }; }; dsi_panel: dsi_panel@0 { reg = <0>; compatible = "tsont,h35c302-00w"; // Add a regulator if you have one //power-supply = <®_display>; // Add a backlight controller if you have one //backlight = <&backlight>; // Add reset pin reset-gpios = <&gpio 22 1>; /* GPIO PIN 22, active Low */ port { panel_in: endpoint { remote-endpoint = <&dsi_out>; }; }; }; }; };};
Code:
#include <linux/debugfs.h>#include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/media-bus-format.h>#include <linux/mod_devicetable.h>#include <linux/module.h>#include <linux/of.h>#include <linux/regulator/consumer.h>#include <video/display_timing.h>#include <video/mipi_display.h>#include <drm/drm_mipi_dsi.h>#include <drm/drm_modes.h>#include <drm/drm_panel.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 0xEFstruct st7703 {struct device *dev;struct drm_panel panel;struct gpio_desc *reset_gpio;struct regulator *vcc;struct regulator *iovcc;bool prepared;struct dentry *debugfs;const struct st7703_panel_desc *desc;enum drm_panel_orientation orientation;};struct st7703_panel_desc {const struct drm_display_mode *mode;unsigned int lanes;unsigned long mode_flags;enum mipi_dsi_pixel_format format;int (*init_sequence)(struct st7703 *ctx);};static inline struct st7703 *panel_to_st7703(struct drm_panel *panel){return container_of(panel, struct st7703, panel);}static int kd035vgfid251_init_sequence (struct st7703 *ctx){struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);/* * Init sequence was supplied by the panel vendor. Panel will not * respond to commands until it is brought out of sleep mode first. */dev_info(ctx->dev, "Sending init code for STARTEK KD035VGFID251 ...\n");/* Magic sequence to unlock user commands below. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xDA, 0x80);/* Set display resolution. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, /* 480 */ 0x13, /* 640 */ 0x70);/* RGB I/F porch timing */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, /* VBP_RGB_GEN */ 0x10, /* VFP_RGB_GEN */ 0x28, /* DE_BP_RGB_GEN */ 0x28, /* DE_FP_RGB_GEN */ /* The rest is undocumented in ST7703 datasheet */ 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00);/* Zig-Zag Type C column inversion. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x82);/* Reference voltage. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x07, /* VREF_SEL */ 0x07 /* NVREF_SEL */);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x9C, /* VCOMDC_F */ 0x9C /* VCOMDC_B */);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x2A, 0x62, 0xF0, 0x60);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x31, /* VC_main = 0, Lane_Number = 2 */ 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, 0x90, 0x0A, 0x00, 0x00, 0x01, 0x4F, 0x01, 0x00, 0x00, 0x37);/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);/* Undocumented command. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);/* Source driving settings. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, /* N_POPON */ 0x73, /* N_NOPON */ 0x50, /* I_POPON */ 0x50, /* I_NOPON */ 0x00, /* SCR[31,24] */ 0x00, /* SCR[23,16] */ 0x12, /* SCR[15,8] */ 0x70, /* SCR[7,0] */ 0x00 /* Undocumented */);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x25, /* VBTHS, VBTLS*/ 0xC0, /* FBOFF_VGH, FBOFF_VGL */ 0x32, /* VRP */ 0x32, /* VRN */ 0x77, /* reserved */ 0xE4, /* 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) */);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xBF, 0xFF, 0x00, 0xFF);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xB8, 0x00, 0x0A, 0x00, 0x00, 0x00);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1E, 0x02);/* * 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(dsi, ST7703_CMD_SETPANEL, 0x0B);/* Adjust the gamma characteristics of the panel. */mipi_dsi_dcs_write_seq(dsi, 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(dsi, ST7703_CMD_SETEQ, 0x07, /* PNOEQ */ 0x07, /* NNOEQ */ 0x0B, /* PEQGND */ 0x0B, /* NEQGND */ 0x0B, /* PEQVCI */ 0x0B, /* 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 */);/* This command is to set forward GIP timing. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xC8, 0x10, 0x0A, 0x00, 0x00, 0xF0, 0x08, 0x12, 0x31, 0x23, 0x4F, 0x86, 0xF0, 0x08, 0x47, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x88, 0x88, 0x08, 0xF8, 0xF4, 0x46, 0x60, 0x02, 0x28, 0x88, 0x88, 0x88, 0x88, 0x18, 0xF8, 0xF5, 0x57, 0x71, 0x13, 0x38, 0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);/* This command is to set backward GIP timing. */mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xF8, 0x18, 0xF8, 0x83, 0x31, 0x17, 0x75, 0x58, 0x88, 0x88, 0x88, 0xF8, 0x08, 0xF8, 0x82, 0x20, 0x06, 0x64, 0x48, 0x88, 0x88, 0x23, 0x00, 0x00, 0x03, 0xF0, 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(dsi, ST7703_CMD_UNKNOWN_EF, 0xFF, 0xFF, 0x01);/* The lines below are done in st7703_enable()mipi_dsi_dcs_exit_sleep_mode(dsi);msleep(150);mipi_dsi_dcs_set_display_on(dsi);*/return 0;}static const struct drm_display_mode kd035vgfid251_mode = {.hdisplay = 640,// H resolution.hsync_start = 640 + 26,// resolution + front porch.hsync_end = 640 + 26 + 4,// resolution + front porch + sync pulse.htotal = 640 + 26 + 4 + 10,// resolution + front porch + sync pulse + back porch = 680px.vdisplay = 480,// V resolution.vsync_start = 480 + 16,// resolution + front porch.vsync_end = 480 + 16 + 4,// resolution + front porch + sync pulse.vtotal = 480 + 16 + 4 + 14,// resolution + front porch + sync pulse + back porch = 514px.clock = 20972,// 60Hz.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,.width_mm = 70,.height_mm = 53,};static const struct st7703_panel_desc kd035vgfid251_desc = {.mode = &kd035vgfid251_mode,.lanes = 2,.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,.format = MIPI_DSI_FMT_RGB888,.init_sequence = kd035vgfid251_init_sequence,};static int h35c302_00w_init_sequence(struct st7703 *ctx){struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);/* * Init sequence was supplied by the panel vendor. Panel will not * respond to commands until it is brought out of sleep mode first. */dev_info(ctx->dev, "Sending init code for TSONT H35C302_00W ...\n");mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);mipi_dsi_dcs_write_seq(dsi, 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(dsi, ST7703_CMD_SETPOWER_EXT, 0x26);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, 0x00);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b, 0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xc0, 0x10);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33, 0x33);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x10, 0x10);mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x6c, 0x7c);mipi_dsi_dcs_write_seq(dsi, 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(dsi, 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, 0xB1, 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(dsi, 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, 0x0a, 0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);return 0;}static const struct drm_display_mode h35c302_00w_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 h35c302_00w_desc = {.mode = &h35c302_00w_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 = h35c302_00w_init_sequence,};static int st7703_enable(struct drm_panel *panel){struct st7703 *ctx = panel_to_st7703(panel);struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);int ret;dev_info(ctx->dev, "Called st7703_enable ..."); //###ret = ctx->desc->init_sequence(ctx);if (ret < 0) {dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);return ret;}msleep(50); //### increased from 20 by MWret = mipi_dsi_dcs_exit_sleep_mode(dsi);if (ret < 0) {dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);return ret;}/* It takes the controller 120 msec to wake up after sleep. */msleep(150);ret = mipi_dsi_dcs_set_display_on(dsi);if (ret)return ret;dev_dbg(ctx->dev, "Panel init sequence done\n");return 0;}static int st7703_disable(struct drm_panel *panel){struct st7703 *ctx = panel_to_st7703(panel);struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);int ret;dev_info(ctx->dev, "Called st7703_disable ..."); //###ret = mipi_dsi_dcs_set_display_off(dsi);if (ret < 0)dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);ret = mipi_dsi_dcs_enter_sleep_mode(dsi);if (ret < 0)dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);/* It takes the controller 120 msec to enter sleep mode. */msleep(120);return 0;}static int st7703_unprepare(struct drm_panel *panel){struct st7703 *ctx = panel_to_st7703(panel);dev_info(ctx->dev, "Called st7703_unprepare ..."); //###if (!ctx->prepared)return 0;gpiod_set_value_cansleep(ctx->reset_gpio, 1);regulator_disable(ctx->iovcc);regulator_disable(ctx->vcc);ctx->prepared = false;return 0;}static int st7703_prepare(struct drm_panel *panel){struct st7703 *ctx = panel_to_st7703(panel);int ret;dev_info(ctx->dev, "Called st7703_prepare ..."); //###if (ctx->prepared)return 0;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. */usleep_range(10000, 20000);gpiod_set_value_cansleep(ctx->reset_gpio, 0);usleep_range(20000, 25000);//###increasing to 120-150ms does not help herectx->prepared = true;return 0;}static const u32 mantix_bus_formats[] = {MEDIA_BUS_FMT_RGB888_1X24,};static int st7703_get_modes(struct drm_panel *panel, struct drm_connector *connector){struct st7703 *ctx = panel_to_st7703(panel);struct drm_display_mode *mode;mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);if (!mode) {dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,drm_mode_vrefresh(ctx->desc->mode));return -ENOMEM;}drm_mode_set_name(mode);mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;connector->display_info.width_mm = mode->width_mm;connector->display_info.height_mm = mode->height_mm;drm_mode_probed_add(connector, mode);drm_display_info_set_bus_formats(&connector->display_info, mantix_bus_formats, ARRAY_SIZE(mantix_bus_formats));return 1;}static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel){struct st7703 *st7703 = panel_to_st7703(panel);return st7703->orientation;}static const struct drm_panel_funcs st7703_drm_funcs = {.disable = st7703_disable,.unprepare = st7703_unprepare,.prepare = st7703_prepare,.enable = st7703_enable,.get_modes = st7703_get_modes,.get_orientation = st7703_get_orientation,};static int allpixelson_set(void *data, u64 val){struct st7703 *ctx = data;struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);dev_info(ctx->dev, "Setting all pixels on\n");mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);msleep(val * 1000);/* Reset the panel to get video back */drm_panel_disable(&ctx->panel);drm_panel_unprepare(&ctx->panel);drm_panel_prepare(&ctx->panel);drm_panel_enable(&ctx->panel);return 0;}DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,allpixelson_set, "%llu\n");static void st7703_debugfs_init(struct st7703 *ctx){ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx, &allpixelson_fops);}static void st7703_debugfs_remove(struct st7703 *ctx){debugfs_remove_recursive(ctx->debugfs);ctx->debugfs = NULL;}static int st7703_probe(struct mipi_dsi_device *dsi){struct device *dev = &dsi->dev;struct st7703 *ctx;int ret;dev_info(dev, "Called st7703_probe ..."); //###ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);if (!ctx)return -ENOMEM;ctx->reset_gpio = devm_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 = devm_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 = devm_regulator_get(dev, "iovcc");if (IS_ERR(ctx->iovcc))return dev_err_probe(dev, PTR_ERR(ctx->iovcc), "Failed to request iovcc regulator\n");ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);if (ret < 0)return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs, DRM_MODE_CONNECTOR_DSI);ret = drm_panel_of_backlight(&ctx->panel);if (ret)return ret;ctx->panel.prepare_prev_first = true;//### ADDED by MW, otherwise LP11 is not set before reset/init of the paneldrm_panel_add(&ctx->panel);msleep(10); //### ADDED by MW, sometimes below mipi_dsi_attach does not work properly as "host not ready"ret = mipi_dsi_attach(dsi);if (ret < 0) {dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);drm_panel_remove(&ctx->panel);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);st7703_debugfs_init(ctx);return 0;}static void st7703_shutdown(struct mipi_dsi_device *dsi){struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);int ret;dev_info(&dsi->dev, "Called st7703_shutdown ..."); //###ret = drm_panel_unprepare(&ctx->panel);if (ret < 0)dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);ret = drm_panel_disable(&ctx->panel);if (ret < 0)dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);}static void st7703_remove(struct mipi_dsi_device *dsi){struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);int ret;st7703_shutdown(dsi);dev_info(&dsi->dev, "Called st7703_remove ..."); //###ret = mipi_dsi_detach(dsi);if (ret < 0)dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);drm_panel_remove(&ctx->panel);st7703_debugfs_remove(ctx);}static const struct of_device_id st7703_of_match[] = {{ .compatible = "startek,kd035vgfid251", .data = &kd035vgfid251_desc },{ .compatible = "tsont,h35c302-00w", .data = &h35c302_00w_desc },{ /* sentinel */ }};MODULE_DEVICE_TABLE(of, st7703_of_match);static struct mipi_dsi_driver st7703_driver = {.probe= st7703_probe,.remove = st7703_remove,.shutdown = st7703_shutdown,.driver = {.name = DRV_NAME,.of_match_table = st7703_of_match,},};module_mipi_dsi_driver(st7703_driver);
I am curious why video-data is shown properly over days but sending commands does sometimes fail...
AND why it does not fail at the very first command sent (would be 0xB9 IIRC), but at a (random) command during the whole init sequence ..
Any help to where to look at is appreciated - THANKS in advance!
Statistics: Posted by RinaMat — Tue Nov 12, 2024 10:48 am