This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SN65DSI83: IMX8M MINI EVK LVDS DISPLAY INTEGRATION

Part Number: SN65DSI83
Other Parts Discussed in Thread: SN65DSI84

Hi Sir/Madam,

                        I'm working on NXP IMX8M MINI EVK board on LINUX environment. We are working on the PANASYS LVDS display which is an custom display, for converting the MIPI-DSI data lines to LVDS data we are using SN65DSI83 as an bridge converter. We added the drivers with parameters for the bridge at the location (drivers/gpu/drm/bridge/sn65dsi83) and added the display parameters in the imx8mm-evk.dts file at the location (arch/arm64/boot/dts/Freescale). After adding the bridge driver and the dts file we are unable to see any display on the evk. Here I'm sharing the boot log and the dts file along with the patch.

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright 2019 NXP
 */

/dts-v1/;

#include <dt-bindings/usb/pd.h>
#include "imx8mm.dtsi"

/ {
	model = "FSL i.MX8MM EVK board";
	compatible = "fsl,imx8mm-evk", "fsl,imx8mm";

	reserved-memory {
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;

		rpmsg_reserved: rpmsg@0xb8000000 {
			no-map;
			reg = <0 0xb8000000 0 0x400000>;
		};
	};

	chosen {
		stdout-path = &uart2;
	};

	leds {
		compatible = "gpio-leds";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_gpio_led>;

		status {
			label = "status";
			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
			default-state = "on";
		};
	};

	modem_reset: modem-reset {
		compatible = "gpio-reset";
		reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
		reset-delay-us = <2000>;
		reset-post-delay-ms = <40>;
		#reset-cells = <0>;
	};

	ir_recv: ir-receiver {
		compatible = "gpio-ir-receiver";
		gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_ir_recv>;
	};

	pcie0_refclk: pcie0-refclk {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <100000000>;
	};

	reg_sd1_vmmc: sd1_regulator {
		compatible = "regulator-fixed";
		regulator-name = "WLAN_EN";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		gpio = <&gpio2 10 GPIO_ACTIVE_HIGH>;
		off-on-delay-us = <20000>;
		startup-delay-us = <100>;
		enable-active-high;
	};

	reg_usdhc2_vmmc: regulator-usdhc2 {
		compatible = "regulator-fixed";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
		regulator-name = "VSD_3V3";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
		off-on-delay-us = <20000>;
		enable-active-high;
	};

	reg_audio_board: regulator-audio-board {
		compatible = "regulator-fixed";
		regulator-name = "EXT_PWREN";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		enable-active-high;
		startup-delay-us = <300000>;
		gpio = <&pca6416 1 GPIO_ACTIVE_HIGH>;
	};

	wm8524: audio-codec {
		#sound-dai-cells = <0>;
		compatible = "wlf,wm8524";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_gpio_wlf>;
		wlf,mute-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
	};

	bt_sco_codec: bt_sco_codec {
		#sound-dai-cells = <0>;
		compatible = "linux,bt-sco";
	};

	sound-bt-sco {
		compatible = "simple-audio-card";
		simple-audio-card,name = "bt-sco-audio";
		simple-audio-card,format = "i2s";
		simple-audio-card,bitclock-inversion;
		simple-audio-card,frame-master = <&btcpu>;
		simple-audio-card,bitclock-master = <&btcpu>;

		btcpu: simple-audio-card,cpu {
			sound-dai = <&sai2>;
			dai-tdm-slot-num = <2>;
			dai-tdm-slot-width = <16>;
		};

		simple-audio-card,codec {
			sound-dai = <&bt_sco_codec>;
		};
	};

	sound-wm8524 {
		compatible = "simple-audio-card";
		simple-audio-card,name = "wm8524-audio";
		simple-audio-card,format = "i2s";
		simple-audio-card,frame-master = <&cpudai>;
		simple-audio-card,bitclock-master = <&cpudai>;
		simple-audio-card,widgets =
			"Line", "Left Line Out Jack",
			"Line", "Right Line Out Jack";
		simple-audio-card,routing =
			"Left Line Out Jack", "LINEVOUTL",
			"Right Line Out Jack", "LINEVOUTR";

		cpudai: simple-audio-card,cpu {
			sound-dai = <&sai3>;
			dai-tdm-slot-num = <2>;
			dai-tdm-slot-width = <32>;
		};

		simple-audio-card,codec {
			sound-dai = <&wm8524>;
			clocks = <&clk IMX8MM_CLK_SAI3_ROOT>;
		};
	};

	sound-ak4458 {
		compatible = "fsl,imx-audio-ak4458";
		model = "ak4458-audio";
		audio-cpu = <&sai1>;
		audio-codec = <&ak4458_1>, <&ak4458_2>;
		ak4458,pdn-gpio = <&pca6416 4 GPIO_ACTIVE_HIGH>;
	};

	sound-ak5558 {
		compatible = "fsl,imx-audio-ak5558";
		model = "ak5558-audio";
		audio-cpu = <&sai5>;
		audio-codec = <&ak5558>;
		status = "disabled";
	};

	sound-ak4497 {
		compatible = "fsl,imx-audio-ak4497";
		model = "ak4497-audio";
		audio-cpu = <&sai1>;
		audio-codec = <&ak4497>;
		status = "disabled";
	};

	sound-spdif {
		compatible = "fsl,imx-audio-spdif";
		model = "imx-spdif";
		spdif-controller = <&spdif1>;
		spdif-out;
		spdif-in;
	};

	sound-micfil {
		compatible = "fsl,imx-audio-micfil";
		model = "imx-audio-micfil";
		cpu-dai = <&micfil>;
	};
};

&A53_0 {
	cpu-supply = <&buck2_reg>;
};

&csi1_bridge {
	fsl,mipi-mode;
	status = "okay";
	port {
		csi1_ep: endpoint {
			remote-endpoint = <&csi1_mipi_ep>;
		};
	};
};

&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_fec1>;
	phy-mode = "rgmii-id";
	phy-handle = <&ethphy0>;
	fsl,magic-packet;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@0 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <0>;
			at803x,eee-disabled;
			at803x,vddio-1p8v;
		};
	};
};

&pcie0{
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pcie0>;
	disable-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>;
	reset-gpio = <&gpio4 21 GPIO_ACTIVE_LOW>;
	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>,
		 <&clk IMX8MM_CLK_PCIE1_AUX>,
		 <&clk IMX8MM_CLK_PCIE1_PHY>,
		 <&pcie0_refclk>;
	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
	ext_osc = <1>;
	reserved-region = <&rpmsg_reserved>;
	status = "okay";
};

&pcie0_ep{
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pcie0>;
	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>,
		 <&clk IMX8MM_CLK_PCIE1_AUX>,
		 <&clk IMX8MM_CLK_PCIE1_PHY>,
		 <&pcie0_refclk>;
	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
	ext_osc = <1>;
	status = "disabled";
};

&sai3 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sai3>;
	assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <24576000>;
	status = "okay";
};

&sai2 {
	#sound-dai-cells = <0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sai2>;
	assigned-clocks = <&clk IMX8MM_CLK_SAI2>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <24576000>;
	status = "okay";
};

&sai1 {
	pinctrl-names = "default", "dsd";
	pinctrl-0 = <&pinctrl_sai1>;
	pinctrl-1 = <&pinctrl_sai1_dsd>;
	assigned-clocks = <&clk IMX8MM_CLK_SAI1>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <49152000>;
	clocks = <&clk IMX8MM_CLK_SAI1_IPG>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_SAI1_ROOT>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_AUDIO_PLL1_OUT>,
		<&clk IMX8MM_AUDIO_PLL2_OUT>;
	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
	fsl,sai-multi-lane;
	fsl,dataline,dsd = <0 0xff 0xff 2 0xff 0x11>;
	dmas = <&sdma2 0 25 0>, <&sdma2 1 25 0>;
	status = "okay";
};

&sai5 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sai5>;
	assigned-clocks = <&clk IMX8MM_CLK_SAI5>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <49152000>;
	clocks = <&clk IMX8MM_CLK_SAI5_IPG>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_SAI5_ROOT>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_AUDIO_PLL1_OUT>,
		<&clk IMX8MM_AUDIO_PLL2_OUT>;
	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
	fsl,sai-asynchronous;
	status = "disabled";
};

&sai6 {
	fsl,sai-monitor-spdif;
	fsl,sai-asynchronous;
	status = "okay";
};

&spdif1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_spdif1>;
	assigned-clocks = <&clk IMX8MM_CLK_SPDIF1>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <24576000>;
	clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_24M>,
		<&clk IMX8MM_CLK_SPDIF1>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_AUDIO_PLL1_OUT>, <&clk IMX8MM_AUDIO_PLL2_OUT>;
	clock-names = "core", "rxtx0", "rxtx1", "rxtx2", "rxtx3",
		"rxtx4", "rxtx5", "rxtx6", "rxtx7", "spba", "pll8k", "pll11k";
	status = "okay";
};

&micfil {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pdm>;
	assigned-clocks = <&clk IMX8MM_CLK_PDM>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <196608000>;
	status = "okay";
};

&snvs_pwrkey {
	status = "okay";
};

&uart1 { /* BT */
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1>;
	assigned-clocks = <&clk IMX8MM_CLK_UART1>;
	assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
	fsl,uart-has-rtscts;
	resets = <&modem_reset>;
	status = "okay";
};

&uart2 { /* console */
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart2>;
	status = "okay";
};

&uart3 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart3>;
	assigned-clocks = <&clk IMX8MM_CLK_UART3>;
	assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
	fsl,uart-has-rtscts;
	status = "okay";
};

&usbotg1 {
	dr_mode = "otg";
	hnp-disable;
	srp-disable;
	adp-disable;
	usb-role-switch;
	picophy,pre-emp-curr-control = <3>;
	picophy,dc-vol-level-adjust = <7>;
	status = "okay";

	port {
		usb1_drd_sw: endpoint {
			remote-endpoint = <&typec1_dr_sw>;
		};
	};
};

&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>;
	pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_usdhc1_gpio>;
	pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_usdhc1_gpio>;
	bus-width = <4>;
	vmmc-supply = <&reg_sd1_vmmc>;
	pm-ignore-notify;
	keep-power-in-suspend;
	non-removable;
	status = "okay";
};

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
	cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
	bus-width = <4>;
	vmmc-supply = <&reg_usdhc2_vmmc>;
	status = "okay";
};

&usdhc3 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc3>;
	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
	bus-width = <8>;
	non-removable;
	status = "okay";
};

&wdog1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_wdog>;
	fsl,ext-reset-output;
	status = "okay";
};

&flexspi {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_flexspi0>;
	status = "okay";

	flash0: mt25qu256aba@0 {
		reg = <0>;
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "jedec,spi-nor";
		spi-max-frequency = <80000000>;
		spi-tx-bus-width = <4>;
		spi-rx-bus-width = <4>;
	};
};

&i2c1 {
	clock-frequency = <400000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	pmic@4b {
		compatible = "rohm,bd71847";
		reg = <0x4b>;
		pinctrl-0 = <&pinctrl_pmic>;
		interrupt-parent = <&gpio1>;
		interrupts = <3 GPIO_ACTIVE_LOW>;
		rohm,reset-snvs-powered;

		regulators {
			buck1_reg: BUCK1 {
				regulator-name = "BUCK1";
				regulator-min-microvolt = <700000>;
				regulator-max-microvolt = <1300000>;
				regulator-boot-on;
				regulator-always-on;
				regulator-ramp-delay = <1250>;
			};

			buck2_reg: BUCK2 {
				regulator-name = "BUCK2";
				regulator-min-microvolt = <700000>;
				regulator-max-microvolt = <1300000>;
				regulator-boot-on;
				regulator-always-on;
				regulator-ramp-delay = <1250>;
				rohm,dvs-run-voltage = <1000000>;
				rohm,dvs-idle-voltage = <900000>;
			};

			buck3_reg: BUCK3 {
				// BUCK5 in datasheet
				regulator-name = "BUCK3";
				regulator-min-microvolt = <700000>;
				regulator-max-microvolt = <1350000>;
				regulator-boot-on;
				regulator-always-on;
			};

			buck4_reg: BUCK4 {
				// BUCK6 in datasheet
				regulator-name = "BUCK4";
				regulator-min-microvolt = <3000000>;
				regulator-max-microvolt = <3300000>;
				regulator-boot-on;
				regulator-always-on;
			};

			buck5_reg: BUCK5 {
				// BUCK7 in datasheet
				regulator-name = "BUCK5";
				regulator-min-microvolt = <1605000>;
				regulator-max-microvolt = <1995000>;
				regulator-boot-on;
				regulator-always-on;
			};

			buck6_reg: BUCK6 {
				// BUCK8 in datasheet
				regulator-name = "BUCK6";
				regulator-min-microvolt = <800000>;
				regulator-max-microvolt = <1400000>;
				regulator-boot-on;
				regulator-always-on;
			};

			ldo1_reg: LDO1 {
				regulator-name = "LDO1";
				regulator-min-microvolt = <1600000>;
				regulator-max-microvolt = <1900000>;
				regulator-boot-on;
				regulator-always-on;
			};

			ldo2_reg: LDO2 {
				regulator-name = "LDO2";
				regulator-min-microvolt = <800000>;
				regulator-max-microvolt = <900000>;
				regulator-boot-on;
				regulator-always-on;
			};

			ldo3_reg: LDO3 {
				regulator-name = "LDO3";
				regulator-min-microvolt = <1800000>;
				regulator-max-microvolt = <3300000>;
				regulator-boot-on;
				regulator-always-on;
			};

			ldo4_reg: LDO4 {
				regulator-name = "LDO4";
				regulator-min-microvolt = <900000>;
				regulator-max-microvolt = <1800000>;
				regulator-boot-on;
				regulator-always-on;
			};

			ldo6_reg: LDO6 {
				regulator-name = "LDO6";
				regulator-min-microvolt = <900000>;
				regulator-max-microvolt = <1800000>;
				regulator-boot-on;
				regulator-always-on;
			};
		};
	};
};

