How can drive SN65DIS85?

Hi, kind NVIDIA and everyone!

I want to drive LVDS LCD using DSI-to-LVDS convertor SN65DIS85 for DSI_A port (tegra dc.1) of Jetson Nano.
I referred Documentation/devicetree/bindings/video/sn65dsi85.txt and linux/sn65dsi83_drv.c at v4.14/dey-2.6/maint · digi-embedded/linux · GitHub, but I could not find how to describe DTS for DSI and I2C, and how to implement for kernel driver.

Please tell me the full example DTS and driver code, or the solution for me.
Thanks,
Best Regards,
aither

Please download the kernel source from dlc and check if any src satisfies your case.

Hi, WayneWWW
First, thanks for your response.

Did you mean L4T source?
I already checked it.

You could check dsi.c for dsi panel driver.

All the display related drivers are under below path.

kernel/nvidia/drivers/video/tegra/dc/

But the device tree are separate so need to check by yourself.

hardware/nvidia/platform/tegra/common/kernel-dts/

Hi, WayneWWW

I already checked them.
My question: how to describe the DSI port with DSI-LVDS converter at DTB?

Thanks, aither

We don’t have such case.

I will let other forum user to share experience.

Hi, WayneWWW

Please tell me how to describe DSI port without DSI-panel at DTB

Thanks, aither

I don’t get he meaning of “how to describe DSI port without DSI-panel”.

TX1 and TX2 all enable DSI port in DTB by default when there is no DSI panel but I don’t think that is what you want.

First, thanks for your kind service.

I use the Jetson Nano module, and at tegra210-p3448-0000-p3449-0000-b00-hdmi-dsi.dts:
host1x {
/* DSI mapped to tegradc.1 /
dc@54240000 {
status = “okay”;
nvidia,dc-or-node = “/host1x/dsi”;
nvidia,dc-connector = <&dsi>;
/
DSI supplies */
avdd_dsi_csi-supply = <&max77620_sd3>;
avdd_lcd-supply = <&battery_reg>;
dvdd_lcd-supply = <&battery_reg>;
vdd_lcd_bl_en-supply = <&battery_reg>;
vdd_lcd_bl-supply = <&battery_reg>;
};

	dsi {
		nvidia,dsi-controller-vs = <DSI_VS_1>;
		status = "okay";
		nvidia,active-panel = <&panel_a_wuxga_8_0>;
		nvidia,dsi-csi-loopback;
		panel-a-wuxga-8-0 {
			status = "okay";
			/* Only 2 lanes used on Porg */
			nvidia,dsi-n-data-lanes = <2>;
		};
	};
};

I checked the wave out of DSI port, when use “nvidia,active-panel = <&panel_a_wuxga_8_0>;” the some wave outputed, but when without “nvidia,active-panel = <&panel_a_wuxga_8_0>;” no wave outputed.
So my question is: when do not use DSI-in-panel, how to describe the above DTB?

Thanks again,
aither

Hi,

We don’t support such case. You must have a nvidia,active-panel.
You have to write your own driver for those you write into nvidia,active-panel. For example, there is a panel driver for panel_a_wuxga_8_0.

I have the same question. It would be extremely helpful to have some information on how to setup the DSI to LVDS conversion step by step. On the NXP iMX8 platform the DSI interface reads the panel configuration from the SN65DSI8x parameters. However the SN65DSI8x driver from nVidia looks like it is only configuring the SN65DSI8x and that’s it.

At this moment I’m assuming that getting the SN65DSI8x to work on a TX2 involves these steps:

  • Choose an existing panel from the drivers (it seems to me there is not much difference between the panel drivers since the timing parameters are in the DTS file)
  • Adjust the display timing parameters in the DTS file for the panel; maybe tweak display enable / backlight signals
  • Add the SN65DSI8x chip to the I2C bus and fill in the parameters to setup the registers
    When the DSI outputs a signal the SN65DSI8x picks it up and converts it to LVDS.

Am I correct so far?

