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 显示集成

Guru**** 2551110 points
Other Parts Discussed in Thread: SN65DSI83

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/interface-group/interface/f/interface-forum/1019343/sn65dsi83-imx8m-mini-evk-lvds-display-integration

器件型号:SN65DSI83
主题中讨论的其他器件: SN65DSI84

尊敬的先生/女士:

            我正在 Linux 环境中使用 NXP IMX8M Mini EVK 板。 我们正在使用 PANASYS LVDS 显示屏作为定制显示屏、为了将 MIPI-DSI 数据线路转换为 LVDS 数据、我们使用 SN65DSI83作为桥接转换器。 我们在该位置添加了带有桥参数的驱动程序(drivers/GPU/DRM/BRIDE/BRIDE/sn65dsi83)、并在位于该位置的 imx8mm-EVK-DTS 文件(arch/arm64/boot/dts/Freescale)中添加了显示参数。 添加网桥驱动程序和 DTS 文件后、我们无法在 EVK 上看到任何显示。 在这里、我将共享引导日志和 DTS 文件以及补丁。

// 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

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    您能否共享 PANASYS LVDS 显示 面板数据表?

    您是否有一个 I2C 控制器可以读取 DSI83寄存器并确保对寄存器进行正确编程?

    此外、如果您打开 DSI83测试图案、它是否会显示在显示屏上?

    谢谢

    David  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我将共享 PANASYS LVDS 显示数据表、我们将通过 MIPI-DSI 通道和 i2c 协议与显示屏通信、它不会在 DSI 测试 patterne2e.ti.com/.../AD_2D00_0037.pdf 上显示

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    e2e.ti.com/.../NMLCD_2D00_1041024768_2D00_LVDS.pdf

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、先生、

        您能否共享要在 NXP IMX8M Mini EVK Yocto 中更新 i2c 寄存器值的路径

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    您能否查看 NXP、因为我不熟悉  NXP IMX8M Mini EVK Yocto?

    谢谢

    David