&i2c2 {
	clock-frequency = <400000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>;
	status = "okay";

	dsi_lvds_bridge: sn65dsi84@2c {
		compatible = "ti,sn65dsi83";
		reg = <0x2c>;
		ti,dsi-lanes = <4>;
		ti,lvds-format = <1>;
		ti,lvds-bpp = <24>;
		ti,width-mm = <217>;
		ti,height-mm = <136>;
		enable-gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>;
		interrupt-parent = <&gpio3>;
		interrupts = <6 IRQ_TYPE_LEVEL_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_lvds>;
		status = "okay";

		display-timings {
			native-mode = <&lvds0_g101evn010>;

			/* AUO G101EVN01.0 */
			lvds0_g101evn010: timing@0 {
				clock-frequency = <69000000>;
				hactive = <1280>;
				vactive = <800>;
				hfront-porch = <120>;
				hback-porch = <1>;
				hsync-len = <8>;
				vback-porch = <10>;
				vfront-porch = <1>;
				vsync-len = <6>;
				hsync-active = <1>;
				vsync-active = <1>;
				de-active = <1>;
				pixelclk-active = <0>;
			};

			/* Fusion 10" F10A-0102 */
			lvds0_hsd101pfw2: timing@1 {
				clock-frequency = <45000000>;
				hactive = <1024>;
				vactive = <600>;
				hfront-porch = <120>;
				hback-porch = <1>;
				hsync-len = <8>;
				vback-porch = <10>;
				vfront-porch = <1>;
				vsync-len = <6>;
				hsync-active = <1>;
				vsync-active = <1>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
		};

		port {
			dsi_lvds_bridge_in: endpoint {
				remote-endpoint = <&mipi_dsi_lvds_out>;
			};
	};

	adv_bridge: adv7535@3d {
		compatible = "adi,adv7533";
		reg = <0x3d>;
		adi,addr-cec = <0x3b>;
		adi,dsi-lanes = <4>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_i2c2_synaptics_dsx_io>;
		interrupt-parent = <&gpio1>;
		interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
		status = "disable";

		port {
			adv7535_from_dsim: endpoint {
				remote-endpoint = <&dsim_to_adv7535>;
			};
		};
	};

	ptn5110: tcpc@50 {
		compatible = "nxp,ptn5110";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_typec1>;
		reg = <0x50>;
		interrupt-parent = <&gpio2>;
		interrupts = <11 8>;
		status = "okay";

		port {
			typec1_dr_sw: endpoint {
				remote-endpoint = <&usb1_drd_sw>;
			};
		};

		typec1_con: connector {
			compatible = "usb-c-connector";
			label = "USB-C";
			power-role = "dual";
			data-role = "dual";
			try-power-role = "sink";
			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
				     PDO_VAR(5000, 20000, 3000)>;
			op-sink-microwatt = <15000000>;
			self-powered;
		};
	};
};

&i2c3 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c3>;
	status = "okay";

	pca6416: gpio@20 {
		compatible = "ti,tca6416";
		reg = <0x20>;
		gpio-controller;
		#gpio-cells = <2>;
		vcc-supply = <&buck4_reg>;
	};

	ak4458_1: ak4458@10 {
		compatible = "asahi-kasei,ak4458";
		reg = <0x10>;
		AVDD-supply = <&reg_audio_board>;
		DVDD-supply = <&reg_audio_board>;
	};

	ak4458_2: ak4458@12 {
		compatible = "asahi-kasei,ak4458";
		reg = <0x12>;
		AVDD-supply = <&reg_audio_board>;
		DVDD-supply = <&reg_audio_board>;
	};

	ak5558: ak5558@13 {
		compatible = "asahi-kasei,ak5558";
		reg = <0x13>;
		ak5558,pdn-gpio = <&pca6416 3 GPIO_ACTIVE_HIGH>;
		AVDD-supply = <&reg_audio_board>;
		DVDD-supply = <&reg_audio_board>;
	};

	ak4497: ak4497@11 {
		compatible = "asahi-kasei,ak4497";
		reg = <0x11>;
		ak4497,pdn-gpio = <&pca6416 5 GPIO_ACTIVE_HIGH>;
		AVDD-supply = <&reg_audio_board>;
		DVDD-supply = <&reg_audio_board>;
	};

	ov5640_mipi: ov5640_mipi@3c {
		compatible = "ovti,ov5640_mipi";
		reg = <0x3c>;
		status = "okay";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_csi_pwn>, <&pinctrl_csi_rst>;
		clocks = <&clk IMX8MM_CLK_CLKO1>;
		clock-names = "csi_mclk";
		assigned-clocks = <&clk IMX8MM_CLK_CLKO1>;
		assigned-clock-parents = <&clk IMX8MM_CLK_24M>;
		assigned-clock-rates = <24000000>;
		csi_id = <0>;
		pwn-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
		mclk = <24000000>;
		mclk_source = <0>;
		port {
			ov5640_mipi1_ep: endpoint {
				remote-endpoint = <&mipi1_sensor_ep>;
			};
		};
	};
};

&iomuxc {
	pinctrl-names = "default";

	pinctrl_csi_pwn: csi_pwn_grp {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7		0x19
		>;
	};

	pinctrl_csi_rst: csi_rst_grp {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6		0x19
			MX8MM_IOMUXC_GPIO1_IO14_CCMSRCGPCMIX_CLKO1	0x59
		>;
	};

	pinctrl_ir_recv: ir-recv {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13		0x4f
		>;
	};

	pinctrl_fec1: fec1grp {
		fsl,pins = <
			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
			MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22		0x19
		>;
	};

	pinctrl_flexspi0: flexspi0grp {
		fsl,pins = <
			MX8MM_IOMUXC_NAND_ALE_QSPI_A_SCLK               0x1c2
			MX8MM_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B            0x82
			MX8MM_IOMUXC_NAND_DATA00_QSPI_A_DATA0           0x82
			MX8MM_IOMUXC_NAND_DATA01_QSPI_A_DATA1           0x82
			MX8MM_IOMUXC_NAND_DATA02_QSPI_A_DATA2           0x82
			MX8MM_IOMUXC_NAND_DATA03_QSPI_A_DATA3           0x82
		>;
	};

	pinctrl_gpio_led: gpioledgrp {
		fsl,pins = <
			MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16	0x19
		>;
	};
	
	pinctrl_lvds: lvdsgrp {
		fsl,pins = <
			/* SN65DSI83 enable */
			MX8MM_IOMUXC_NAND_ALE_GPIO3_IO0		0x19
			/* SN65DSI83 interrupt */
			MX8MM_IOMUXC_NAND_DATA00_GPIO3_IO6	0x19
		>;
	};

	pinctrl_gpio_wlf: gpiowlfgrp {
		fsl,pins = <
			MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21	0xd6
		>;
	};

	pinctrl_i2c1: i2c1grp {
		fsl,pins = <
			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
		>;
	};

	pinctrl_i2c2: i2c2grp {
		fsl,pins = <
			MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL			0x400001c3
			MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA			0x400001c3
		>;
	};

	pinctrl_i2c3: i2c3grp {
		fsl,pins = <
			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL			0x400001c3
			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA			0x400001c3
		>;
	};

	pinctrl_mipi_dsi_en: mipi_dsi_en {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8		0x16
		>;
	};

	pinctrl_i2c2_synaptics_dsx_io: synaptics_dsx_iogrp {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9               0x19    /* Touch int */
		>;
	};

	pinctrl_pcie0: pcie0grp {
		fsl,pins = <
			MX8MM_IOMUXC_I2C4_SCL_PCIE1_CLKREQ_B	0x61 /* open drain, pull up */
			MX8MM_IOMUXC_GPIO1_IO05_GPIO1_IO5	0x41
			MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21	0x41
		>;
	};

	pinctrl_pmic: pmicirq {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x41
		>;
	};

	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
		fsl,pins = <
			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
		>;
	};

	pinctrl_sai2: sai2grp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI2_TXC_SAI2_TX_BCLK      0xd6
			MX8MM_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC     0xd6
			MX8MM_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0    0xd6
			MX8MM_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0    0xd6
		>;
	};

	pinctrl_sai3: sai3grp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
			MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
			MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK        0xd6
			MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6
		>;
	};

	pinctrl_sai1: sai1grp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI1_MCLK_SAI1_MCLK	0xd6
			MX8MM_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC	0xd6
			MX8MM_IOMUXC_SAI1_RXD7_SAI1_TX_SYNC	0xd6
			MX8MM_IOMUXC_SAI1_TXC_SAI1_TX_BCLK	0xd6
			MX8MM_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0	0xd6
			MX8MM_IOMUXC_SAI1_TXD1_SAI1_TX_DATA1	0xd6
			MX8MM_IOMUXC_SAI1_TXD2_SAI1_TX_DATA2	0xd6
			MX8MM_IOMUXC_SAI1_TXD3_SAI1_TX_DATA3	0xd6
			MX8MM_IOMUXC_SAI1_TXD4_SAI1_TX_DATA4	0xd6
			MX8MM_IOMUXC_SAI1_TXD5_SAI1_TX_DATA5	0xd6
			MX8MM_IOMUXC_SAI1_TXD6_SAI1_TX_DATA6	0xd6
			MX8MM_IOMUXC_SAI1_TXD7_SAI1_TX_DATA7	0xd6
		>;
	};

	pinctrl_sai1_dsd: sai1grp_dsd {
		fsl,pins = <
			MX8MM_IOMUXC_SAI1_MCLK_SAI1_MCLK	0xd6
			MX8MM_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC	0xd6
			MX8MM_IOMUXC_SAI1_RXD7_SAI1_TX_DATA4	0xd6
			MX8MM_IOMUXC_SAI1_TXC_SAI1_TX_BCLK	0xd6
			MX8MM_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0	0xd6
			MX8MM_IOMUXC_SAI1_TXD1_SAI1_TX_DATA1	0xd6
			MX8MM_IOMUXC_SAI1_TXD2_SAI1_TX_DATA2	0xd6
			MX8MM_IOMUXC_SAI1_TXD3_SAI1_TX_DATA3	0xd6
			MX8MM_IOMUXC_SAI1_TXD4_SAI1_TX_DATA4	0xd6
			MX8MM_IOMUXC_SAI1_TXD5_SAI1_TX_DATA5	0xd6
			MX8MM_IOMUXC_SAI1_TXD6_SAI1_TX_DATA6	0xd6
			MX8MM_IOMUXC_SAI1_TXD7_SAI1_TX_DATA7	0xd6
		>;
	};

	pinctrl_sai5: sai5grp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI5_MCLK_SAI5_MCLK	0xd6
			MX8MM_IOMUXC_SAI5_RXC_SAI5_RX_BCLK	0xd6
			MX8MM_IOMUXC_SAI5_RXFS_SAI5_RX_SYNC	0xd6
			MX8MM_IOMUXC_SAI5_RXD0_SAI5_RX_DATA0	0xd6
			MX8MM_IOMUXC_SAI5_RXD1_SAI5_RX_DATA1    0xd6
			MX8MM_IOMUXC_SAI5_RXD2_SAI5_RX_DATA2    0xd6
			MX8MM_IOMUXC_SAI5_RXD3_SAI5_RX_DATA3    0xd6
		>;
	};

	pinctrl_pdm: pdmgrp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI5_MCLK_SAI5_MCLK	0xd6
			MX8MM_IOMUXC_SAI5_RXC_PDM_CLK		0xd6
			MX8MM_IOMUXC_SAI5_RXFS_SAI5_RX_SYNC	0xd6
			MX8MM_IOMUXC_SAI5_RXD0_PDM_DATA0	0xd6
			MX8MM_IOMUXC_SAI5_RXD1_PDM_DATA1	0xd6
			MX8MM_IOMUXC_SAI5_RXD2_PDM_DATA2	0xd6
			MX8MM_IOMUXC_SAI5_RXD3_PDM_DATA3	0xd6
		>;
	};

	pinctrl_spdif1: spdif1grp {
		fsl,pins = <
			MX8MM_IOMUXC_SPDIF_TX_SPDIF1_OUT	0xd6
			MX8MM_IOMUXC_SPDIF_RX_SPDIF1_IN		0xd6
		>;
	};

	pinctrl_typec1: typec1grp {
		fsl,pins = <
			MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11	0x159
		>;
	};

	pinctrl_uart1: uart1grp {
		fsl,pins = <
			MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
			MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
			MX8MM_IOMUXC_UART3_RXD_UART1_DCE_CTS_B	0x140
			MX8MM_IOMUXC_UART3_TXD_UART1_DCE_RTS_B	0x140
			MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6	0x19
		>;
	};

	pinctrl_uart2: uart2grp {
		fsl,pins = <
			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
		>;
	};

	pinctrl_uart3: uart3grp {
		fsl,pins = <
			MX8MM_IOMUXC_ECSPI1_SCLK_UART3_DCE_RX		0x140
			MX8MM_IOMUXC_ECSPI1_MOSI_UART3_DCE_TX		0x140
			MX8MM_IOMUXC_ECSPI1_SS0_UART3_DCE_RTS_B		0x140
			MX8MM_IOMUXC_ECSPI1_MISO_UART3_DCE_CTS_B	0x140
		>;
	};

	pinctrl_usdhc1_gpio: usdhc1grpgpio {
		fsl,pins = <
			MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10	0x41
		>;
	};

	pinctrl_usdhc1: usdhc1grp {
		fsl,pins = <
			MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK		0x190
			MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD		0x1d0
			MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0	0x1d0
			MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1	0x1d0
			MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2	0x1d0
			MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3	0x1d0
		>;
	};

	pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
		fsl,pins = <
			MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK		0x194
			MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD		0x1d4
			MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0	0x1d4
			MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1	0x1d4
			MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2	0x1d4
			MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3	0x1d4
		>;
	};

	pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
		fsl,pins = <
			MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK		0x196
			MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD		0x1d6
			MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0	0x1d6
			MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1	0x1d6
			MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2	0x1d6
			MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3	0x1d6
		>;
	};

	pinctrl_usdhc2_gpio: usdhc2grpgpio {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x1c4
		>;
	};

	pinctrl_usdhc2: usdhc2grp {
		fsl,pins = <
			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
		>;
	};

	pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
		fsl,pins = <
			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
		>;
	};

	pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
		fsl,pins = <
			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
		>;
	};

	pinctrl_usdhc3: usdhc3grp {
		fsl,pins = <
			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x190
			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x190
		>;
	};

	pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
		fsl,pins = <
			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x194
			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x194
		>;
	};

	pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
		fsl,pins = <
			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x196
			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x196
		>;
	};


	lvds_backlight: lvds_backlight {
 		compatible = "pwm-backlight";
 		pwms = <&pwm1 0 100000 0>;
 		brightness-levels =
 		    < 0	 15
 			 23
 			 31
 			 39
 			 47
 			 55
 			 63
 			 71
 			 79
 			 87
 			 95
 			103
 			111
 			119
 			127
 			135
 			143
 			151
 			159
 			167
 			175
 			183
 			191
 			199
 			207
 			215
 			223
 			231
 			239
 			247
 			255>;
 		default-brightness-level = <127>; // 125
 	};

	pinctrl_pwm1: pwmgrp {
 		fsl,pins = <
 				MX8MM_IOMUXC_GPIO1_IO01_PWM1_OUT 0x16
 			>;
 		};
 
	pinctrl_wdog: wdoggrp {
		fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0xc6
		>;
	};
};