The next question I have is: how to split a display over 2 DSI outputs? LVDS tops out at about 1920x1080 and higher resolution panels require up to 8 LVDS lanes which will have to be split between two SN65DSI8x chips. I have such a carrier board for the TX2.
Is there a way to connect 2 DSI outputs to one logical screen or is it necessary to create two logical screens each with half the resolution?

how to split a display over 2 DSI outputs

Unfortunately, none of jetson platform is able to run 2 DSI output now.

For TX1 series, the hw capability does not support.

Let me rephrase the question: I have 1 display panel (for example: 1980x1980) which has a total of 16 LVDS lanes. There are 2 SN65DSI84 chips on the board which each use 4 DSI lanes and turn these into 8 LVDS lanes. So 8 DSI lanes (with 2 clock lanes) are converted into 16 LVDS lanes. The first 8 LVDS lanes drive the upper half of the panel, the last 8 lanes drive the lower half of the panel. The panel is basically two seperate displays in one.

Is this a supported configuration?

Figure27 in the ‘NVIDIA Jetson TX2 Series OEM Product Design Guide’ (revision 20190606
) says that a DSI dual link configuration can drive two seperate displays or 1 display. If it means that a larger logical display can be spread across two smaller physical displays (with some constraints on the resolution) it would be perfect for my application IF the split can be defined for upper half and lower half to go into a specific group of DSI lanes. One of the primary reasons for my customer to choose the TX2 is to drive bigger displays through DSI / LVDS so this is the most important feature for them.

Hi,

Yes, I understood the OEM product DG say it can have split DSI to separate displays. Unfortunately, the software driver does not implement it very well and has problem. Since TX2 has been published for some years, other forum users asked similar questions before as below post.

This is still no fix and currently no plan for it.

OK clear. I’ll need to take this back to the customer first.
BTW I noticed that I made an error in the display panel configuration. The split isn’t horizontal (upper/lower) but vertical (left / right).

In the end I managed to get things to work. The hardware I work with has 2 sn65dsi84 DSI to LVDS bridges to make 4 LVDS channels (16 lanes) from 8 DSI lanes. This should allow to drive up to 4k LVDS displays.

I added the dsi patches from this thread: Two DSI panels displays on TX2 with Jetpack 3.2.1? - #7 by Ratbert

The DTS part to get the DSI output to work.

	/* HDMI 1 (port 1) */
	nvdisplay@15210000 {
		status = "disabled";
		win-mask = <0x0C>;
    };

	nvdisplay@15200000 {
		nvidia,dc-or-node = "/host1x/dsi";
		nvidia,dc-connector = <&dsi>;
		status = "okay";
		win-mask = <0x03>;
	};
	
	/* HDMI 2 (port 0) */
	nvdisplay@15220000 {
		status = "okay";
		win-mask = <0x30>;
	};
	
	/******  DSI (LVDS 1) *************/
	
	dsi {	/* dsi@15300000 */
		nvidia,dsi-controller-vs = <DSI_VS_1>;
		status = "okay";
		/* nvidia,active-panel = <&panel_lvds1>; */ /* single panel output */
		nvidia,active-panel = <&panel_lvds_dual1>;		/* ganged panel output */


	   panel_lvds1: panel-lvds1 {
		    status = "disabled";
		    compatible = "c,wxga-14-0";
		    nvidia,dsi-instance = <0>;
		    nvidia,dsi-n-data-lanes = <4>;
		    nvidia,dsi-pixel-format = <3>;		/* 24 bit planar*/
		    nvidia,dsi-refresh-rate = <60>;
		    nvidia,dsi-video-data-type = <0>;
		    nvidia,dsi-video-clock-mode = <0>;
		    nvidia,dsi-video-burst-mode = <1>;
		    nvidia,dsi-ganged-type = <0>;		/* 0= not used, 1=left/right, 2=odd/even 3=overlapped ?*/
		    nvidia,dsi-split-link-type= <0>;	/* split link, 1=A/B) */
		    nvidia,dsi-ganged-swap-links = <0>;
		    nvidia,dsi-ganged-write-to-all-links = <0>;
		    nvidia,dsi-controller-vs = <1>;
		    nvidia,dsi-virtual-channel = <0>;
		    nvidia,dsi-panel-reset = <1>;
		    nvidia,panel-bl-pwm-gpio = <&tegra_aon_gpio TEGRA_AON_GPIO(U, 0) 1>; /* PU0 */
		    nvidia,dsi-ulpm-not-support = <1>;
		    nvidia,dsi-suspend-stop-stream-late = <1>;
		    nvidia,dsi-power-saving-suspend = <1>;
		    nvidia,default_color_space = <1>;
			
			pwms = <&tegra_pwm1 0 40161>;
			
			disp-default-out {
				nvidia,out-type = <2>;
				nvidia,out-width = <220>;
				nvidia,out-height = <180>;
				nvidia,out-flags = <(0 << 3)>;
				nvidia,out-xres = <800>;
				nvidia,out-yres = <600>;
		    };
		    display-timings {
		    	/delete-node/ 1200x1920-32-60Hz;  /*remove existing resolution*/
		    
		    	/* drive 2 800x600 panels as one single panel */
		     	800x600-32-60Hz {
					clock-frequency = <40000000>;
					hactive = <800>;
					vactive = <600>;
					hfront-porch = <220>;
					hback-porch = <34>;
					vfront-porch = <24>;
					vback-porch = <4>;
					hsync-len = <13>;
					vsync-len = <2>;
					hsync-active = <0>;
					vsync-active = <0>;
					de-active = <1>;
					nvidia,h-ref-to-sync = <1>;
					nvidia,v-ref-to-sync = <11>;
		     	};
			};

		};

	   panel_lvds_dual1: panel-lvds-dual1 {
		    status = "okay";
		    compatible = "c,wxga-14-0";
		    nvidia,dsi-instance = <0>;
		    nvidia,dsi-n-data-lanes = <8>;
		    nvidia,dsi-pixel-format = <3>;		/* 24 bit planar*/
		    nvidia,dsi-refresh-rate = <60>;
		    nvidia,dsi-video-data-type = <0>;
		    nvidia,dsi-video-clock-mode = <0>;
		    nvidia,dsi-video-burst-mode = <1>;
		    nvidia,dsi-ganged-type = <1>;		/* 0= not used, 1=left/right, 2=odd/even 3=overlapped ?*/
		    nvidia,dsi-split-link-type= <0>;	/* split link, 1=A/B ) */
		    nvidia,dsi-ganged-swap-links = <1>;
		    nvidia,dsi-ganged-write-to-all-links = <0>;
		    nvidia,dsi-controller-vs = <1>;
		    nvidia,dsi-virtual-channel = <0>;
		    nvidia,dsi-panel-reset = <1>;
		    nvidia,panel-bl-pwm-gpio = <&tegra_aon_gpio TEGRA_AON_GPIO(U, 0) 1>; /* PU0 */
		    nvidia,dsi-ulpm-not-support = <1>;
		    nvidia,dsi-suspend-stop-stream-late = <1>;
		    nvidia,dsi-power-saving-suspend = <1>;
		    nvidia,default_color_space = <1>;
			
			pwms = <&tegra_pwm1 0 40161>;
			
			disp-default-out {
				nvidia,out-type = <2>;
				nvidia,out-width = <220>;
				nvidia,out-height = <180>;
				nvidia,out-flags = <(0 << 3)>;
				nvidia,out-xres = <1600>;
				nvidia,out-yres = <600>;
		    };
		    display-timings {
		    	/delete-node/ 1200x1920-32-60Hz;  /*remove existing resolution*/
		    
		    	/* drive 2 800x600 panels as one single panel */
		     	1600x600-32-60Hz {
					clock-frequency = <80000000>;
					hactive = <1600>;
					vactive = <600>;
					hfront-porch = <420>;
					hback-porch = <76>;
					vfront-porch = <24>;
					vback-porch = <4>;
					hsync-len = <26>;
					vsync-len = <2>;
					hsync-active = <0>;
					vsync-active = <0>;
					de-active = <1>;
					nvidia,h-ref-to-sync = <1>;
					nvidia,v-ref-to-sync = <11>;
		     	};
			};

		};
	
	};