&lcdif {
	status = "okay";
};

&mipi_csi_1 {
	#address-cells = <1>;
	#size-cells = <0>;
	status = "okay";
	port {
		mipi1_sensor_ep: endpoint@1 {
			remote-endpoint = <&ov5640_mipi1_ep>;
			data-lanes = <2>;
			csis-hs-settle = <13>;
			csis-clk-settle = <2>;
			csis-wclk;
		};

		csi1_mipi_ep: endpoint@2 {
			remote-endpoint = <&csi1_ep>;
		};
	};
};

&mipi_dsi {
	status = "okay";

	port@1 {
		dsim_to_adv7535: endpoint {
			remote-endpoint = <&adv7535_from_dsim>;
			attach-bridge;
		};
	};

	port@2 {
		mipi_dsi_lvds_out: endpoint {
			remote-endpoint = <&dsi_lvds_bridge_in>;
		};
};

&vpu_g1 {
	status = "okay";
};

&vpu_g2 {
	status = "okay";
};

&vpu_h1 {
	status = "okay";
};

&gpu {
	status = "okay";
};

From e808b65935978dc0ca28777320c6c2defb8ad569 Mon Sep 17 00:00:00 2001
From: Matteo Lisi <matteo.lisi@engicam.com>
Date: Wed, 6 Feb 2019 15:35:17  0100
Subject: [PATCH 1/3] add sn65dsi83 driver and drm fix

---
 drivers/gpu/drm/Makefile                      |   2  -
 drivers/gpu/drm/bridge/Kconfig                |  16  
 drivers/gpu/drm/bridge/Makefile               |   3  
 drivers/gpu/drm/bridge/sec-dsim.c             |   4  -
 drivers/gpu/drm/bridge/sn65dsi83.c            | 666                   
 drivers/gpu/drm/bridge/sn65dsi83/Kconfig      |   7  
 drivers/gpu/drm/bridge/sn65dsi83/Makefile     |   2  
 .../gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c  | 400            
 .../gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h  |  55   
 .../gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c  | 433             
 .../drm/bridge/sn65dsi83/sn65dsi83_timing.h   |  33  
 drivers/gpu/drm/bridge/sn65dsi84-dsi2lvds.c   | 210       
 drivers/gpu/drm/drm_modes.c                   |   2  -
 drivers/gpu/drm/drm_notify.c                  |  43   
 include/drm/drmP.h                            |   4  
 15 files changed, 1876 insertions( ), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83.c
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/Makefile
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h
 create mode 100644 drivers/gpu/drm/bridge/sn65dsi84-dsi2lvds.c
 create mode 100644 drivers/gpu/drm/drm_notify.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index c5da7b5a5..02ab6dbd9 100644
--- a/drivers/gpu/drm/Makefile
    b/drivers/gpu/drm/Makefile
@@ -18,7  18,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_encoder.o drm_mode_object.o drm_property.o \
 		drm_plane.o drm_color_mgmt.o drm_print.o \
 		drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
-		drm_syncobj.o drm_lease.o
 		drm_syncobj.o drm_lease.o drm_notify.o
 
 drm-$(CONFIG_DRM_LIB_RANDOM)  = lib/drm_random.o
 drm-$(CONFIG_DRM_VM)  = drm_vm.o
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 593e9a4e9..d711bf187 100644
--- a/drivers/gpu/drm/bridge/Kconfig
    b/drivers/gpu/drm/bridge/Kconfig
@@ -134,4  134,20 @@ config DRM_ITE_IT6263
 	---help---
 	  ITE IT6263 bridge chip driver.
 
 config DRM_TI_SN65DSI84
 	tristate "SN65DSI84 DSI to LVDS bridge (old)"
 	select REGMAP_I2C
 	select DRM_MIPI_DSI
 	---help---
 	  Support for the Texas Intruments SN65DSI84 bridge.
 
 config DRM_TI_SN65DSI83
 	tristate "SN65DSI83/4 DSI to LVDS bridge (suggested)"
 	select REGMAP_I2C
 	select DRM_MIPI_DSI
 	---help---
 	  Support for the Texas Intruments SN65DSI84 and SN65DSI83 bridges.
 
 source "drivers/gpu/drm/bridge/sn65dsi83/Kconfig"
 
 endmenu
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index d684dce13..a151c13d1 100644
--- a/drivers/gpu/drm/bridge/Makefile
    b/drivers/gpu/drm/bridge/Makefile
@@ -16,3  16,6 @@ obj-$(CONFIG_DRM_ITE_IT6263)  = it6263.o
 obj-$(CONFIG_DRM_NWL_DSI)  = nwl-dsi.o
 obj-$(CONFIG_DRM_SEC_MIPI_DSIM)  = sec-dsim.o
 obj-$(CONFIG_DRM_NXP_SEIKO_43WVFIG)  = nxp-seiko-43wvfig.o
 obj-$(CONFIG_DRM_TI_SN65DSI84)  = sn65dsi84-dsi2lvds.o
 obj-$(CONFIG_DRM_TI_SN65DSI83)  = sn65dsi83.o
 obj-$(CONFIG_DRM_I2C_SN65DSI83)  = sn65dsi83/
diff --git a/drivers/gpu/drm/bridge/sec-dsim.c b/drivers/gpu/drm/bridge/sec-dsim.c
index ea4966a5d..dd5dd3a76 100644
--- a/drivers/gpu/drm/bridge/sec-dsim.c
    b/drivers/gpu/drm/bridge/sec-dsim.c
@@ -469,14  469,14 @@ static int sec_mipi_dsim_host_attach(struct mipi_dsi_host *host,
 
 	if (dsim->channel)
 		return -EINVAL;
-
 /*
 	if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)		||
 	    !((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)	||
 	      (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))) {
 		dev_err(dev, "unsupported dsi mode\n");
 		return -EINVAL;
 	}
-
 */
 	if (dsi->format != MIPI_DSI_FMT_RGB888 &&
 	    dsi->format != MIPI_DSI_FMT_RGB565 &&
 	    dsi->format != MIPI_DSI_FMT_RGB666 &&
diff --git a/drivers/gpu/drm/bridge/sn65dsi83.c b/drivers/gpu/drm/bridge/sn65dsi83.c
new file mode 100644
index 000000000..789ae6404
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83.c
@@ -0,0  1,666 @@
 /*
  *  sn65dsi83.c - DVI output chip
  *
  *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <drm/drmP.h>
 #include <drm/drm_mode.h>
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <linux/of_gpio.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/hwmon.h>
 #include <linux/input-polldev.h>
 #include <linux/gpio.h>
 #include <linux/fb.h>
 #include <linux/kthread.h>
 #include <video/display_timing.h>
 #include <video/of_videomode.h>
 #include <video/videomode.h>
 
 /* register definitions according to the sn65dsi83 data sheet */
 #define SN_SOFT_RESET		0x09
 #define SN_CLK_SRC		0x0a
 #define SN_CLK_DIV		0x0b
 
 #define SN_PLL_EN		0x0d
 #define SN_DSI_LANES		0x10
 #define SN_DSI_EQ		0x11
 #define SN_DSI_CLK		0x12
 #define SN_FORMAT		0x18
 
 #define SN_LVDS_VOLTAGE		0x19
 #define SN_LVDS_TERM		0x1a
 #define SN_LVDS_CM_VOLTAGE	0x1b
 #define SN_HACTIVE_LOW		0x20
 #define SN_HACTIVE_HIGH		0x21
 #define SN_VACTIVE_LOW		0x24
 #define SN_VACTIVE_HIGH		0x25
 #define SN_SYNC_DELAY_LOW	0x28
 #define SN_SYNC_DELAY_HIGH	0x29
 #define SN_HSYNC_LOW		0x2c
 #define SN_HSYNC_HIGH		0x2d
 #define SN_VSYNC_LOW		0x30
 #define SN_VSYNC_HIGH		0x31
 #define SN_HBP			0x34
 #define SN_VBP			0x36
 #define SN_HFP			0x38
 #define SN_VFP			0x3a
 #define SN_TEST_PATTERN		0x3c
 #define SN_IRQ_EN		0xe0
 #define SN_IRQ_MASK		0xe1
 #define SN_IRQ_STAT		0xe5
 
 static const char *client_name = "sn65dsi83";
 
 static const unsigned char registers_to_show[] = {
 	SN_SOFT_RESET, 	SN_CLK_SRC, SN_CLK_DIV, SN_PLL_EN,
 	SN_DSI_LANES, SN_DSI_EQ, SN_DSI_CLK, SN_FORMAT,
 	SN_LVDS_VOLTAGE, SN_LVDS_TERM, SN_LVDS_CM_VOLTAGE,
 	0, SN_HACTIVE_LOW,
 	0, SN_VACTIVE_LOW,
 	0, SN_SYNC_DELAY_LOW,
 	0, SN_HSYNC_LOW,
 	0, SN_VSYNC_LOW,
 	SN_HBP, SN_VBP,
 	SN_HFP, SN_VFP,
 	SN_TEST_PATTERN,
 	SN_IRQ_EN, SN_IRQ_MASK, SN_IRQ_STAT,
 };
 
 struct sn65dsi83_priv
 {
 	struct i2c_client	*client;
 	struct device_node	*disp_node;
 	struct device_node	*disp_dsi;
 	struct gpio_desc	*gp_en;
 	struct clk		*mipi_clk;
 	struct notifier_block	fbnb;
 	struct notifier_block	drmnb;
 	u32			int_cnt;
 	u32			pixelclock;
 	u8			chip_enabled;
 	u8			show_reg;
 	u8			dsi_lanes;
 	u8			spwg;	/* lvds lane 3 has MSBs of color */
 	u8			jeida;	/* lvds lane 3 has LSBs of color */
 	u8			dsi_bpp;
 	u16			sync_delay;
 
 	u8			dsi_clk_divider;
 	u8			mipi_clk_index;
 };
 
 /**
  * sn_i2c_read_reg - read data from a register of the i2c slave device.
  *
  * @client: i2c device.
  * @reg: the register to read from.
  * @buf: raw write data buffer.
  * @len: length of the buffer to write
  */
 static int sn_i2c_read_byte(struct sn65dsi83_priv *sn, u8 reg)
 {
 	struct i2c_client *client = sn->client;
 	int ret = i2c_smbus_read_byte_data(client, reg);
 
 	if (ret < 0)
 		dev_err(&client->dev, "%s failed(%i)\n", __func__, ret);
 	return ret;
 }
 
 /**
  * sn_i2c_write - write data to a register of the i2c slave device.
  *
  * @client: i2c device.
  * @reg: the register to write to.
  * @buf: raw data buffer to write.
  * @len: length of the buffer to write
  */
 static int sn_i2c_write_byte(struct sn65dsi83_priv *sn, u8 reg, u8 val)
 {
 	struct i2c_client *client = sn->client;
 	int ret = i2c_smbus_write_byte_data(sn->client, reg, val);
 
 	if (ret < 0)
 		dev_err(&client->dev, "%s failed(%i)\n", __func__, ret);
 	return ret;
 }
 
 static void sn_disable(struct sn65dsi83_priv *sn)
 {
 	if (sn->chip_enabled) {
 		disable_irq(sn->client->irq);
 		sn->chip_enabled = 0;
 	}
 	gpiod_set_value(sn->gp_en, 0);
 }
 
 static void sn_enable_gp(struct gpio_desc *gp_en)
 {
 	msleep(15);	/* disabled for at least 10 ms */
 	gpiod_set_value(gp_en, 1);
 	msleep(1);
 }
 
 static void sn_enable_irq(struct sn65dsi83_priv *sn)
 {
 	sn_i2c_write_byte(sn, SN_IRQ_STAT, 0xff);
 	sn_i2c_write_byte(sn, SN_IRQ_MASK, 0x7f);
 	sn_i2c_write_byte(sn, SN_IRQ_EN, 1);
 }
 
 static int sn_get_dsi_clk_divider(struct sn65dsi83_priv *sn)
 {
 	u32 dsi_clk_divider = 25;
 	u32 mipi_clk_rate;
 	u8 mipi_clk_index;
 	int ret;
 	u32 pixelclock = sn->pixelclock;
 
 	mipi_clk_rate = clk_get_rate(sn->mipi_clk);
 	if (!mipi_clk_rate) {
 		pr_err("mipi clock is off\n");
 		/* Divided by 2 because mipi output clock is DDR */
 		mipi_clk_rate = pixelclock * sn->dsi_bpp / (sn->dsi_lanes * 2);
 	}
 	if (mipi_clk_rate > 500000000) {
 		pr_err("mipi clock(%d) is too high\n", mipi_clk_rate);
 		mipi_clk_rate = 500000000;
 	}
 	if (pixelclock)
 		dsi_clk_divider = mipi_clk_rate / pixelclock;
 
 	if (dsi_clk_divider > 25)
 		dsi_clk_divider = 25;
 	else if (!dsi_clk_divider)
 		dsi_clk_divider = 1;
 	mipi_clk_index = mipi_clk_rate / 5000000;
 	if (mipi_clk_index < 8)
 		mipi_clk_index = 8;
 	ret = (sn->dsi_clk_divider == dsi_clk_divider) &&
 		(sn->mipi_clk_index == mipi_clk_index);
 	if (!ret)
 		pr_info("dsi_clk_divider = %d, mipi_clk_index=%d, mipi_clk_rate=%d\n",
 			dsi_clk_divider, mipi_clk_index, mipi_clk_rate);
 	sn->dsi_clk_divider = dsi_clk_divider;
 	sn->mipi_clk_index = mipi_clk_index;
 	return ret;
 }
 
 static int sn_setup_regs(struct sn65dsi83_priv *sn)
 {
 	unsigned i = 5;
 	int format = 0x10;
 	u32 pixelclock;
 	struct videomode vm;
 	int ret;
 
 	ret = of_get_videomode(sn->disp_dsi, &vm, 0);
 	if (ret < 0)
 		return ret;
 
 	pixelclock = vm.pixelclock;
 	if (pixelclock) {
 		if (pixelclock > 37500000) {
 			i = (pixelclock - 12500000) / 25000000;
 			if (i > 5)
 				i = 5;
 		}
 	}
 	sn->pixelclock = pixelclock;
 	pr_info("pixelclock=%d %dx%d, margins=%d,%d %d,%d  syncs=%d %d\n",
 		pixelclock, vm.hactive, vm.vactive,
 		vm.hback_porch, vm.hfront_porch,
 		vm.vback_porch, vm.vfront_porch,
 		vm.hsync_len, vm.vsync_len);
 	sn_i2c_write_byte(sn, SN_CLK_SRC, (i << 1) | 1);
 	sn_get_dsi_clk_divider(sn);
 	sn_i2c_write_byte(sn, SN_CLK_DIV, (sn->dsi_clk_divider - 1) << 3);
 
 	sn_i2c_write_byte(sn, SN_DSI_LANES, ((4 - sn->dsi_lanes) << 3) | 0x20);
 	sn_i2c_write_byte(sn, SN_DSI_EQ, 0);
 	sn_i2c_write_byte(sn, SN_DSI_CLK, sn->mipi_clk_index);
 	if (vm.flags & DISPLAY_FLAGS_DE_LOW)
 		format |= BIT(7);
 	if (!(vm.flags & DISPLAY_FLAGS_HSYNC_HIGH))
 		format |= BIT(6);
 	if (!(vm.flags & DISPLAY_FLAGS_VSYNC_HIGH))
 		format |= BIT(5);
 	if (sn->dsi_bpp == 24) {
 		if (sn->spwg) {
 			/* lvds lane 3 has MSBs of color */
 			format |= BIT(3);
 		} else if (sn->jeida) {
 			/* lvds lane 3 has LSBs of color */
 			format |= BIT(3) | BIT(1);
 		} else {
 			/* unused lvds lane 3 has LSBs of color */
 			format |= BIT(1);
 		}
 	}
 	sn_i2c_write_byte(sn, SN_FORMAT, format);
 
 	sn_i2c_write_byte(sn, SN_LVDS_VOLTAGE, 5);
 	sn_i2c_write_byte(sn, SN_LVDS_TERM, 3);
 	sn_i2c_write_byte(sn, SN_LVDS_CM_VOLTAGE, 0);
 	sn_i2c_write_byte(sn, SN_HACTIVE_LOW, (u8)vm.hactive);
 	sn_i2c_write_byte(sn, SN_HACTIVE_HIGH, (u8)(vm.hactive >> 8));
 	sn_i2c_write_byte(sn, SN_VACTIVE_LOW, (u8)vm.vactive);
 	sn_i2c_write_byte(sn, SN_VACTIVE_HIGH, (u8)(vm.vactive >> 8));
 	sn_i2c_write_byte(sn, SN_SYNC_DELAY_LOW, (u8)sn->sync_delay);
 	sn_i2c_write_byte(sn, SN_SYNC_DELAY_HIGH, (u8)(sn->sync_delay >> 8));
 	sn_i2c_write_byte(sn, SN_HSYNC_LOW, (u8)vm.hsync_len);
 	sn_i2c_write_byte(sn, SN_HSYNC_HIGH, (u8)(vm.hsync_len >> 8));
 	sn_i2c_write_byte(sn, SN_VSYNC_LOW, (u8)vm.vsync_len);
 	sn_i2c_write_byte(sn, SN_VSYNC_HIGH, (u8)(vm.vsync_len >> 8));
 	sn_i2c_write_byte(sn, SN_HBP, (u8)vm.hback_porch);
 	sn_i2c_write_byte(sn, SN_VBP, (u8)vm.vback_porch);
 	sn_i2c_write_byte(sn, SN_HFP, (u8)vm.hfront_porch);
 	sn_i2c_write_byte(sn, SN_VFP, (u8)vm.vfront_porch);
 	sn_i2c_write_byte(sn, SN_TEST_PATTERN, 0);
 	return 0;
 }
 
 static void sn_enable_pll(struct sn65dsi83_priv *sn)
 {
 	if (!sn_get_dsi_clk_divider(sn)) {
 		sn_i2c_write_byte(sn, SN_CLK_DIV, (sn->dsi_clk_divider - 1) << 3);
 		sn_i2c_write_byte(sn, SN_DSI_CLK, sn->mipi_clk_index);
 	}
 	sn_i2c_write_byte(sn, SN_PLL_EN, 1);
 	msleep(5);
 	sn_i2c_write_byte(sn, SN_SOFT_RESET, 1);
 	sn_enable_irq(sn);
 }
 
 static void sn_disable_pll(struct sn65dsi83_priv *sn)
 {
 	if (sn->chip_enabled)
 		sn_i2c_write_byte(sn, SN_PLL_EN, 0);
 }
 
 static void sn_init(struct sn65dsi83_priv *sn)
 {
 	sn_i2c_write_byte(sn, SN_SOFT_RESET, 1);
 	sn_i2c_write_byte(sn, SN_PLL_EN, 0);
 	sn_i2c_write_byte(sn, SN_IRQ_MASK, 0x0);
 	sn_i2c_write_byte(sn, SN_IRQ_EN, 1);
 }
 
 static void sn_prepare(struct sn65dsi83_priv *sn)
 {
 	sn_enable_gp(sn->gp_en);
 	sn_init(sn);
 	if (!sn->chip_enabled) {
 		sn->chip_enabled = 1;
 		enable_irq(sn->client->irq);
 	}
 	sn_setup_regs(sn);
 }
 
 static int sn_drm_event(struct notifier_block *nb, unsigned long event, void *data)
 {
 	struct drm_device *drm_dev = data;
 	struct device_node *node = drm_dev->dev->of_node;
 	struct sn65dsi83_priv *sn = container_of(nb, struct sn65dsi83_priv, drmnb);
 	struct device *dev = &sn->client->dev;
 
 	dev_dbg(dev, "%s: event %lx\n", __func__, event);
 
 	if (node != sn->disp_node)
 		return 0;
 
 	switch (event) {
 	case DRM_MODE_DPMS_ON:
 		sn_enable_pll(sn);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
 		sn_disable_pll(sn);
 		break;
 	default:
 		dev_info(dev, "%s: unknown event %lx\n", __func__, event);
 	}
 
 	return 0;
 }
 
 static int sn_fb_event(struct notifier_block *nb, unsigned long event, void *data)
 {
 	struct fb_event *evdata = data;
 	struct fb_info *info = evdata->info;
 	struct device_node *node = info->device->of_node;
 	struct sn65dsi83_priv *sn = container_of(nb, struct sn65dsi83_priv, fbnb);
 	struct device *dev;
 	int blank_type;
 
 	dev = &sn->client->dev;
 	dev_dbg(dev, "%s: event %lx\n", __func__, event);
 	if (node != sn->disp_node)
 		return 0;
 
 	switch (event) {
 	case FB_R_EARLY_EVENT_BLANK:
 		blank_type = *((int *)evdata->data);
 		if (blank_type == FB_BLANK_UNBLANK) {
 			sn_disable(sn);
 		} else {
 			sn_enable_pll(sn);
 		}
 		break;
 	case FB_EARLY_EVENT_BLANK:
 		blank_type = *((int *)evdata->data);
 		if (blank_type == FB_BLANK_UNBLANK) {
 			sn_prepare(sn);
 		} else {
 			sn_disable_pll(sn);
 		}
 		break;
 	case FB_EVENT_BLANK: {
 		blank_type = *((int *)evdata->data);
 		if (blank_type == FB_BLANK_UNBLANK) {
 			sn_enable_pll(sn);
 		} else {
 			sn_disable(sn);
 		}
 		dev_info(dev, "%s: blank type 0x%x\n", __func__, blank_type );
 		break;
 	}
 	case FB_EVENT_SUSPEND : {
 		dev_info(dev, "%s: suspend\n", __func__ );
 		sn_disable(sn);
 		break;
 	}
 	case FB_EVENT_RESUME : {
 		dev_info(dev, "%s: resume\n", __func__ );
 		break;
 	}
 	case FB_EVENT_FB_REGISTERED : {
 		if (clk_get_rate(sn->mipi_clk)) {
 			sn_prepare(sn);
 			sn_enable_pll(sn);
 		}
 		break;
 	}
 	default:
 		dev_info(dev, "%s: unknown event %lx\n", __func__, event);
 	}
 	return 0;
 }
 
 
 
 /*
  * We only report errors in this handler
  */
 static irqreturn_t sn_irq_handler(int irq, void *id)
 {
 	struct sn65dsi83_priv *sn = id;
 	int status = sn_i2c_read_byte(sn, SN_IRQ_STAT);
 
 	if (status > 0) {
 		sn_i2c_write_byte(sn, SN_IRQ_STAT, status);
 		dev_info(&sn->client->dev, "%s: status %x %x %x\n", __func__,
 			status, sn_i2c_read_byte(sn, SN_CLK_SRC),
 			sn_i2c_read_byte(sn, SN_IRQ_MASK));
 //		if (status & 1)
 //			sn_i2c_write_byte(sn, SN_SOFT_RESET, 1);
 		if (sn->int_cnt   > 10) {
 			disable_irq_nosync(sn->client->irq);
 		} else {
 			msleep(100);
 		}
 		return IRQ_HANDLED;
 	} else {
 		dev_err(&sn->client->dev, "%s: read error %d\n", __func__, status);
 	}
 	return IRQ_NONE;
 }
 
 
 static ssize_t sn65dsi83_reg_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	struct sn65dsi83_priv *sn = dev_get_drvdata(dev);
 	int val;
 	const unsigned char *p = registers_to_show;
 	int i = 0;
 	int total = 0;
 	int reg;
 	int cnt;
 
 	if (!sn->chip_enabled)
 		return -EBUSY;
 	if (sn->show_reg != 0) {
 		val = sn_i2c_read_byte(sn, sn->show_reg);
 		return sprintf(buf, "%02x: %02x\n", sn->show_reg, val);
 	}
 
 	while (i < ARRAY_SIZE(registers_to_show)) {
 		reg = *p  ;
 		i  ;
 		if (!reg) {
 			reg = *p  ;
 			i  ;
 			val = sn_i2c_read_byte(sn, reg);
 			val |= sn_i2c_read_byte(sn, reg   1) << 8;
 			cnt = sprintf(&buf[total], "%02x: %04x (%d)\n", reg, val, val);
 		} else {
 			val = sn_i2c_read_byte(sn, reg);
 			cnt = sprintf(&buf[total], "%02x: %02x (%d)\n", reg, val, val);
 		}
 		if (cnt <= 0)
 			break;
 		total  = cnt;
 	}
 	return total;
 }
 
 static ssize_t sn65dsi83_reg_store(struct device *dev, struct device_attribute *attr,
 	const char *buf, size_t count)
 {
 	unsigned val;
 	int ret;
 	struct sn65dsi83_priv *sn = dev_get_drvdata(dev);
 	char *endp;
 	unsigned reg = simple_strtol(buf, &endp, 16);
 
 	if (!sn->chip_enabled)
 		return -EBUSY;
 	if (reg > 0xe5)
 		return count;
 
 	sn->show_reg = reg;
 	if (!endp)
 		return count;
 	if (*endp == 0x20)
 		endp  ;
 	if (!*endp || *endp == 0x0a)
 		return count;
 	val = simple_strtol(endp, &endp, 16);
 	if (val >= 0x100)
 		return count;
 
 	dev_err(dev, "%s:reg=0x%x, val=0x%x\n", __func__, reg, val);
 	ret = sn_i2c_write_byte(sn, reg, val);
 	if (ret < 0)
 		return ret;
 	return count;
 }
 
 static DEVICE_ATTR(sn65dsi83_reg, 0644, sn65dsi83_reg_show, sn65dsi83_reg_store);
 
 /*
  * I2C init/probing/exit functions
  */
 static int sn65dsi83_probe(struct i2c_client *client,
 				  const struct i2c_device_id *id)
 {
 	int ret;
 	struct sn65dsi83_priv *sn;
 	struct i2c_adapter *adapter;
         struct device_node *np = client->dev.of_node;
 	struct gpio_desc *gp_en;
 	const char *df;
 	u32 sync_delay;
 	u32 dsi_lanes;
 
 	dev_info(&client->dev, "sn65dsi83_probe 1\n");
 	adapter = to_i2c_adapter(client->dev.parent);
 
 	ret = i2c_check_functionality(adapter,
 					 I2C_FUNC_SMBUS_BYTE |
 					 I2C_FUNC_SMBUS_BYTE_DATA);
 	if (!ret) {
 		dev_err(&client->dev, "i2c_check_functionality failed\n");
 		return -ENODEV;
 	}
 
 	gp_en = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW);
 	if (IS_ERR(gp_en)) {
 		if (PTR_ERR(gp_en) != -EPROBE_DEFER)
 			dev_err(&client->dev, "Failed to get enable gpio: %ld\n",
 				PTR_ERR(gp_en));
 		return PTR_ERR(gp_en);
 	}
 	if (gp_en) {
 		sn_enable_gp(gp_en);
 	} else {
 		dev_warn(&client->dev, "no enable pin available");
 	}
 	ret = i2c_smbus_read_byte_data(client, SN_CLK_SRC);
 	if (ret < 0) {
 		/* enable might be used for something else, change to input */
 		gpiod_direction_input(gp_en);
 		dev_info(&client->dev, "i2c read failed\n");
 		return -ENODEV;
 	}
 //	gpiod_set_value(gp_en, 0);
 
 	sn = devm_kzalloc(&client->dev, sizeof(*sn), GFP_KERNEL);
 	if (!sn)
 		return -ENOMEM;
 	sn->client = client;
 	sn->gp_en = gp_en;
 	sn_init(sn);
 
 	sn->disp_dsi = of_parse_phandle(np, "display-dsi", 0);
 	if (!sn->disp_dsi)
 		return -ENODEV;
 
 	sn->disp_node = of_parse_phandle(np, "display", 0);
 	if (!sn->disp_node)
 		return -ENODEV;
 
 	sn->sync_delay = 0x120;
 	if (!of_property_read_u32(np, "sync-delay", &sync_delay)) {
 		if (sync_delay > 0xfff)
 			return -EINVAL;
 		sn->sync_delay = sync_delay;
 	}
 
 	if (of_property_read_u32(sn->disp_dsi, "dsi-lanes", &dsi_lanes) < 0)
 		return -EINVAL;
 	if (dsi_lanes < 1 || dsi_lanes > 4)
 		return -EINVAL;
 	sn->dsi_lanes = dsi_lanes;
 	sn->spwg = of_property_read_bool(sn->disp_dsi, "spwg");
 	sn->jeida = of_property_read_bool(sn->disp_dsi, "jeida");
 	ret = of_property_read_string(sn->disp_dsi, "dsi-format", &df);
 	if (ret) {
 		dev_err(&client->dev, "dsi-format missing in display node%d\n", ret);
 		return ret;
 	}
 	sn->dsi_bpp = !strcmp(df, "rgb666") ? 18 : 24;
 
 	sn->mipi_clk = devm_clk_get(&client->dev, "mipi_clk");
 	if (IS_ERR(sn->mipi_clk))
 		return PTR_ERR(sn->mipi_clk);
 
 	ret = devm_request_threaded_irq(&client->dev, client->irq,
 			NULL, sn_irq_handler,
 			IRQF_ONESHOT, client->name, sn);
 	if (ret)
 		pr_info("%s: request_irq failed, irq:%i\n", client_name, client->irq);
 	disable_irq(client->irq);
 
 	i2c_set_clientdata(client, sn);
 	sn->drmnb.notifier_call = sn_drm_event;
 	ret = drm_register_client(&sn->drmnb);
 	if (ret < 0) {
 		dev_err(&client->dev, "drm_register_client failed(%d)\n", ret);
 		return ret;
 	}
 	sn->fbnb.notifier_call = sn_fb_event;
 	ret = fb_register_client(&sn->fbnb);
 	if (ret < 0) {
 		dev_err(&client->dev, "fb_register_client failed(%d)\n", ret);
 		return ret;
 	}
 	ret = device_create_file(&client->dev, &dev_attr_sn65dsi83_reg);
 	if (ret < 0)
 		pr_warn("failed to add sn65dsi83 sysfs files\n");
 
 	sn_prepare(sn);
 	dev_info(&client->dev, "succeeded\n");
 	return 0;
 }
 
 static int sn65dsi83_remove(struct i2c_client *client)
 {
 	struct sn65dsi83_priv *sn = i2c_get_clientdata(client);
 
 	device_remove_file(&client->dev, &dev_attr_sn65dsi83_reg);
 	fb_unregister_client(&sn->drmnb);
 	fb_unregister_client(&sn->fbnb);
 	sn_disable(sn);
 	return 0;
 }
 
 static const struct i2c_device_id sn65dsi83_id[] = {
 	{"sn65dsi83", 0},
 	{},
 };
 
 MODULE_DEVICE_TABLE(i2c, sn65dsi83_id);
 
 static struct i2c_driver sn65dsi83_driver = {
 	.driver = {
 		   .name = "sn65dsi83",
 		   .owner = THIS_MODULE,
 		   },
 	.probe = sn65dsi83_probe,
 	.remove = sn65dsi83_remove,
 	.id_table = sn65dsi83_id,
 };
 
 module_i2c_driver(sn65dsi83_driver);
 
 MODULE_AUTHOR("Boundary Devices, Inc.");
 MODULE_DESCRIPTION("sn65dsi83 mipi to lvds bridge");
 MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bridge/sn65dsi83/Kconfig b/drivers/gpu/drm/bridge/sn65dsi83/Kconfig
new file mode 100644
index 000000000..1d8f37f68
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83/Kconfig
@@ -0,0  1,7 @@
 config DRM_I2C_SN65DSI83
 	bool "SN65DSI83 mipi dsi to lvds bridge"
 	depends on OF
 	select DRM_MIPI_DSI
 	default y
 	help
 	  Support for the sn65dsi83 MIPI DSI to LVDS bridge
diff --git a/drivers/gpu/drm/bridge/sn65dsi83/Makefile b/drivers/gpu/drm/bridge/sn65dsi83/Makefile
new file mode 100644
index 000000000..dee7f493b
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83/Makefile
@@ -0,0  1,2 @@
 sn65dsi83-objs := sn65dsi83_drv.o sn65dsi83_brg.o
 obj-$(CONFIG_DRM_I2C_SN65DSI83) := sn65dsi83.o
diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c
new file mode 100644
index 000000000..20bbf2a54
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c
@@ -0,0  1,400 @@
 /*
  * Copyright (C) 2018 CopuLab Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
 
 #include <linux/i2c.h>
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/slab.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_connector.h>
 #include <video/mipi_display.h>
 #include <video/of_videomode.h>
 #include <video/videomode.h>
 
 #include "sn65dsi83_brg.h"
 
 /* Register addresses */
 
 #define SN65DSI83_SOFT_RESET         0x09
 #define SN65DSI83_CORE_PLL           0x0A
     #define LVDS_CLK_RANGE_SHIFT    1
     #define HS_CLK_SRC_SHIFT        0
 
 #define SN65DSI83_PLL_DIV            0x0B
     #define DSI_CLK_DIV_SHIFT       3
 
 #define SN65DSI83_PLL_EN             0x0D
 #define SN65DSI83_DSI_CFG            0x10
     #define CHA_DSI_LANES_SHIFT    3
 
 #define SN65DSI83_DSI_EQ              0x11
 #define SN65DSI83_CHA_DSI_CLK_RNG     0x12
 #define SN65DSI83_CHB_DSI_CLK_RNG     0x13
 #define SN65DSI83_LVDS_MODE           0x18
     #define DE_NEG_POLARITY_SHIFT 7
     #define HS_NEG_POLARITY_SHIFT 6
     #define VS_NEG_POLARITY_SHIFT 5
     #define LVDS_LINK_CFG_SHIFT   4
     #define CHA_24BPP_MODE_SHIFT  3
     #define CHA_24BPP_FMT1_SHIFT  1
 
 #define SN65DSI83_LVDS_SIGN           0x19
 #define SN65DSI83_LVDS_TERM           0x1A
 #define SN65DSI83_LVDS_CM_ADJ         0x1B
 #define SN65DSI83_CHA_LINE_LEN_LO     0x20
 #define SN65DSI83_CHA_LINE_LEN_HI     0x21
 #define SN65DSI83_CHB_LINE_LEN_LO     0x22
 #define SN65DSI83_CHB_LINE_LEN_HI     0x23
 #define SN65DSI83_CHA_VERT_LINES_LO   0x24
 #define SN65DSI83_CHA_VERT_LINES_HI   0x25
 #define SN65DSI83_CHB_VERT_LINES_LO   0x26
 #define SN65DSI83_CHB_VERT_LINES_HI   0x27
 #define SN65DSI83_CHA_SYNC_DELAY_LO   0x28
 #define SN65DSI83_CHA_SYNC_DELAY_HI   0x29
 #define SN65DSI83_CHB_SYNC_DELAY_LO   0x2A
 #define SN65DSI83_CHB_SYNC_DELAY_HI   0x2B
 #define SN65DSI83_CHA_HSYNC_WIDTH_LO  0x2C
 #define SN65DSI83_CHA_HSYNC_WIDTH_HI  0x2D
 #define SN65DSI83_CHB_HSYNC_WIDTH_LO  0x2E
 #define SN65DSI83_CHB_HSYNC_WIDTH_HI  0x2F
 #define SN65DSI83_CHA_VSYNC_WIDTH_LO  0x30
 #define SN65DSI83_CHA_VSYNC_WIDTH_HI  0x31
 #define SN65DSI83_CHB_VSYNC_WIDTH_LO  0x32
 #define SN65DSI83_CHB_VSYNC_WIDTH_HI  0x33
 #define SN65DSI83_CHA_HORZ_BACKPORCH  0x34
 #define SN65DSI83_CHB_HORZ_BACKPORCH  0x35
 #define SN65DSI83_CHA_VERT_BACKPORCH  0x36
 #define SN65DSI83_CHB_VERT_BACKPORCH  0x37
 #define SN65DSI83_CHA_HORZ_FRONTPORCH 0x38
 #define SN65DSI83_CHB_HORZ_FRONTPORCH 0x39
 #define SN65DSI83_CHA_VERT_FRONTPORCH 0x3A
 #define SN65DSI83_CHB_VERT_FRONTPORCH 0x3B
 #define SN65DSI83_CHA_ERR             0xE5
 #define SN65DSI83_TEST_PATTERN        0x3C
 #define SN65DSI83_REG_3D              0x3D
 #define SN65DSI83_REG_3E              0x3E
 
 static int sn65dsi83_brg_power_on(struct sn65dsi83_brg *brg)
 {
     dev_info(&brg->client->dev,"%s\n",__func__);
     gpiod_set_value_cansleep(brg->gpio_enable, 1);
     /* Wait for 1ms for the internal voltage regulator to stabilize */
     msleep(1);
 
     return 0;
 }
 
 static void sn65dsi83_brg_power_off(struct sn65dsi83_brg *brg)
 {
     dev_info(&brg->client->dev,"%s\n",__func__);
     gpiod_set_value_cansleep(brg->gpio_enable, 0);
     /*
      * The EN pin must be held low for at least 10 ms
      * before being asserted high
      */
     msleep(10);
 }
 
 static int sn65dsi83_write(struct i2c_client *client, u8 reg, u8 val)
 {
     int ret;
 
     ret = i2c_smbus_write_byte_data(client, reg, val);
 
     if (ret)
         dev_err(&client->dev, "failed to write at 0x%02x", reg);
 
     dev_dbg(&client->dev, "%s: write reg 0x%02x data 0x%02x", __func__, reg, val);
 
     return ret;
 }
 #define SN65DSI83_WRITE(reg,val) sn65dsi83_write(client, (reg) , (val))
 
 static int sn65dsi83_read(struct i2c_client *client, u8 reg)
 {
     int ret;
 
     dev_info(&client->dev, "client 0x%p", client);
     ret = i2c_smbus_read_byte_data(client, reg);
 
     if (ret < 0) {
         dev_err(&client->dev, "failed reading at 0x%02x", reg);
         return ret;
     }
 
     dev_dbg(&client->dev, "%s: read reg 0x%02x data 0x%02x", __func__, reg, ret);
 
     return ret;
 }
 #define SN65DSI83_READ(reg) sn65dsi83_read(client, (reg))
 
 static int sn65dsi83_brg_start_stream(struct sn65dsi83_brg *brg)
 {
     int regval;
     struct i2c_client *client = I2C_CLIENT(brg);
 
     dev_info(&client->dev,"%s\n",__func__);
     /* Set the PLL_EN bit (CSR 0x0D.0) */
     SN65DSI83_WRITE(SN65DSI83_PLL_EN, 0x1);
     /* Wait for the PLL_LOCK bit to be set (CSR 0x0A.7) */
     msleep(200);
 
     /* Perform SW reset to apply changes */
     SN65DSI83_WRITE(SN65DSI83_SOFT_RESET, 0x01);
 
     /* Read CHA Error register */
     regval = SN65DSI83_READ(SN65DSI83_CHA_ERR);
     dev_info(&client->dev, "CHA (0x%02x) = 0x%02x",
          SN65DSI83_CHA_ERR, regval);
 
 	SN65DSI83_WRITE(SN65DSI83_CHA_ERR, 0xff);
     regval = SN65DSI83_READ(SN65DSI83_CHA_ERR);
     dev_info(&client->dev, "CHA (0x%02x) = 0x%02x",
          SN65DSI83_CHA_ERR, regval);
     msleep(10);
 
     regval = SN65DSI83_READ(SN65DSI83_CHA_ERR);
     dev_info(&client->dev, "CHA (0x%02x) = 0x%02x",
          SN65DSI83_CHA_ERR, regval);
 
     return 0;
 }
 
 static void sn65dsi83_brg_stop_stream(struct sn65dsi83_brg *brg)
 {
     struct i2c_client *client = I2C_CLIENT(brg);
     dev_info(&client->dev,"%s\n",__func__);
     /* Clear the PLL_EN bit (CSR 0x0D.0) */
     SN65DSI83_WRITE(SN65DSI83_PLL_EN, 0x00);
 }
 
 static int sn65dsi83_calk_clk_range(int min_regval, int max_regval,
                 unsigned long min_clk, unsigned long inc,
                 unsigned long target_clk)
 {
     int regval = min_regval;
     unsigned long clk = min_clk;
 
     while (regval <= max_regval) {
         if ((clk <= target_clk) && (target_clk < (clk   inc)))
             return regval;
 
         regval  ;
         clk  = inc;
     }
 
     return -1;
 }
 
 #define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
 static int sn65dsi83_calk_div(int min_regval, int max_regval, int min_div,
                 int inc, unsigned long source_clk,
                 unsigned long target_clk)
 {
     int regval = min_regval;
     int div = min_div;
     unsigned long curr_delta;
     unsigned long prev_delta = ABS(DIV_ROUND_UP(source_clk, div) -
                     target_clk);
 
     while (regval <= max_regval) {
         curr_delta = ABS(DIV_ROUND_UP(source_clk, div) - target_clk);
         if (curr_delta > prev_delta)
             return --regval;
 
         regval  ;
         div  = inc;
     }
 
     return -1;
 }
 
 static int sn65dsi83_brg_configure(struct sn65dsi83_brg *brg)
 {
     int regval = 0;
     struct i2c_client *client = I2C_CLIENT(brg);
     struct videomode *vm = VM(brg);
 
     u32 dsi_clk = (((PIXCLK * BPP(brg)) / DSI_LANES(brg)) >> 1);
 
     dev_info(&client->dev, "DSI clock [ %u ] Hz\n",dsi_clk);
     dev_info(&client->dev, "GeoMetry [ %d x %d ] Hz\n",HACTIVE,VACTIVE);
 
     /* Reset PLL_EN and SOFT_RESET registers */
     SN65DSI83_WRITE(SN65DSI83_SOFT_RESET,0x00);
     SN65DSI83_WRITE(SN65DSI83_PLL_EN,0x00);
 
     /* LVDS clock setup */
     if  ((25000000 <= PIXCLK) && (PIXCLK < 37500000))
         regval = 0;
     else
         regval = sn65dsi83_calk_clk_range(0x01, 0x05, 37500000, 25000000,
                     PIXCLK);
 
     if (regval < 0) {
         dev_err(&client->dev, "failed to configure LVDS clock");
         return -EINVAL;
     }
 
     regval = (regval << LVDS_CLK_RANGE_SHIFT);
     regval |= (1 << HS_CLK_SRC_SHIFT); /* Use DSI clock */
     SN65DSI83_WRITE(SN65DSI83_CORE_PLL,regval);
 
     /* DSI clock range */
     regval = sn65dsi83_calk_clk_range(0x08, 0x64, 40000000, 5000000, dsi_clk);
     if (regval < 0) {
         dev_err(&client->dev, "failed to configure DSI clock range\n");
         return -EINVAL;
     }
     SN65DSI83_WRITE(SN65DSI83_CHA_DSI_CLK_RNG,regval);
 
     /* DSI clock divider */
     regval = sn65dsi83_calk_div(0x0, 0x18, 1, 1, dsi_clk, PIXCLK);
     if (regval < 0) {
         dev_err(&client->dev, "failed to calculate DSI clock divider");
         return -EINVAL;
     }
 
     regval = regval << DSI_CLK_DIV_SHIFT;
     SN65DSI83_WRITE(SN65DSI83_PLL_DIV,regval);
 
     /* Configure DSI_LANES  */
     regval = SN65DSI83_READ(SN65DSI83_DSI_CFG);
     regval &= ~(3 << CHA_DSI_LANES_SHIFT);
     regval |= ((4 - DSI_LANES(brg)) << CHA_DSI_LANES_SHIFT);
 	printk("DSI lanes = %d.... val = 0x%x\n", (int)DSI_LANES(brg), regval);
     SN65DSI83_WRITE(SN65DSI83_DSI_CFG,regval);
 
     /* CHA_DSI_DATA_EQ - No Equalization */
     /* CHA_DSI_CLK_EQ  - No Equalization */
     SN65DSI83_WRITE(SN65DSI83_DSI_EQ,0x00);
 
     /* Video formats */
     regval = 0;
     if (FLAGS & DISPLAY_FLAGS_HSYNC_LOW)
         regval |= (1 << HS_NEG_POLARITY_SHIFT);
 
     if (FLAGS & DISPLAY_FLAGS_VSYNC_LOW)
         regval |= (1 << VS_NEG_POLARITY_SHIFT);
 
     if (FLAGS & DISPLAY_FLAGS_DE_LOW)
         regval |= (1 << DE_NEG_POLARITY_SHIFT);
 
     if (BPP(brg) == 24)
         regval |= (1 << CHA_24BPP_MODE_SHIFT);
 
     if (FORMAT(brg) == 1)
         regval |= (1 << CHA_24BPP_FMT1_SHIFT);
 
     regval |= (1 << LVDS_LINK_CFG_SHIFT);
 	printk("SN65DSI83_LVDS_MODE = 0x%x\n", regval);
     SN65DSI83_WRITE(SN65DSI83_LVDS_MODE,regval);
 
     /* Voltage and pins */
     SN65DSI83_WRITE(SN65DSI83_LVDS_SIGN,0x00);
     SN65DSI83_WRITE(SN65DSI83_LVDS_TERM,0x03);
     SN65DSI83_WRITE(SN65DSI83_LVDS_CM_ADJ,0x00);
 
     /* Configure sync delay to minimal allowed value */
     SN65DSI83_WRITE(SN65DSI83_CHA_SYNC_DELAY_LO,0x21);
     SN65DSI83_WRITE(SN65DSI83_CHA_SYNC_DELAY_HI,0x00);
 
     /* Geometry */
     SN65DSI83_WRITE(SN65DSI83_CHA_LINE_LEN_LO,LOW(HACTIVE));
     SN65DSI83_WRITE(SN65DSI83_CHA_LINE_LEN_HI,HIGH(HACTIVE));
 
     SN65DSI83_WRITE(SN65DSI83_CHA_VERT_LINES_LO,LOW(VACTIVE));
     SN65DSI83_WRITE(SN65DSI83_CHA_VERT_LINES_HI,HIGH(VACTIVE));
 
     SN65DSI83_WRITE(SN65DSI83_CHA_HSYNC_WIDTH_LO,LOW(HPW));
     SN65DSI83_WRITE(SN65DSI83_CHA_HSYNC_WIDTH_HI,HIGH(HPW));
 
     SN65DSI83_WRITE(SN65DSI83_CHA_VSYNC_WIDTH_LO,LOW(VPW));
     SN65DSI83_WRITE(SN65DSI83_CHA_VSYNC_WIDTH_HI,HIGH(VPW));
 
     SN65DSI83_WRITE(SN65DSI83_CHA_HORZ_BACKPORCH,LOW(HBP));
     SN65DSI83_WRITE(SN65DSI83_CHA_VERT_BACKPORCH,LOW(VBP));
 
     SN65DSI83_WRITE(SN65DSI83_CHA_HORZ_FRONTPORCH,LOW(HFP));
     SN65DSI83_WRITE(SN65DSI83_CHA_VERT_FRONTPORCH,LOW(VFP));
 
     SN65DSI83_WRITE(SN65DSI83_TEST_PATTERN,0x00);
     SN65DSI83_WRITE(SN65DSI83_REG_3D,0x00);
     SN65DSI83_WRITE(SN65DSI83_REG_3E,0x00);
 
     /* mute channel B */
     SN65DSI83_WRITE(SN65DSI83_CHB_DSI_CLK_RNG, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_LINE_LEN_LO, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_LINE_LEN_HI, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_VERT_LINES_LO, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_VERT_LINES_HI, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_SYNC_DELAY_LO, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_SYNC_DELAY_HI, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_HSYNC_WIDTH_LO, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_HSYNC_WIDTH_HI, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_VSYNC_WIDTH_LO, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_VSYNC_WIDTH_HI, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_HORZ_BACKPORCH, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_VERT_BACKPORCH, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_HORZ_FRONTPORCH, 0x00);
     SN65DSI83_WRITE(SN65DSI83_CHB_VERT_FRONTPORCH, 0x00);
     return 0;
 }
 
 static int sn65dsi83_brg_setup(struct sn65dsi83_brg *brg)
 {
     struct i2c_client *client = I2C_CLIENT(brg);
     dev_info(&client->dev,"%s\n",__func__);
     sn65dsi83_brg_power_on(brg);
     return sn65dsi83_brg_configure(brg);
 }
 
 static int sn65dsi83_brg_reset(struct sn65dsi83_brg *brg)
 {
     /* Soft Reset reg value at power on should be 0x00 */
     struct i2c_client *client = I2C_CLIENT(brg);
     int ret = SN65DSI83_READ(SN65DSI83_SOFT_RESET);
     dev_info(&client->dev,"%s\n",__func__);
     if (ret != 0x00) {
         dev_err(&client->dev,"Failed to reset the device");
         return -ENODEV;
     }
     return 0;
 }
 
 static struct sn65dsi83_brg_funcs brg_func = {
     .power_on = sn65dsi83_brg_power_on,
     .power_off = sn65dsi83_brg_power_off,
     .setup = sn65dsi83_brg_setup,
     .reset = sn65dsi83_brg_reset,
     .start_stream = sn65dsi83_brg_start_stream,
     .stop_stream = sn65dsi83_brg_stop_stream,
 };
 
 static struct sn65dsi83_brg brg = {
     .funcs = &brg_func,
 };
 
 struct sn65dsi83_brg *sn65dsi83_brg_get(void) {
     return &brg;
 }
diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h
new file mode 100644
index 000000000..9f23df8af
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h
@@ -0,0  1,55 @@
 #ifndef _SN65DSI83_BRG_H__
 #define _SN65DSI83_BRG_H__
 
 #include <linux/i2c.h>
 #include <linux/gpio/consumer.h>
 #include <video/videomode.h>
 
 struct sn65dsi83_brg;
 struct sn65dsi83_brg_funcs {
     int (*power_on)(struct sn65dsi83_brg *sn65dsi8383_brg);
     void (*power_off)(struct sn65dsi83_brg *sn65dsi8383_brg);
     int (*reset)(struct sn65dsi83_brg *sn65dsi8383_brg);
     int (*setup)(struct sn65dsi83_brg *sn65dsi8383_brg);
     int (*start_stream)(struct sn65dsi83_brg *sn65dsi8383_brg);
     void (*stop_stream)(struct sn65dsi83_brg *sn65dsi8383_brg);
 };
 
 struct sn65dsi83_brg {
     struct i2c_client *client;
     struct gpio_desc *gpio_enable;
     /* Bridge Panel Parameters */
     struct videomode vm;
     u32 width_mm;
     u32 height_mm;
     u32 format;
     u32 bpp;
 
     u8 num_dsi_lanes;
     struct sn65dsi83_brg_funcs *funcs;
 };
 struct sn65dsi83_brg *sn65dsi83_brg_get(void);
 
 #define I2C_DEVICE(A) &(A)->client->dev
 #define I2C_CLIENT(A) (A)->client
 #define VM(A) &(A)->vm
 #define BPP(A) (A)->bpp
 #define FORMAT(A) (A)->format
 #define DSI_LANES(A) (A)->num_dsi_lanes
 
 /* The caller has to have a vm structure defined */
 #define PIXCLK vm->pixelclock
 #define HACTIVE vm->hactive
 #define HFP vm->hfront_porch
 #define HBP vm->hback_porch
 #define HPW vm->hsync_len
 #define VACTIVE vm->vactive
 #define VFP vm->vfront_porch
 #define VBP vm->vback_porch
 #define VPW vm->vsync_len
 #define FLAGS vm->flags
 
 #define HIGH(A) (((A) >> 8) & 0xFF)
 #define LOW(A)  ((A)  & 0xFF)
 
 #endif /* _SN65DSI83_BRG_H__ */
diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c
new file mode 100644
index 000000000..b0adb20de
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c
@@ -0,0  1,433 @@
 /*
  * Licensed under the GPL-2.
  */
 #define DEBUG
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/slab.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc_helper.h>
 #include <video/mipi_display.h>
 #include <video/of_videomode.h>
 #include <video/videomode.h>
 
 #include "sn65dsi83_timing.h"
 #include "sn65dsi83_brg.h"
 
 struct sn65dsi83 {
     u8 channel_id;
     enum drm_connector_status status;
     bool powered;
     struct drm_display_mode curr_mode;
     struct drm_bridge bridge;
     struct drm_connector connector;
     struct device_node *host_node;
     struct mipi_dsi_device *dsi;
     struct sn65dsi83_brg *brg;
 };
 
 static int sn65dsi83_attach_dsi(struct sn65dsi83 *sn65dsi83);
 #define DRM_DEVICE(A) A->dev->dev
 /* Connector funcs */
 static struct sn65dsi83 *connector_to_sn65dsi83(struct drm_connector *connector)
 {
     return container_of(connector, struct sn65dsi83, connector);
 }
 
 static int sn65dsi83_connector_get_modes(struct drm_connector *connector)
 {
     struct sn65dsi83 *sn65dsi83 = connector_to_sn65dsi83(connector);
     struct sn65dsi83_brg *brg = sn65dsi83->brg;
     struct device *dev = connector->dev->dev;
     struct drm_display_mode *mode;
     u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
     u32 *bus_flags = &connector->display_info.bus_flags;
     int ret;
 
     dev_info(dev, "%s\n",__func__);
     mode = drm_mode_create(connector->dev);
     if (!mode) {
         DRM_DEV_ERROR(dev, "Failed to create display mode!\n");
         return 0;
     }
 
     drm_display_mode_from_videomode(&brg->vm, mode);
     mode->width_mm = brg->width_mm;
     mode->height_mm = brg->height_mm;
     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 
     drm_mode_probed_add(connector, mode);
     drm_mode_connector_list_update(connector);
 
     connector->display_info.width_mm = mode->width_mm;
     connector->display_info.height_mm = mode->height_mm;
 
     if (brg->vm.flags & DISPLAY_FLAGS_DE_HIGH)
         *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
     if (brg->vm.flags & DISPLAY_FLAGS_DE_LOW)
         *bus_flags |= DRM_BUS_FLAG_DE_LOW;
     if (brg->vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
         *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
     if (brg->vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
         *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
 
     ret = drm_display_info_set_bus_formats(&connector->display_info,
                            &bus_format, 1);
     if (ret)
         return ret;
 
     return 1;
 }
 
 static enum drm_mode_status
 sn65dsi83_connector_mode_valid(struct drm_connector *connector,
                  struct drm_display_mode *mode)
 {
     struct sn65dsi83 *sn65dsi83 = connector_to_sn65dsi83(connector);
     struct device *dev = connector->dev->dev;
 	if (mode->clock > ( sn65dsi83->brg->vm.pixelclock / 1000 ))
 		return MODE_CLOCK_HIGH;
 
     dev_info(dev, "%s: mode: %d*%d@%d is valid\n",__func__,
             mode->hdisplay,mode->vdisplay,mode->clock);
 
 	//drm_kms_helper_hotplug_event(connector->dev);
     return MODE_OK;
 }
 
 static struct drm_connector_helper_funcs sn65dsi83_connector_helper_funcs = {
     .get_modes = sn65dsi83_connector_get_modes,
     .mode_valid = sn65dsi83_connector_mode_valid,
 };
 
 static enum drm_connector_status
 sn65dsi83_connector_detect(struct drm_connector *connector, bool force)
 {
     struct sn65dsi83 *sn65dsi83 = connector_to_sn65dsi83(connector);
     struct device *dev = connector->dev->dev;
     enum drm_connector_status status;
     dev_info(dev, "%s\n",__func__);
 
     status = connector_status_connected;
     sn65dsi83->status = status;
     return status;
 }
 
 static int sn65dsi83_drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 {
 	drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
 	drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
 	return 0;
 }
 
 static struct drm_connector_funcs sn65dsi83_connector_funcs = {
 //    .dpms = drm_atomic_helper_connector_dpms,
 	.dpms = sn65dsi83_drm_helper_connector_dpms,
     .fill_modes = drm_helper_probe_single_connector_modes,
     .detect = sn65dsi83_connector_detect,
     .destroy = drm_connector_cleanup,
     .reset = drm_atomic_helper_connector_reset,
     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 /* Bridge funcs */
 static struct sn65dsi83 *bridge_to_sn65dsi83(struct drm_bridge *bridge)
 {
     return container_of(bridge, struct sn65dsi83, bridge);
 }
 
 static void sn65dsi83_bridge_enable(struct drm_bridge *bridge)
 {
     struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
     dev_info(DRM_DEVICE(bridge),"%s\n",__func__);
     sn65dsi83->brg->funcs->setup(sn65dsi83->brg);
     sn65dsi83->brg->funcs->start_stream(sn65dsi83->brg);
 }
 
 static void sn65dsi83_bridge_disable(struct drm_bridge *bridge)
 {
     struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
     dev_info(DRM_DEVICE(bridge),"%s\n",__func__);
     sn65dsi83->brg->funcs->stop_stream(sn65dsi83->brg);
     sn65dsi83->brg->funcs->power_off(sn65dsi83->brg);
 }
 
 static void sn65dsi83_bridge_mode_set(struct drm_bridge *bridge,
                     struct drm_display_mode *mode,
                     struct drm_display_mode *adj_mode)
 {
     struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
     dev_info(DRM_DEVICE(bridge), "%s: mode: %d*%d@%d\n",__func__,
             mode->hdisplay,mode->vdisplay,mode->clock);
     drm_mode_copy(&sn65dsi83->curr_mode, adj_mode);
 }
 
 static int sn65dsi83_bridge_attach(struct drm_bridge *bridge)
 {
     struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
     int ret;
 
     dev_info(DRM_DEVICE(bridge),"%s\n",__func__);
     if (!bridge->encoder) {
         DRM_ERROR("Parent encoder object not found");
         return -ENODEV;
     }
 
     sn65dsi83->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
 
     ret = drm_connector_init(bridge->dev, &sn65dsi83->connector,
                  &sn65dsi83_connector_funcs,
                  DRM_MODE_CONNECTOR_DSI);
     if (ret) {
         DRM_ERROR("Failed to initialize connector with drm\n");
         return ret;
     }
     drm_connector_helper_add(&sn65dsi83->connector,
                  &sn65dsi83_connector_helper_funcs);
     drm_mode_connector_attach_encoder(&sn65dsi83->connector, bridge->encoder);
 
     ret = sn65dsi83_attach_dsi(sn65dsi83);
 
 	// MM
 	//drm_bridge_enable(bridge);
     return ret;
 }
 
 static struct drm_bridge_funcs sn65dsi83_bridge_funcs = {
     .enable = sn65dsi83_bridge_enable,
     .disable = sn65dsi83_bridge_disable,
     .mode_set = sn65dsi83_bridge_mode_set,
     .attach = sn65dsi83_bridge_attach,
 };
 
 static int sn65dsi83_parse_dt(struct device_node *np,
     struct sn65dsi83 *sn65dsi83)
 {
     struct device *dev = &sn65dsi83->brg->client->dev;
     u32 num_lanes = 4, bpp = 24, format = 2, width = 149, height = 93;
     struct device_node *endpoint;
 
 	dev_dbg(dev, "sn65dsi83_parse_dt\n");
 
     endpoint = of_graph_get_next_endpoint(np, NULL);
     if (!endpoint)
         return -ENODEV;
 
     sn65dsi83->host_node = of_graph_get_remote_port_parent(endpoint);
     if (!sn65dsi83->host_node) {
         of_node_put(endpoint);
         return -ENODEV;
     }
 
 	dev_dbg(dev, "sn65dsi83_parse_dt... parsing dt\n");
     of_property_read_u32(np, "ti,dsi-lanes", &num_lanes);
     of_property_read_u32(np, "ti,lvds-format", &format);
     of_property_read_u32(np, "ti,lvds-bpp", &bpp);
     of_property_read_u32(np, "ti,width-mm", &width);
     of_property_read_u32(np, "ti,height-mm", &height);
 
     if (num_lanes < 1 || num_lanes > 4) {
         dev_err(dev, "Invalid dsi-lanes: %d\n", num_lanes);
         return -EINVAL;
     }
     sn65dsi83->brg->num_dsi_lanes = num_lanes;
 
     sn65dsi83->brg->gpio_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
     if (IS_ERR(sn65dsi83->brg->gpio_enable)) {
         dev_err(dev, "failed to parse enable gpio");
         return PTR_ERR(sn65dsi83->brg->gpio_enable);
     }
 
     sn65dsi83->brg->format = format;
     sn65dsi83->brg->bpp = bpp;
 
     sn65dsi83->brg->width_mm = width;
     sn65dsi83->brg->height_mm = height;
 
     /* Read default timing if there is not device tree node for */
     if ((of_get_videomode(np, &sn65dsi83->brg->vm, 0)) < 0)
 	{
 		 dev_dbg(dev, "******** panel_default_timing\n");  
         videomode_from_timing(&panel_default_timing, &sn65dsi83->brg->vm);
 	}
 
     of_node_put(endpoint);
     of_node_put(sn65dsi83->host_node);
 
     return 0;
 }
 
 static int sn65dsi83_probe(struct i2c_client *i2c,
     const struct i2c_device_id *id)
 {
     struct sn65dsi83 *sn65dsi83;
     struct device *dev = &i2c->dev;
     int ret;
 
     dev_info(dev,"%s\n",__func__);
     if (!dev->of_node)
         return -EINVAL;
 
     sn65dsi83 = devm_kzalloc(dev, sizeof(*sn65dsi83), GFP_KERNEL);
     if (!sn65dsi83)
         return -ENOMEM;
 
     /* Initialize it before DT parser */
     sn65dsi83->brg = sn65dsi83_brg_get();
     sn65dsi83->brg->client = i2c;
 
     sn65dsi83->powered = false;
     sn65dsi83->status = connector_status_disconnected;
 
     i2c_set_clientdata(i2c, sn65dsi83);
 
     ret = sn65dsi83_parse_dt(dev->of_node, sn65dsi83);
     if (ret)
         return ret;
 
     sn65dsi83->brg->funcs->power_off(sn65dsi83->brg);
     sn65dsi83->brg->funcs->power_on(sn65dsi83->brg);
     ret  = sn65dsi83->brg->funcs->reset(sn65dsi83->brg);
     if (ret != 0x00) {
         dev_err(dev, "Failed to reset the device");
         return -ENODEV;
     }
     sn65dsi83->brg->funcs->power_off(sn65dsi83->brg);
 
 
     sn65dsi83->bridge.funcs = &sn65dsi83_bridge_funcs;
     sn65dsi83->bridge.of_node = dev->of_node;
 
     ret = drm_bridge_add(&sn65dsi83->bridge);
     if (ret) {
         dev_err(dev, "failed to add sn65dsi83 bridge\n");
     }
 
     dev_info(dev,"%s done\n",__func__);
 
     return ret;
 }
 
 static int sn65dsi83_attach_dsi(struct sn65dsi83 *sn65dsi83)
 {
     struct device *dev = &sn65dsi83->brg->client->dev;
     struct mipi_dsi_host *host;
     struct mipi_dsi_device *dsi;
     int ret = 0;
     const struct mipi_dsi_device_info info = { .type = "sn65dsi83",
                            .channel = 0,
                            .node = NULL,
                          };
 
     dev_info(dev, "%s\n",__func__);
     host = of_find_mipi_dsi_host_by_node(sn65dsi83->host_node);
     if (!host) {
         dev_err(dev, "failed to find dsi host\n");
         return -EPROBE_DEFER;
     }
 
     dsi = mipi_dsi_device_register_full(host, &info);
     if (IS_ERR(dsi)) {
         dev_err(dev, "failed to create dsi device\n");
         ret = PTR_ERR(dsi);
         return -ENODEV;
     }
 
     sn65dsi83->dsi = dsi;
 
     dsi->lanes = sn65dsi83->brg->num_dsi_lanes;
     dsi->format = MIPI_DSI_FMT_RGB888;
 //    dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE |
 //               MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_VIDEO_BURST;
 
   dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE;
 //	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
 //			  MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
 
     ret = mipi_dsi_attach(dsi);
     if (ret < 0) {
         dev_err(dev, "failed to attach dsi to host\n");
         mipi_dsi_device_unregister(dsi);
     }
 
     return ret;
 }
 
 static void sn65dsi83_detach_dsi(struct sn65dsi83 *sn65dsi83)
 {
     struct device *dev = &sn65dsi83->brg->client->dev;
     dev_info(dev, "%s\n",__func__);
     mipi_dsi_detach(sn65dsi83->dsi);
     mipi_dsi_device_unregister(sn65dsi83->dsi);
 }
 
 static int sn65dsi83_remove(struct i2c_client *i2c)
 {
     struct sn65dsi83 *sn65dsi83 = i2c_get_clientdata(i2c);
     struct device *dev = &sn65dsi83->brg->client->dev;
     dev_info(dev, "%s\n",__func__);
 
     sn65dsi83_detach_dsi(sn65dsi83);
     drm_bridge_remove(&sn65dsi83->bridge);
 
     return 0;
 }
 
 static const struct i2c_device_id sn65dsi83_i2c_ids[] = {
     { "sn65dsi83", 0 },
     { }
 };
 MODULE_DEVICE_TABLE(i2c, sn65dsi83_i2c_ids);
 
 static const struct of_device_id sn65dsi83_of_ids[] = {
     { .compatible = "ti,sn65dsi83" },
     { }
 };
 MODULE_DEVICE_TABLE(of, sn65dsi83_of_ids);
 
 static struct mipi_dsi_driver sn65dsi83_dsi_driver = {
     .driver.name = "sn65dsi83",
 };
 
 static struct i2c_driver sn65dsi83_driver = {
     .driver = {
         .name = "sn65dsi83",
         .of_match_table = sn65dsi83_of_ids,
     },
     .id_table = sn65dsi83_i2c_ids,
     .probe = sn65dsi83_probe,
     .remove = sn65dsi83_remove,
 };
 
 static int __init sn65dsi83_init(void)
 {
     if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
         mipi_dsi_driver_register(&sn65dsi83_dsi_driver);
 
     return i2c_add_driver(&sn65dsi83_driver);
 }
 module_init(sn65dsi83_init);
 
 static void __exit sn65dsi83_exit(void)
 {
     i2c_del_driver(&sn65dsi83_driver);
 
     if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
         mipi_dsi_driver_unregister(&sn65dsi83_dsi_driver);
 }
 module_exit(sn65dsi83_exit);
 
 MODULE_AUTHOR("CompuLab <compulab@compula.co.il>");
 MODULE_DESCRIPTION("SN65DSI bridge driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h
new file mode 100644
index 000000000..e9bb6633c
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h
@@ -0,0  1,33 @@
 #ifndef __SN65DSI83_TIMING_H__
 #define __SN65DSI83_TIMING_H__
 
 /* Default Video Parameters */
 #define PIXCLK_INIT 62500000
 
 #define HACTIVE_INIT 1280
 #define HPW_INIT 2
 #define HBP_INIT 6
 #define HFP_INIT 5
 
 #define VACTIVE_INIT 800
 #define VPW_INIT 1
 #define VBP_INIT 2
 #define VFP_INIT 3
 
 static const struct display_timing panel_default_timing = {
     .pixelclock = { PIXCLK_INIT, PIXCLK_INIT, PIXCLK_INIT },
     .hactive = { HACTIVE_INIT, HACTIVE_INIT, HACTIVE_INIT },
     .hfront_porch = { HFP_INIT, HFP_INIT, HFP_INIT },
     .hsync_len = { HPW_INIT, HPW_INIT, HPW_INIT },
     .hback_porch = { HBP_INIT, HBP_INIT, HBP_INIT },
     .vactive = { VACTIVE_INIT, VACTIVE_INIT, VACTIVE_INIT },
     .vfront_porch = { VFP_INIT, VFP_INIT, VFP_INIT },
     .vsync_len = { VPW_INIT, VPW_INIT, VPW_INIT },
     .vback_porch = { VBP_INIT, VBP_INIT, VBP_INIT },
     .flags = DISPLAY_FLAGS_HSYNC_LOW |
          DISPLAY_FLAGS_VSYNC_LOW |
          DISPLAY_FLAGS_DE_LOW |
          DISPLAY_FLAGS_PIXDATA_NEGEDGE,
 };
 
 #endif /* __SN65DSI83_TIMING_H__ */
diff --git a/drivers/gpu/drm/bridge/sn65dsi84-dsi2lvds.c b/drivers/gpu/drm/bridge/sn65dsi84-dsi2lvds.c
new file mode 100644
index 000000000..2d0858505
--- /dev/null
    b/drivers/gpu/drm/bridge/sn65dsi84-dsi2lvds.c
@@ -0,0  1,210 @@
 /*
  * Texas Instruments sn65dsi84 DSI to LVDS bridge driver.
  *
  * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
 
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/gpio/consumer.h>
 
 static int sn65dsi84_i2c_read(struct i2c_client *client, char *writebuf,
 			   int writelen, char *readbuf, int readlen)
 {
 	int ret;
 
 	if (writelen > 0) {
 		struct i2c_msg msgs[] = {
 			{
 				.addr = client->addr,
 				.flags = 0,
 				.len = writelen,
 				.buf = writebuf,
 			},
 			{
 				.addr = client->addr,
 				.flags = I2C_M_RD,
 				.len = readlen,
 				.buf = readbuf,
 			},
 		};
 
 		ret = i2c_transfer(client->adapter, msgs, 2);
 		if (ret < 0)
 			dev_err(&client->dev, "%s: i2c read error.\n", __func__);
 	} else {
 		struct i2c_msg msgs[] = {
 			{
 				.addr = client->addr,
 				.flags = I2C_M_RD,
 				.len = readlen,
 				.buf = readbuf,
 			},
 		};
 
 		ret = i2c_transfer(client->adapter, msgs, 1);
 		if (ret < 0)
 			dev_err(&client->dev, "%s:i2c read error.\n", __func__);
 	}
 
 	return ret;
 }
 
 static int sn65dsi84_i2c_write(struct i2c_client *client, char *writebuf,
 			    int writelen)
 {
 	int ret;
 
 	struct i2c_msg msgs[] = {
 		{
 			.addr = client->addr,
 			.flags = 0,
 			.len = writelen,
 			.buf = writebuf,
 		},
 	};
 	ret = i2c_transfer(client->adapter, msgs, 1);
 	if (ret < 0)
 		dev_err(&client->dev, "%s: i2c write error.\n", __func__);
 
 	return ret;
 }
 
 static int sn65dsi84_write_reg(struct i2c_client *client, u8 addr, const u8 val)
 {
 	u8 buf[2] = {0};
 
 	buf[0] = addr;
 	buf[1] = val;
 
 	return sn65dsi84_i2c_write(client, buf, sizeof(buf));
 }
 
 static int sn65dsi84_probe(struct i2c_client *client,
 			   const struct i2c_device_id *id)
 {
 	struct property *prop;
 	int err;
 	int i, size;
 	struct device_node *np = client->dev.of_node;
 	int addresses[100];
 	int values[100];
 	int chipid[] = {0x35, 0x38, 0x49, 0x53, 0x44, 0x20, 0x20, 0x20, 0x01};
 	char address, value;
 	struct gpio_desc *enable_gpio;
 	enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH);
 	if (enable_gpio)
 		gpiod_set_value_cansleep(enable_gpio, 1);
 	for (i = 0; i < sizeof(chipid) / sizeof(int); i  ) {
 		address = (char)i;
 		err = sn65dsi84_i2c_read(client, &address, 1, &value, 1);
 		if (err < 0) {
 			dev_err(&client->dev, "failed to read chip id\n");
 			return err;
 		}
 		if (value != chipid[i]) {
 			dev_err(&client->dev, "chip id is not correct\n");
 			return err;
 		}
 	}
 	prop = of_find_property(np, "sn65dsi84,addresses", NULL);
 	if (!prop)
 		return -EINVAL;
 	if (!prop->value)
 		return -ENODATA;
 	size = prop->length / sizeof(int);
 
 	err = of_property_read_u32_array(np, "sn65dsi84,addresses", addresses, size);
 	if (err && (err != -EINVAL)) {
 		dev_err(&client->dev, "Unable to read 'sn65dsi84,addresses'\n");
 		return err;
 	}
 	prop = of_find_property(np, "sn65dsi84,values", NULL);
 	if (!prop)
 		return -EINVAL;
 	if (!prop->value)
 		return -ENODATA;
 	i = prop->length / sizeof(u32);
 	if (i != size) {
 		dev_err(&client->dev, "invalid 'sn65dsi84,values' length should be same as addresses\n");
 		return -EINVAL;
 	}
 	err = of_property_read_u32_array(np, "sn65dsi84,values", values, i);
 	if (err && (err != -EINVAL)) {
 		dev_err(&client->dev, "Unable to read 'sn65dsi84,values'\n");
 		return err;
 	}
 	for (i = 0; i < size; i  ) {
 		sn65dsi84_write_reg(client, addresses[i], values[i]);
 		if (err < 0) {
 			dev_err(&client->dev, "failed to write data to the chip\n");
 			return err;
 		}
 	}
 
 	return 0;
 }
 
 static int sn65dsi84_remove(struct i2c_client *client)
 {
 	struct gpio_desc *enable_gpio;
 
 	enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW);
 	if (enable_gpio)
 		gpiod_set_value_cansleep(enable_gpio, 0);
 
 	return 0;
 }
 
 static const struct i2c_device_id sn65dsi84_id[] = {
 	{"sn65dsi84", 0},
 	{},
 };
 
 MODULE_DEVICE_TABLE(i2c, sn65dsi84_id);
 
 static struct of_device_id sn65dsi84_match_table[] = {
 	{ .compatible = "ti,sn65dsi84",},
 	{ },
 };
 
 static struct i2c_driver sn65dsi84_i2c_driver = {
 	.probe = sn65dsi84_probe,
 	.remove = sn65dsi84_remove,
 	.driver = {
 		.name = "sn65dsi84",
 		.owner = THIS_MODULE,
 		.of_match_table = sn65dsi84_match_table,
 	},
 	.id_table = sn65dsi84_id,
 };
 
 static int __init sn65dsi84_init(void)
 {
 	return i2c_add_driver(&sn65dsi84_i2c_driver);
 }
 
 static void __exit sn65dsi84_exit(void)
 {
 	i2c_del_driver(&sn65dsi84_i2c_driver);
 }
 
 module_init(sn65dsi84_init);
 module_exit(sn65dsi84_exit);
 
 MODULE_DESCRIPTION("TI SN65DSI84 DSI to LVDS bridge driver");
 MODULE_LICENSE("GPL v2");
 
 
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 4a3f68a33..6d6ed9d2c 100644
--- a/drivers/gpu/drm/drm_modes.c
    b/drivers/gpu/drm/drm_modes.c
@@ -1340,7  1340,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 	bool yres_specified = false, cvt = false, rb = false;
 	bool interlace = false, margins = false, was_digit = false;
 	int i;
-	enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
 	enum drm_connector_force force = DRM_FORCE_ON;
 
 #ifdef CONFIG_FB
 	if (!mode_option)
diff --git a/drivers/gpu/drm/drm_notify.c b/drivers/gpu/drm/drm_notify.c
new file mode 100644
index 000000000..f5d46f375
--- /dev/null
    b/drivers/gpu/drm/drm_notify.c
@@ -0,0  1,43 @@
 // SPDX-License-Identifier: (GPL-2.0 )
 /*
  *  linux/drivers/gpu/drm/drm_notify.c
  *
  *  Based on:
  *  linux/drivers/video/fb_notify.c
  *
  *  Copyright (C) 2018 Boundary Devices LLC
  */
 #include <linux/notifier.h>
 #include <linux/export.h>
 
 static BLOCKING_NOTIFIER_HEAD(drm_notifier_list);
 
 /**
  *	drm_register_client - register a client notifier
  *	@nb: notifier block to callback on events
  */
 int drm_register_client(struct notifier_block *nb)
 {
 	return blocking_notifier_chain_register(&drm_notifier_list, nb);
 }
 EXPORT_SYMBOL(drm_register_client);
 
 /**
  *	drm_unregister_client - unregister a client notifier
  *	@nb: notifier block to callback on events
  */
 int drm_unregister_client(struct notifier_block *nb)
 {
 	return blocking_notifier_chain_unregister(&drm_notifier_list, nb);
 }
 EXPORT_SYMBOL(drm_unregister_client);
 
 /**
  * drm_notifier_call_chain - notify clients of events
  *
  */
 int drm_notifier_call_chain(unsigned long val, void *v)
 {
 	return blocking_notifier_call_chain(&drm_notifier_list, val, v);
 }
 EXPORT_SYMBOL_GPL(drm_notifier_call_chain);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 59be1232d..8f1e7839f 100644
--- a/include/drm/drmP.h
    b/include/drm/drmP.h
@@ -348,4  348,8 @@ static __inline__ bool drm_can_sleep(void)
 /* helper for handling conditionals in various for_each macros */
 #define for_each_if(condition) if (!(condition)) {} else
 
 extern int drm_register_client(struct notifier_block *nb);
 extern int drm_unregister_client(struct notifier_block *nb);
 extern int drm_notifier_call_chain(unsigned long val, void *v);
 
 #endif