I used an 800x600 LVDS panel for testing. For dual output the desktop size must be double so the resolution is set to 1600x600. There also has to be room for the hsync pulses, front porch and back porch. When doubling the horizontal resolution the hsync pulses, front porch and back porch must also be made larger. Without that I get the dreaded ’ dsi: video fifo overflow’ message. And don’t forget to double the pixel clock frequency.

The next problem for me was the sn65dsi84 driver. The one that comes with the TX2 kernel is very rudimentary and requires to come up with the settings manually. I have used this chip before in a different design and the sn65dsi8x driver allows set it up using display timings. However that platform uses a DRM based video system. The TX2 doesn’t use DRM (yet) so I hacked the driver to be also usefull without DRM (added a no-drm-connect option). I’ve attached a patch to add this driver to the Tegra 32.2.1 kernel drivers. The driver should still work with DRM based video systems; there is nothing system specific in it.

The DTS tree to drive two panels looks like this:

i2c@3160000 {

	sn65dsi84_1: sn65dsi84@2c {
		compatible = "ti,sn65dsi83";
		reg = <0x2c>;
		ti,dsi-lanes = <4>;
		ti,lvds-format = <0>;
		ti,lvds-bpp = <24>;
		ti,width-mm = <220>;
		ti,height-mm = <180>;
		ti,lvds-channels = <1>;
		ti,always-on=<1>;
		ti,no-drm-connect=<1>;
		ti,reverse-lvds=<0>;
		
		enable-gpios = <&tegra_aon_gpio TEGRA_AON_GPIO(U, 3) GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		dsi-lanes = <4>;
		panel-width-mm = <220>;
		panel-height-mm = <180>;
		

	    display-timings {
	    
			timing {
				clock-frequency = <40000000>;
				hactive = <800>;
				vactive = <600>;
				hfront-porch = <220>;
				hback-porch = <38>;
				vfront-porch = <24>;
				vback-porch = <4>;
				hsync-len = <13>;
				vsync-len = <2>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
	     	};
		};


		port {
			panel1_in: endpoint {
			remote-endpoint = <&mipi_dsi_bridge_out>;
			};
		};

	};

	sn65dsi84_2: sn65dsi84@2d {
		compatible = "ti,sn65dsi83";
		reg = <0x2d>;				/* I2C address* */
		ti,dsi-lanes = <4>;
		ti,lvds-format = <0>;		/* 0= NS, 1=JEIDA */
		ti,lvds-bpp = <24>;
		ti,width-mm = <220>;
		ti,height-mm = <180>;
		ti,lvds-channels = <1>;		/* 1=1 channel, 2=2 channels  (4 lanes per channel). */
		ti,always-on=<1>;			/* Power up immediately and don't power down*/
		ti,no-drm-connect=<1>;		/* Start directly from probe function, use if the system doesn't use DRM */
		ti,reverse-lvds=<1>;		/* 0=normal, 1=reverse lanes and channels (mirrored PCB layout) */
		ti,burst-mode= <0>;			/* 0= SYNC PULSE, 1= BURST. Only for DRM mode */
		
		
		enable-gpios = <&tegra_aon_gpio TEGRA_AON_GPIO(U, 3) GPIO_ACTIVE_HIGH>;		/*panel power control */
		enable-panel = <>;		/* panel enable control */
		pinctrl-names = "default";
		dsi-lanes = <4>;
		panel-width-mm = <220>;
		panel-height-mm = <180>;
		

	    display-timings {
	    
	    	/* 800x600 @60Hz */
			timing {
				clock-frequency = <40000000>;
				hactive = <800>;
				vactive = <600>;
				hfront-porch = <220>;
				hback-porch = <38>;
				vfront-porch = <24>;
				vback-porch = <4>;
				hsync-len = <13>;
				vsync-len = <2>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
	     	};
		};


		port {
			panel2_in: endpoint {
			remote-endpoint = <&mipi_dsi_bridge_out>;
			};
		};

	};
};

/* Dummy node to fullfill the requirement to have an endpoint for the sn65dsi83 driver*/
mipi_dsi_bridge {
status = “okay”;
clock-drop-level = <1>;

port@1 {
	mipi_dsi_bridge_out: endpoint {
		remote-endpoint = <&panel_lvds1>;
	};
};

};

sn65dsi83 driver.patch.txt (32.0 KB)

1 Like

Hi @nico4ocqz

it seems that the patch you attached does not actually contain any handling for the “no-drm-connect” property that you mention and added in the dts. Would you mind sharing the changes you did for this?

That is odd… I have attached the current versions to this reply which also does some checks on whether the DSI link stays up. It seems the DSI link may not always initialise correctly or can lose sync later on. If that happens the system will be reset.
sn65dsi83_brg.c (14.2 KB)
sn65dsi83_brg.h (1.9 KB)
sn65dsi83_drv.c (16.8 KB)
sn65dsi83_timing.h (1.0 KB)

Thanks @nico4ocqz for sharing your patches.
We’re seeing issues with clock not getting a stable PLL lock here. Looking at the SN65DSI83 datasheet it seems that it expects to have a BIAS of >=70mV applied to the DSI signals, which the Jetson Nano’s DSI output does not have. So we suspect this is the problem currently.
Do you have faced something similar?

The problem I’m seeing that in rare cases one of the DSI lanes doesn’t come up properly so the SN65DSI83 can’t synchronise to it (which is detected by the driver I wrote and the system is reset). This is however for a ganged display with a total of 16 LVDS lanes. I have played with various DSI settings in the devicetree file. These seem to work best for the project I’m working on. I copied and pasted the devicetree part for a non-ganged display assuming that is what you are working with:

		    nvidia,dsi-instance = <0>;
		    nvidia,dsi-n-data-lanes = <4>;
		    nvidia,dsi-pixel-format = <3>;		/* 24 bit planar*/
		    nvidia,dsi-refresh-rate = <60>;
		    nvidia,dsi-video-data-type = <0>;
		    nvidia,dsi-video-clock-mode = <0>;
		    nvidia,dsi-video-burst-mode = <1>;
		    nvidia,dsi-ganged-type = <0>;		/* 0= not used, 1=left/right, 2=odd/even 3=overlapped ?*/
		    nvidia,dsi-split-link-type= <0>;	/* split link, 1=A/B 4= links A/C )
		    nvidia,dsi-ganged-swap-links = <0>;
		    nvidia,dsi-ganged-write-to-all-links = <0>;
		    nvidia,dsi-controller-vs = <1>;
		    nvidia,dsi-virtual-channel = <0>;
		    nvidia,dsi-panel-reset = <1>;
		    nvidia,panel-bl-pwm-gpio = <&tegra_aon_gpio TEGRA_AON_GPIO(U, 0) 1>; /* PU0 */
		    nvidia,dsi-ulpm-not-support = <1>;
		    nvidia,dsi-suspend-stop-stream-late = <1>;
		    nvidia,dsi-power-saving-suspend = <1>;
		    nvidia,default_color_space = <1>;
			nvidia,dsi-pkt-seq =
				 <CMD_VS LEN_SHORT CMD_BLNK LEN_HSYNC CMD_HE LEN_SHORT PKT_LP LINE_STOP>,
				 <CMD_VE LEN_SHORT CMD_BLNK LEN_HSYNC CMD_HE LEN_SHORT PKT_LP LINE_STOP>,
				 <CMD_HS LEN_SHORT CMD_BLNK LEN_HSYNC CMD_HE LEN_SHORT PKT_LP LINE_STOP>,
				 <CMD_HS LEN_SHORT CMD_BLNK LEN_HSYNC CMD_HE LEN_SHORT CMD_BLNK LEN_HBP CMD_RGB_24BPP LEN_HACTIVE3 CMD_BLNK LEN_HFP LINE_STOP>,
				 <CMD_HS LEN_SHORT CMD_BLNK LEN_HSYNC CMD_HE LEN_SHORT PKT_LP LINE_STOP>,
				 <CMD_HS LEN_SHORT CMD_BLNK LEN_HSYNC CMD_HE LEN_SHORT CMD_BLNK LEN_HBP CMD_RGB_24BPP LEN_HACTIVE3 CMD_BLNK LEN_HFP LINE_STOP>;
1 Like