Skip to contentSkip to conversation

drm: add constant N value in helper file

PATCH In review Chandan Uddaraju 8 participants 22 messages Dec 2, 2019 – Mar 3, 2020 7 messages not in the archive Page 1 of 2

Subsystems (7)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH v3 1/5 dt-bindings: msm/dp: add bindings of DP/DP-PLL driver for Snapdragon 845

Add bindings for Snapdragon 845 DisplayPort and
display-port PLL driver.

Changes in V2:
Provide details about sel-gpio

---
 .../devicetree/bindings/display/msm/dp.txt         | 249 +++++++++++++++++++++
 .../devicetree/bindings/display/msm/dpu.txt        |  16 +-
 2 files changed, 261 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/msm/dp.txt
Documentation/devicetree/bindings/display/msm/dp.txt new file +249 -0
new file mode 100644
index 0000000..38be36d
@@ -0,0 +1,249 @@
+Qualcomm Technologies, Inc.
+DP is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification.
+DP Controller: Required properties:
+- compatible:           Should be "qcom,dp-display".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the controller instance.
+- reg-names:            A list of strings that name the list of regs.
+			"dp_ahb" - DP controller memory region.
+			"dp_aux" - DP AUX memory region.
+			"dp_link" - DP link layer memory region.
+			"dp_p0" - DP pixel clock domain memory region.
+			"dp_phy" - DP PHY memory region.
+			"dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region.
+			"dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region.
+			"dp_mmss_cc" - Display Clock Control memory region.
+			"qfprom_physical" - QFPROM Phys memory region.
+			"dp_pll" - USB3 DP combo PLL memory region.
+			"usb3_dp_com" - USB3 DP PHY combo memory region.
+			"hdcp_physical" - DP HDCP memory region.
+- interrupt-parent	phandle to the interrupt parent device node.
+- interrupts:		The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+			"core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk",
+			"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent".
+- pll-node:		phandle to DP PLL node.
+- vdda-1p2-supply:		phandle to vdda 1.2V regulator node.
+- vdda-0p9-supply:		phandle to vdda 0.9V regulator node.
+- qcom,aux-cfg0-settings:		Specifies the DP AUX configuration 0 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg1-settings:		Specifies the DP AUX configuration 1 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg2-settings:		Specifies the DP AUX configuration 2 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg3-settings:		Specifies the DP AUX configuration 3 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg4-settings:		Specifies the DP AUX configuration 4 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg5-settings:		Specifies the DP AUX configuration 5 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg6-settings:		Specifies the DP AUX configuration 6 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg7-settings:		Specifies the DP AUX configuration 7 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg8-settings:		Specifies the DP AUX configuration 8 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg9-settings:		Specifies the DP AUX configuration 9 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,max-pclk-frequency-khz:	An integer specifying the maximum. pixel clock in KHz supported by Display Port.
+- extcon:				Phandle for the external connector class interface.
+- qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the a particular "type" of DP module. The module "types"
+					can be "core", "ctrl", and "phy". Within the same type,
+					there can be more than one instance of this binding,
+					in which case the entry would be appended with the
+					supply entry index.
+					e.g. qcom,ctrl-supply-entry@0
+					-- qcom,supply-name: name of the supply (vdd/vdda/vddio)
+					-- qcom,supply-min-voltage: minimum voltage level (uV)
+					-- qcom,supply-max-voltage: maximum voltage level (uV)
+					-- qcom,supply-enable-load: load drawn (uA) from enabled supply
+					-- qcom,supply-disable-load: load drawn (uA) from disabled supply
+					-- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
+					-- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
+					-- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
+					-- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
+- pinctrl-names:	List of names to assign mdss pin states defined in pinctrl device node
+					Refer to pinctrl-bindings.txt
+- pinctrl-<0..n>:	Lists phandles each pointing to the pin configuration node within a pin
+					controller. These pin configurations are installed in the pinctrl
+					device node. Refer to pinctrl-bindings.txt
+DP Endpoint properties:
+  - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's
+    input endpoint. For port@1, set to the DPU interface output. See [2] for
+    device graph info.
+
+Optional properties:
+- qcom,aux-en-gpio:		Specifies the aux-channel enable gpio.
+- qcom,aux-sel-gpio:		Specifies the mux-selection that might be needed for aux interface.
+
+
+DP PLL: Required properties:
+- compatible:           Should be "qcom,dp-pll-10nm".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the PLL instance.
+- reg-names:            A list of strings that name the list of regs.
+			"pll_base" - DP PLL memory region.
+			"phy_base" - DP PHY memory region.
+			"ln_tx0_base" - USB3 DP PHY combo TX-0 lane memory region.
+			"ln_tx1_base" - USB3 DP PHY combo TX-1 lane memory region.
+			"gdsc_base" - gdsc memory region.
+- interrupt-parent	phandle to the interrupt parent device node.
+- interrupts:		The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+			"iface_clk", "ref_clk", cfg_ahb_clk", "pipe_clk".
+- clock-rate:           Initial clock rate to be configured. For the shared clocks, the default value			     is set to zero so that minimum clock value is configured. Non-zero clock
+			value can be used to configure DP pixel clock.
+
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/graph.txt
+
+Example:
+	msm_dp: dp_display@ae90000{
+		cell-index = <0>;
+		compatible = "qcom,dp-display";
+
+		reg =   <0 0x90000 0x0dc>,
+			<0 0x90200 0x0c0>,
+			<0 0x90400 0x508>,
+			<0 0x90a00 0x094>,
+			<1 0xeaa00 0x200>,
+			<1 0xea200 0x200>,
+			<1 0xea600 0x200>,
+			<2 0x02000 0x1a0>,
+			<3 0x00000 0x621c>,
+			<1 0xea000 0x180>,
+			<1 0xe8000 0x20>,
+			<4 0xe1000 0x034>;
+		reg-names = "dp_ahb", "dp_aux", "dp_link",
+			"dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+			"dp_mmss_cc", "qfprom_physical", "dp_pll",
+			"usb3_dp_com", "hdcp_physical";
+
+		interrupt-parent = <&mdss>;
+		interrupts = <12 0>;
+
+		extcon = <&usb_1_ssphy>;
+		clocks =  <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+			<&rpmhcc RPMH_CXO_CLK>,
+			<&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			<&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+		clock-names = "core_aux_clk", "core_ref_clk_src",
+			"core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk",
+			"ctrl_link_iface_clk", "ctrl_pixel_clk",
+			"crypto_clk", "pixel_clk_rcg";
+
+		pll-node = <&dp_pll>;
+		qcom,aux-cfg0-settings = [20 00];
+		qcom,aux-cfg1-settings = [24 13 23 1d];
+		qcom,aux-cfg2-settings = [28 24];
+		qcom,aux-cfg3-settings = [2c 00];
+		qcom,aux-cfg4-settings = [30 0a];
+		qcom,aux-cfg5-settings = [34 26];
+		qcom,aux-cfg6-settings = [38 0a];
+		qcom,aux-cfg7-settings = [3c 03];
+		qcom,aux-cfg8-settings = [40 bb];
+		qcom,aux-cfg9-settings = [44 03];
+
+		qcom,max-pclk-frequency-khz = <675000>;
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-1p2";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <21800>;
+				qcom,supply-disable-load = <4>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-0p9";
+				qcom,supply-min-voltage = <880000>;
+				qcom,supply-max-voltage = <880000>;
+				qcom,supply-enable-load = <36000>;
+				qcom,supply-disable-load = <32>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				dp_in: endpoint {
+					remote-endpoint = <&dpu_intf0_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				dp_out: endpoint {
+				};
+			};
+		};
+	};
+
+	dp_pll: dp-pll@c011000 {
+		compatible = "qcom,dp-pll-10nm";
+		label = "DP PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <1 0xea000 0x200>,
+		      <1 0xeaa00 0x200>,
+		      <1 0xea200 0x200>,
+		      <1 0xea600 0x200>,
+		      <2 0x03000 0x8>;
+		reg-names = "pll_base", "phy_base", "ln_tx0_base",
+			"ln_tx1_base", "gdsc_base";
+
+		clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+			 <&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			 <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			 <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+		clock-names = "iface_clk", "ref_clk",
+			"cfg_ahb_clk", "pipe_clk";
+		clock-rate = <0>;
+
+	};
Documentation/devicetree/bindings/display/msm/dpu.txt +12 -4
index a61dd40..eac6e1c 100644
@@ -63,8 +63,9 @@ Required properties:
 	Documentation/devicetree/bindings/graph.txt
 	Documentation/devicetree/bindings/media/video-interfaces.txt
 
-	Port 0 -> DPU_INTF1 (DSI1)
-	Port 1 -> DPU_INTF2 (DSI2)
+	Port 0 -> DPU_INTF0 (DP)
+	Port 1 -> DPU_INTF1 (DSI1)
+	Port 2 -> DPU_INTF2 (DSI2)
 
 Optional properties:
 - assigned-clocks: list of clock specifiers for clocks needing rate assignment
@@ -125,13 +126,20 @@ Example:
 
 				port@0 {
 					reg = <0>;
-					dpu_intf1_out: endpoint {
-						remote-endpoint = <&dsi0_in>;
+					dpu_intf0_out: endpoint {
+						remote-endpoint = <&dp_in>;
 					};
 				};
 
 				port@1 {
 					reg = <1>;
+					dpu_intf1_out: endpoint {
+						remote-endpoint = <&dsi0_in>;
+					};
+				};
+
+				port@2 {
+					reg = <2>;
 					dpu_intf2_out: endpoint {
 						remote-endpoint = <&dsi1_in>;
 					};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
maintainer
#2 lore raw

Re: [DPU PATCH v3 1/5] dt-bindings: msm/dp: add bindings of DP/DP-PLL driver for Snapdragon 845

Quoted 2 lines · Chandan Uddaraju

Add bindings for Snapdragon 845 DisplayPort and
display-port PLL driver.

Is it just me, but I keep getting 2 copies of codeaurora emails?

Quoted 3 lines

Changes in V2:
Provide details about sel-gpio

This is V3, what changed in V3?

Quoted 7 lines
---
 .../devicetree/bindings/display/msm/dp.txt         | 249 +++++++++++++++++++++
 .../devicetree/bindings/display/msm/dpu.txt        |  16 +-
 2 files changed, 261 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/msm/dp.txt

New bindings should be in DT schema format.

Documentation/devicetree/bindings/display/msm/dp.txt line 4

Quoted 10 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +4 -0
new file mode 100644
index 0000000..38be36d
@@ -0,0 +1,249 @@
+Qualcomm Technologies, Inc.
+DP is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification.
+DP Controller: Required properties:
+- compatible:           Should be "qcom,dp-display".

Needs to be more specific like including the SoC name.

Documentation/devicetree/bindings/display/msm/dp.txt line 6

Quoted 2 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +2 -0
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the controller instance.

FDT doesn't use cell-index.

Documentation/devicetree/bindings/display/msm/dp.txt line 15

Quoted 9 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +9 -0
+- reg-names:            A list of strings that name the list of regs.
+			"dp_ahb" - DP controller memory region.
+			"dp_aux" - DP AUX memory region.
+			"dp_link" - DP link layer memory region.
+			"dp_p0" - DP pixel clock domain memory region.
+			"dp_phy" - DP PHY memory region.
+			"dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region.
+			"dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region.
+			"dp_mmss_cc" - Display Clock Control memory region.

Sounds like a separate clock controller node...

Documentation/devicetree/bindings/display/msm/dp.txt line 18

Quoted 3 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +3 -0
+			"qfprom_physical" - QFPROM Phys memory region.
+			"dp_pll" - USB3 DP combo PLL memory region.
+			"usb3_dp_com" - USB3 DP PHY combo memory region.

Should be a separate phy node?

Documentation/devicetree/bindings/display/msm/dp.txt line 19

Quoted 1 line
Documentation/devicetree/bindings/display/msm/dp.txt new file +1 -0
+			"hdcp_physical" - DP HDCP memory region.

The 'dp_' part is redundant.

What does 'physical' mean? Addresses in DT are always physical.

Documentation/devicetree/bindings/display/msm/dp.txt line 20

Quoted 1 line
Documentation/devicetree/bindings/display/msm/dp.txt new file +1 -0
+- interrupt-parent	phandle to the interrupt parent device node.

Don't document interrupt-parent. It's not required either because it could be in a parent node.

Documentation/devicetree/bindings/display/msm/dp.txt line 26

Quoted 6 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +6 -0
+- interrupts:		The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+			"core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk",
+			"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent".

Clocks should be actual clock inputs to the module. If 'pixel_parent' is just some parent clock you want to assign, then use assigned-clocks.

Documentation/devicetree/bindings/display/msm/dp.txt line 27

Quoted 1 line
Documentation/devicetree/bindings/display/msm/dp.txt new file +1 -0
+- pll-node:		phandle to DP PLL node.

But you have a DP PLL reg region defined. Is this something else?

Needs a 'qcom' prefix if it stays.

Documentation/devicetree/bindings/display/msm/dp.txt line 33

Quoted 6 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +6 -0
+- vdda-1p2-supply:		phandle to vdda 1.2V regulator node.
+- vdda-0p9-supply:		phandle to vdda 0.9V regulator node.
+- qcom,aux-cfg0-settings:		Specifies the DP AUX configuration 0 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.

Needs more details on what these are and why they must be in DT. We generally don't just stuff DT with raw values to initial registers with.

Line lengths should be <80 char.

Quoted 27 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +27 -0
+- qcom,aux-cfg1-settings:		Specifies the DP AUX configuration 1 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg2-settings:		Specifies the DP AUX configuration 2 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg3-settings:		Specifies the DP AUX configuration 3 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg4-settings:		Specifies the DP AUX configuration 4 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg5-settings:		Specifies the DP AUX configuration 5 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg6-settings:		Specifies the DP AUX configuration 6 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg7-settings:		Specifies the DP AUX configuration 7 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the

Documentation/devicetree/bindings/display/msm/dp.txt line 70

Quoted 10 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +10 -0
+					programmable values.
+- qcom,aux-cfg8-settings:		Specifies the DP AUX configuration 8 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg9-settings:		Specifies the DP AUX configuration 9 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,max-pclk-frequency-khz:	An integer specifying the maximum. pixel clock in KHz supported by Display Port.

Wrap your lines.

Documentation/devicetree/bindings/display/msm/dp.txt line 71

Quoted 1 line
Documentation/devicetree/bindings/display/msm/dp.txt new file +1 -0
+- extcon:				Phandle for the external connector class interface.

Don't use extcon. Either dp-connector or usb-connector binding instead.

Quoted 5 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +5 -0
+- qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the a particular "type" of DP module. The module "types"
+					can be "core", "ctrl", and "phy". Within the same type,
+					there can be more than one instance of this binding,
+					in which case the entry would be appended with the
+					supply entry index.

Documentation/devicetree/bindings/display/msm/dp.txt line 86

Quoted 10 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +10 -0
+					e.g. qcom,ctrl-supply-entry@0
+					-- qcom,supply-name: name of the supply (vdd/vdda/vddio)
+					-- qcom,supply-min-voltage: minimum voltage level (uV)
+					-- qcom,supply-max-voltage: maximum voltage level (uV)
+					-- qcom,supply-enable-load: load drawn (uA) from enabled supply
+					-- qcom,supply-disable-load: load drawn (uA) from disabled supply
+					-- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
+					-- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
+					-- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
+					-- qcom,supply-post-off-sleep: time to sleep (ms) after turning off

Not sure what you're trying to do here, but looks like the regulator binding should be used.

Documentation/devicetree/bindings/display/msm/dp.txt line 99

Quoted 13 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +13 -0
+- pinctrl-names:	List of names to assign mdss pin states defined in pinctrl device node
+					Refer to pinctrl-bindings.txt
+- pinctrl-<0..n>:	Lists phandles each pointing to the pin configuration node within a pin
+					controller. These pin configurations are installed in the pinctrl
+					device node. Refer to pinctrl-bindings.txt
+DP Endpoint properties:
+  - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's
+    input endpoint. For port@1, set to the DPU interface output. See [2] for
+    device graph info.
+
+Optional properties:
+- qcom,aux-en-gpio:		Specifies the aux-channel enable gpio.
+- qcom,aux-sel-gpio:		Specifies the mux-selection that might be needed for aux interface.

-gpios is the preferred form.

Documentation/devicetree/bindings/display/msm/dp.txt line 102

Quoted 3 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +3 -0
+
+
+DP PLL: Required properties:

Should be a separate doc.

Quoted 152 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +147 -0
+- compatible:           Should be "qcom,dp-pll-10nm".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the PLL instance.
+- reg-names:            A list of strings that name the list of regs.
+			"pll_base" - DP PLL memory region.
+			"phy_base" - DP PHY memory region.
+			"ln_tx0_base" - USB3 DP PHY combo TX-0 lane memory region.
+			"ln_tx1_base" - USB3 DP PHY combo TX-1 lane memory region.
+			"gdsc_base" - gdsc memory region.
+- interrupt-parent	phandle to the interrupt parent device node.
+- interrupts:		The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+			"iface_clk", "ref_clk", cfg_ahb_clk", "pipe_clk".
+- clock-rate:           Initial clock rate to be configured. For the shared clocks, the default value			     is set to zero so that minimum clock value is configured. Non-zero clock
+			value can be used to configure DP pixel clock.
+
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/graph.txt
+
+Example:
+	msm_dp: dp_display@ae90000{
+		cell-index = <0>;
+		compatible = "qcom,dp-display";
+
+		reg =   <0 0x90000 0x0dc>,
+			<0 0x90200 0x0c0>,
+			<0 0x90400 0x508>,
+			<0 0x90a00 0x094>,
+			<1 0xeaa00 0x200>,
+			<1 0xea200 0x200>,
+			<1 0xea600 0x200>,
+			<2 0x02000 0x1a0>,
+			<3 0x00000 0x621c>,
+			<1 0xea000 0x180>,
+			<1 0xe8000 0x20>,
+			<4 0xe1000 0x034>;
+		reg-names = "dp_ahb", "dp_aux", "dp_link",
+			"dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+			"dp_mmss_cc", "qfprom_physical", "dp_pll",
+			"usb3_dp_com", "hdcp_physical";
+
+		interrupt-parent = <&mdss>;
+		interrupts = <12 0>;
+
+		extcon = <&usb_1_ssphy>;
+		clocks =  <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+			<&rpmhcc RPMH_CXO_CLK>,
+			<&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			<&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+		clock-names = "core_aux_clk", "core_ref_clk_src",
+			"core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk",
+			"ctrl_link_iface_clk", "ctrl_pixel_clk",
+			"crypto_clk", "pixel_clk_rcg";
+
+		pll-node = <&dp_pll>;
+		qcom,aux-cfg0-settings = [20 00];
+		qcom,aux-cfg1-settings = [24 13 23 1d];
+		qcom,aux-cfg2-settings = [28 24];
+		qcom,aux-cfg3-settings = [2c 00];
+		qcom,aux-cfg4-settings = [30 0a];
+		qcom,aux-cfg5-settings = [34 26];
+		qcom,aux-cfg6-settings = [38 0a];
+		qcom,aux-cfg7-settings = [3c 03];
+		qcom,aux-cfg8-settings = [40 bb];
+		qcom,aux-cfg9-settings = [44 03];
+
+		qcom,max-pclk-frequency-khz = <675000>;
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-1p2";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <21800>;
+				qcom,supply-disable-load = <4>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-0p9";
+				qcom,supply-min-voltage = <880000>;
+				qcom,supply-max-voltage = <880000>;
+				qcom,supply-enable-load = <36000>;
+				qcom,supply-disable-load = <32>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				dp_in: endpoint {
+					remote-endpoint = <&dpu_intf0_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				dp_out: endpoint {
+				};
+			};
+		};
+	};
+
+	dp_pll: dp-pll@c011000 {
+		compatible = "qcom,dp-pll-10nm";
+		label = "DP PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <1 0xea000 0x200>,
+		      <1 0xeaa00 0x200>,
+		      <1 0xea200 0x200>,
+		      <1 0xea600 0x200>,
+		      <2 0x03000 0x8>;
+		reg-names = "pll_base", "phy_base", "ln_tx0_base",
+			"ln_tx1_base", "gdsc_base";
+
+		clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+			 <&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			 <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			 <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+		clock-names = "iface_clk", "ref_clk",
+			"cfg_ahb_clk", "pipe_clk";
+		clock-rate = <0>;
+
+	};
Documentation/devicetree/bindings/display/msm/dpu.txt +0 -0
index a61dd40..eac6e1c 100644

Documentation/devicetree/bindings/display/msm/dpu.txt Required properties: · line 68

Quoted 8 lines
Documentation/devicetree/bindings/display/msm/dpu.txt +3 -2
@@ -63,8 +63,9 @@ Required properties:
 	Documentation/devicetree/bindings/graph.txt
 	Documentation/devicetree/bindings/media/video-interfaces.txt
 
-	Port 0 -> DPU_INTF1 (DSI1)
-	Port 1 -> DPU_INTF2 (DSI2)
+	Port 0 -> DPU_INTF0 (DP)
+	Port 1 -> DPU_INTF1 (DSI1)
+	Port 2 -> DPU_INTF2 (DSI2)

No, you can't redefine existing binding.

Quoted 30 lines
Documentation/devicetree/bindings/display/msm/dpu.txt +9 -2
 Optional properties:
 - assigned-clocks: list of clock specifiers for clocks needing rate assignment
@@ -125,13 +126,20 @@ Example:
 
 				port@0 {
 					reg = <0>;
-					dpu_intf1_out: endpoint {
-						remote-endpoint = <&dsi0_in>;
+					dpu_intf0_out: endpoint {
+						remote-endpoint = <&dp_in>;
 					};
 				};
 
 				port@1 {
 					reg = <1>;
+					dpu_intf1_out: endpoint {
+						remote-endpoint = <&dsi0_in>;
+					};
+				};
+
+				port@2 {
+					reg = <2>;
 					dpu_intf2_out: endpoint {
 						remote-endpoint = <&dsi1_in>;
 					};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
#3 lore raw

Re: [DPU PATCH v3 1/5] dt-bindings: msm/dp: add bindings of DP/DP-PLL driver for Snapdragon 845

In reply to Chandan Uddaraju
Quoted 128 lines · Chandan Uddaraju

Add bindings for Snapdragon 845 DisplayPort and
display-port PLL driver.

Changes in V2:
Provide details about sel-gpio

---
 .../devicetree/bindings/display/msm/dp.txt         | 249 +++++++++++++++++++++
 .../devicetree/bindings/display/msm/dpu.txt        |  16 +-
 2 files changed, 261 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/msm/dp.txt
Documentation/devicetree/bindings/display/msm/dp.txt new file +108 -0
new file mode 100644
index 0000000..38be36d
@@ -0,0 +1,249 @@
+Qualcomm Technologies, Inc.
+DP is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification.
+DP Controller: Required properties:
+- compatible:           Should be "qcom,dp-display".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the controller instance.
+- reg-names:            A list of strings that name the list of regs.
+                       "dp_ahb" - DP controller memory region.
+                       "dp_aux" - DP AUX memory region.
+                       "dp_link" - DP link layer memory region.
+                       "dp_p0" - DP pixel clock domain memory region.
+                       "dp_phy" - DP PHY memory region.
+                       "dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region.
+                       "dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region.
+                       "dp_mmss_cc" - Display Clock Control memory region.
+                       "qfprom_physical" - QFPROM Phys memory region.
+                       "dp_pll" - USB3 DP combo PLL memory region.
+                       "usb3_dp_com" - USB3 DP PHY combo memory region.
+                       "hdcp_physical" - DP HDCP memory region.
+- interrupt-parent     phandle to the interrupt parent device node.
+- interrupts:          The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+                       "core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+                       "core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk",
+                       "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent".
+- pll-node:            phandle to DP PLL node.
+- vdda-1p2-supply:             phandle to vdda 1.2V regulator node.
+- vdda-0p9-supply:             phandle to vdda 0.9V regulator node.
+- qcom,aux-cfg0-settings:              Specifies the DP AUX configuration 0 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg1-settings:              Specifies the DP AUX configuration 1 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg2-settings:              Specifies the DP AUX configuration 2 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg3-settings:              Specifies the DP AUX configuration 3 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg4-settings:              Specifies the DP AUX configuration 4 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg5-settings:              Specifies the DP AUX configuration 5 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg6-settings:              Specifies the DP AUX configuration 6 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg7-settings:              Specifies the DP AUX configuration 7 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg8-settings:              Specifies the DP AUX configuration 8 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,aux-cfg9-settings:              Specifies the DP AUX configuration 9 settings. The first
+                                       entry in this array corresponds to the register offset
+                                       within DP AUX, while the remaining entries indicate the
+                                       programmable values.
+- qcom,max-pclk-frequency-khz: An integer specifying the maximum. pixel clock in KHz supported by Display Port.
+- extcon:                              Phandle for the external connector class interface.
+- qcom,<type>-supply-entries:          A node that lists the elements of the supply used by the a particular "type" of DP module. The module "types"
+                                       can be "core", "ctrl", and "phy". Within the same type,
+                                       there can be more than one instance of this binding,
+                                       in which case the entry would be appended with the
+                                       supply entry index.
+                                       e.g. qcom,ctrl-supply-entry@0
+                                       -- qcom,supply-name: name of the supply (vdd/vdda/vddio)
+                                       -- qcom,supply-min-voltage: minimum voltage level (uV)
+                                       -- qcom,supply-max-voltage: maximum voltage level (uV)
+                                       -- qcom,supply-enable-load: load drawn (uA) from enabled supply
+                                       -- qcom,supply-disable-load: load drawn (uA) from disabled supply
+                                       -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
+                                       -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
+                                       -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
+                                       -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
+- pinctrl-names:       List of names to assign mdss pin states defined in pinctrl device node
+                                       Refer to pinctrl-bindings.txt
+- pinctrl-<0..n>:      Lists phandles each pointing to the pin configuration node within a pin
+                                       controller. These pin configurations are installed in the pinctrl
+                                       device node. Refer to pinctrl-bindings.txt
+DP Endpoint properties:
+  - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's
+    input endpoint. For port@1, set to the DPU interface output. See [2] for
+    device graph info.
+
+Optional properties:
+- qcom,aux-en-gpio:            Specifies the aux-channel enable gpio.
+- qcom,aux-sel-gpio:           Specifies the mux-selection that might be needed for aux interface.
+
+
+DP PLL: Required properties:
+- compatible:           Should be "qcom,dp-pll-10nm".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the PLL instance.
+- reg-names:            A list of strings that name the list of regs.
+                       "pll_base" - DP PLL memory region.
+                       "phy_base" - DP PHY memory region.

Documentation/devicetree/bindings/display/msm/dp.txt line 118

Quoted 10 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +10 -0
+                       "ln_tx0_base" - USB3 DP PHY combo TX-0 lane memory region.
+                       "ln_tx1_base" - USB3 DP PHY combo TX-1 lane memory region.
+                       "gdsc_base" - gdsc memory region.
+- interrupt-parent     phandle to the interrupt parent device node.
+- interrupts:          The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+                       "iface_clk", "ref_clk", cfg_ahb_clk", "pipe_clk".
+- clock-rate:           Initial clock rate to be configured. For the shared clocks, the default value                       is set to zero so that minimum clock value is configured. Non-zero clock
+                       value can be used to configure DP pixel clock.

This should be a clock provider, no?

Quoted 174 lines
Documentation/devicetree/bindings/display/msm/dp.txt new file +131 -0
+
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/graph.txt
+
+Example:
+       msm_dp: dp_display@ae90000{
+               cell-index = <0>;
+               compatible = "qcom,dp-display";
+
+               reg =   <0 0x90000 0x0dc>,
+                       <0 0x90200 0x0c0>,
+                       <0 0x90400 0x508>,
+                       <0 0x90a00 0x094>,
+                       <1 0xeaa00 0x200>,
+                       <1 0xea200 0x200>,
+                       <1 0xea600 0x200>,
+                       <2 0x02000 0x1a0>,
+                       <3 0x00000 0x621c>,
+                       <1 0xea000 0x180>,
+                       <1 0xe8000 0x20>,
+                       <4 0xe1000 0x034>;
+               reg-names = "dp_ahb", "dp_aux", "dp_link",
+                       "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+                       "dp_mmss_cc", "qfprom_physical", "dp_pll",
+                       "usb3_dp_com", "hdcp_physical";
+
+               interrupt-parent = <&mdss>;
+               interrupts = <12 0>;
+
+               extcon = <&usb_1_ssphy>;
+               clocks =  <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+                       <&rpmhcc RPMH_CXO_CLK>,
+                       <&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+                       <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+                       <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+                       <&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+                       <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+                       <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+                       <&dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+                       <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+               clock-names = "core_aux_clk", "core_ref_clk_src",
+                       "core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+                       "core_usb_pipe_clk", "ctrl_link_clk",
+                       "ctrl_link_iface_clk", "ctrl_pixel_clk",
+                       "crypto_clk", "pixel_clk_rcg";
+
+               pll-node = <&dp_pll>;
+               qcom,aux-cfg0-settings = [20 00];
+               qcom,aux-cfg1-settings = [24 13 23 1d];
+               qcom,aux-cfg2-settings = [28 24];
+               qcom,aux-cfg3-settings = [2c 00];
+               qcom,aux-cfg4-settings = [30 0a];
+               qcom,aux-cfg5-settings = [34 26];
+               qcom,aux-cfg6-settings = [38 0a];
+               qcom,aux-cfg7-settings = [3c 03];
+               qcom,aux-cfg8-settings = [40 bb];
+               qcom,aux-cfg9-settings = [44 03];
+
+               qcom,max-pclk-frequency-khz = <675000>;
+
+               qcom,ctrl-supply-entries {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       qcom,ctrl-supply-entry@0 {
+                               reg = <0>;
+                               qcom,supply-name = "vdda-1p2";
+                               qcom,supply-min-voltage = <1200000>;
+                               qcom,supply-max-voltage = <1200000>;
+                               qcom,supply-enable-load = <21800>;
+                               qcom,supply-disable-load = <4>;
+                       };
+               };
+
+               qcom,phy-supply-entries {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       qcom,phy-supply-entry@0 {
+                               reg = <0>;
+                               qcom,supply-name = "vdda-0p9";
+                               qcom,supply-min-voltage = <880000>;
+                               qcom,supply-max-voltage = <880000>;
+                               qcom,supply-enable-load = <36000>;
+                               qcom,supply-disable-load = <32>;
+                       };
+               };
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               dp_in: endpoint {
+                                       remote-endpoint = <&dpu_intf0_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               dp_out: endpoint {
+                               };
+                       };
+               };
+       };
+
+       dp_pll: dp-pll@c011000 {
+               compatible = "qcom,dp-pll-10nm";
+               label = "DP PLL";
+               cell-index = <0>;
+               #clock-cells = <1>;
+
+               reg = <1 0xea000 0x200>,
+                     <1 0xeaa00 0x200>,
+                     <1 0xea200 0x200>,
+                     <1 0xea600 0x200>,
+                     <2 0x03000 0x8>;
+               reg-names = "pll_base", "phy_base", "ln_tx0_base",
+                       "ln_tx1_base", "gdsc_base";
+
+               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                        <&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+                        <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+                        <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+               clock-names = "iface_clk", "ref_clk",
+                       "cfg_ahb_clk", "pipe_clk";
+               clock-rate = <0>;
+
+       };
Documentation/devicetree/bindings/display/msm/dpu.txt +12 -5
index a61dd40..eac6e1c 100644
@@ -63,8 +63,9 @@ Required properties:
        Documentation/devicetree/bindings/graph.txt
        Documentation/devicetree/bindings/media/video-interfaces.txt
 
-       Port 0 -> DPU_INTF1 (DSI1)
-       Port 1 -> DPU_INTF2 (DSI2)
+       Port 0 -> DPU_INTF0 (DP)
+       Port 1 -> DPU_INTF1 (DSI1)
+       Port 2 -> DPU_INTF2 (DSI2)
 
 Optional properties:
 - assigned-clocks: list of clock specifiers for clocks needing rate assignment
@@ -125,13 +126,20 @@ Example:
 
                                port@0 {
                                        reg = <0>;
-                                       dpu_intf1_out: endpoint {
-                                               remote-endpoint = <&dsi0_in>;
+                                       dpu_intf0_out: endpoint {
+                                               remote-endpoint = <&dp_in>;
                                        };
                                };
 
                                port@1 {
                                        reg = <1>;
+                                       dpu_intf1_out: endpoint {
+                                               remote-endpoint = <&dsi0_in>;
+                                       };
+                               };
+
+                               port@2 {
+                                       reg = <2>;
                                        dpu_intf2_out: endpoint {
                                                remote-endpoint = <&dsi1_in>;
                                        };
--

The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

A message that is not in the archive (sent off-list or not yet received): 1575294437-6129-1-git-send-email-chandanu-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org

#5 lore raw

PATCH v3 1/5 dt-bindings: msm/dp: add bindings of DP/DP-PLL driver for Snapdragon 845

Add bindings for Snapdragon 845 DisplayPort and
display-port PLL driver.

Changes in V2:
Provide details about sel-gpio

---
 .../devicetree/bindings/display/msm/dp.txt         | 249 +++++++++++++++++++++
 .../devicetree/bindings/display/msm/dpu.txt        |  16 +-
 2 files changed, 261 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/msm/dp.txt
Documentation/devicetree/bindings/display/msm/dp.txt new file +249 -0
new file mode 100644
index 0000000..38be36d
@@ -0,0 +1,249 @@
+Qualcomm Technologies, Inc.
+DP is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification.
+DP Controller: Required properties:
+- compatible:           Should be "qcom,dp-display".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the controller instance.
+- reg-names:            A list of strings that name the list of regs.
+			"dp_ahb" - DP controller memory region.
+			"dp_aux" - DP AUX memory region.
+			"dp_link" - DP link layer memory region.
+			"dp_p0" - DP pixel clock domain memory region.
+			"dp_phy" - DP PHY memory region.
+			"dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region.
+			"dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region.
+			"dp_mmss_cc" - Display Clock Control memory region.
+			"qfprom_physical" - QFPROM Phys memory region.
+			"dp_pll" - USB3 DP combo PLL memory region.
+			"usb3_dp_com" - USB3 DP PHY combo memory region.
+			"hdcp_physical" - DP HDCP memory region.
+- interrupt-parent	phandle to the interrupt parent device node.
+- interrupts:		The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+			"core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk",
+			"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent".
+- pll-node:		phandle to DP PLL node.
+- vdda-1p2-supply:		phandle to vdda 1.2V regulator node.
+- vdda-0p9-supply:		phandle to vdda 0.9V regulator node.
+- qcom,aux-cfg0-settings:		Specifies the DP AUX configuration 0 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg1-settings:		Specifies the DP AUX configuration 1 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg2-settings:		Specifies the DP AUX configuration 2 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg3-settings:		Specifies the DP AUX configuration 3 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg4-settings:		Specifies the DP AUX configuration 4 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg5-settings:		Specifies the DP AUX configuration 5 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg6-settings:		Specifies the DP AUX configuration 6 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg7-settings:		Specifies the DP AUX configuration 7 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg8-settings:		Specifies the DP AUX configuration 8 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,aux-cfg9-settings:		Specifies the DP AUX configuration 9 settings. The first
+					entry in this array corresponds to the register offset
+					within DP AUX, while the remaining entries indicate the
+					programmable values.
+- qcom,max-pclk-frequency-khz:	An integer specifying the maximum. pixel clock in KHz supported by Display Port.
+- extcon:				Phandle for the external connector class interface.
+- qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the a particular "type" of DP module. The module "types"
+					can be "core", "ctrl", and "phy". Within the same type,
+					there can be more than one instance of this binding,
+					in which case the entry would be appended with the
+					supply entry index.
+					e.g. qcom,ctrl-supply-entry@0
+					-- qcom,supply-name: name of the supply (vdd/vdda/vddio)
+					-- qcom,supply-min-voltage: minimum voltage level (uV)
+					-- qcom,supply-max-voltage: maximum voltage level (uV)
+					-- qcom,supply-enable-load: load drawn (uA) from enabled supply
+					-- qcom,supply-disable-load: load drawn (uA) from disabled supply
+					-- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
+					-- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
+					-- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
+					-- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
+- pinctrl-names:	List of names to assign mdss pin states defined in pinctrl device node
+					Refer to pinctrl-bindings.txt
+- pinctrl-<0..n>:	Lists phandles each pointing to the pin configuration node within a pin
+					controller. These pin configurations are installed in the pinctrl
+					device node. Refer to pinctrl-bindings.txt
+DP Endpoint properties:
+  - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's
+    input endpoint. For port@1, set to the DPU interface output. See [2] for
+    device graph info.
+
+Optional properties:
+- qcom,aux-en-gpio:		Specifies the aux-channel enable gpio.
+- qcom,aux-sel-gpio:		Specifies the mux-selection that might be needed for aux interface.
+
+
+DP PLL: Required properties:
+- compatible:           Should be "qcom,dp-pll-10nm".
+- reg:                  Base address and length of DP hardware's memory mapped regions.
+- cell-index:           Specifies the PLL instance.
+- reg-names:            A list of strings that name the list of regs.
+			"pll_base" - DP PLL memory region.
+			"phy_base" - DP PHY memory region.
+			"ln_tx0_base" - USB3 DP PHY combo TX-0 lane memory region.
+			"ln_tx1_base" - USB3 DP PHY combo TX-1 lane memory region.
+			"gdsc_base" - gdsc memory region.
+- interrupt-parent	phandle to the interrupt parent device node.
+- interrupts:		The interrupt signal from the DP block.
+- clocks:               Clocks required for Display Port operation. See [1] for details on clock bindings.
+- clock-names:          Names of the clocks corresponding to handles. Following clocks are required:
+			"iface_clk", "ref_clk", cfg_ahb_clk", "pipe_clk".
+- clock-rate:           Initial clock rate to be configured. For the shared clocks, the default value			     is set to zero so that minimum clock value is configured. Non-zero clock
+			value can be used to configure DP pixel clock.
+
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/graph.txt
+
+Example:
+	msm_dp: dp_display@ae90000{
+		cell-index = <0>;
+		compatible = "qcom,dp-display";
+
+		reg =   <0 0x90000 0x0dc>,
+			<0 0x90200 0x0c0>,
+			<0 0x90400 0x508>,
+			<0 0x90a00 0x094>,
+			<1 0xeaa00 0x200>,
+			<1 0xea200 0x200>,
+			<1 0xea600 0x200>,
+			<2 0x02000 0x1a0>,
+			<3 0x00000 0x621c>,
+			<1 0xea000 0x180>,
+			<1 0xe8000 0x20>,
+			<4 0xe1000 0x034>;
+		reg-names = "dp_ahb", "dp_aux", "dp_link",
+			"dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+			"dp_mmss_cc", "qfprom_physical", "dp_pll",
+			"usb3_dp_com", "hdcp_physical";
+
+		interrupt-parent = <&mdss>;
+		interrupts = <12 0>;
+
+		extcon = <&usb_1_ssphy>;
+		clocks =  <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+			<&rpmhcc RPMH_CXO_CLK>,
+			<&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			<&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+			<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+		clock-names = "core_aux_clk", "core_ref_clk_src",
+			"core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk",
+			"ctrl_link_iface_clk", "ctrl_pixel_clk",
+			"crypto_clk", "pixel_clk_rcg";
+
+		pll-node = <&dp_pll>;
+		qcom,aux-cfg0-settings = [20 00];
+		qcom,aux-cfg1-settings = [24 13 23 1d];
+		qcom,aux-cfg2-settings = [28 24];
+		qcom,aux-cfg3-settings = [2c 00];
+		qcom,aux-cfg4-settings = [30 0a];
+		qcom,aux-cfg5-settings = [34 26];
+		qcom,aux-cfg6-settings = [38 0a];
+		qcom,aux-cfg7-settings = [3c 03];
+		qcom,aux-cfg8-settings = [40 bb];
+		qcom,aux-cfg9-settings = [44 03];
+
+		qcom,max-pclk-frequency-khz = <675000>;
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-1p2";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <21800>;
+				qcom,supply-disable-load = <4>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-0p9";
+				qcom,supply-min-voltage = <880000>;
+				qcom,supply-max-voltage = <880000>;
+				qcom,supply-enable-load = <36000>;
+				qcom,supply-disable-load = <32>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				dp_in: endpoint {
+					remote-endpoint = <&dpu_intf0_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				dp_out: endpoint {
+				};
+			};
+		};
+	};
+
+	dp_pll: dp-pll@c011000 {
+		compatible = "qcom,dp-pll-10nm";
+		label = "DP PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <1 0xea000 0x200>,
+		      <1 0xeaa00 0x200>,
+		      <1 0xea200 0x200>,
+		      <1 0xea600 0x200>,
+		      <2 0x03000 0x8>;
+		reg-names = "pll_base", "phy_base", "ln_tx0_base",
+			"ln_tx1_base", "gdsc_base";
+
+		clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+			 <&gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			 <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			 <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+		clock-names = "iface_clk", "ref_clk",
+			"cfg_ahb_clk", "pipe_clk";
+		clock-rate = <0>;
+
+	};
Documentation/devicetree/bindings/display/msm/dpu.txt +12 -4
index a61dd40..eac6e1c 100644
@@ -63,8 +63,9 @@ Required properties:
 	Documentation/devicetree/bindings/graph.txt
 	Documentation/devicetree/bindings/media/video-interfaces.txt
 
-	Port 0 -> DPU_INTF1 (DSI1)
-	Port 1 -> DPU_INTF2 (DSI2)
+	Port 0 -> DPU_INTF0 (DP)
+	Port 1 -> DPU_INTF1 (DSI1)
+	Port 2 -> DPU_INTF2 (DSI2)
 
 Optional properties:
 - assigned-clocks: list of clock specifiers for clocks needing rate assignment
@@ -125,13 +126,20 @@ Example:
 
 				port@0 {
 					reg = <0>;
-					dpu_intf1_out: endpoint {
-						remote-endpoint = <&dsi0_in>;
+					dpu_intf0_out: endpoint {
+						remote-endpoint = <&dp_in>;
 					};
 				};
 
 				port@1 {
 					reg = <1>;
+					dpu_intf1_out: endpoint {
+						remote-endpoint = <&dsi0_in>;
+					};
+				};
+
+				port@2 {
+					reg = <2>;
 					dpu_intf2_out: endpoint {
 						remote-endpoint = <&dsi1_in>;
 					};
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

_______________________________________________
Freedreno mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/freedreno
#6 lore raw

PATCH v3 3/5 drm/msm/dp: add displayPort driver support

In reply to a message not in the archive

Add the needed displayPort files to enable DP driver on msm target.

"dp_display" module is the main module that calls into other sub-modules. "dp_drm" file represents the interface between DRM framework and DP driver.

changes in v2:
-- Update copyright markings on all relevant files.
-- Change pr_err() to DRM_ERROR()
-- Use APIs directly instead of function pointers.
-- Use drm_display_mode structure to store link parameters in the driver. -- Use macros for register definitions instead of hardcoded values. -- Replace writel_relaxed/readl_relaxed with writel/readl
and remove memory barriers.
-- Remove unnecessary NULL checks.
-- Use drm helper functions for dpcd read/write.
-- Use DRM_DEBUG_DP for debug msgs.

changes in V3:
-- Removed changes in dpu_io_util.[ch]
-- Added locking around "is_connected" flag and removed atomic_set() -- Removed the argument validation checks in all the static functions
except initialization functions and few API calls across msm/dp files
-- Removed hardcoded values for register reads/writes
-- Removed vreg related generic structures.
-- Added return values where ever necessary.
-- Updated dp_ctrl_on function.
-- Calling the ctrl specific catalog functions directly instead of
function pointers.
-- Added seperate change that adds standard value in drm_dp_helper file. -- Added separate change in this list that is used to initialize
displayport in DPU driver.
-- Added change to use drm_dp_get_adjust_request_voltage() function.

---
 drivers/gpu/drm/msm/Kconfig                 |    9 +
 drivers/gpu/drm/msm/Makefile                |   13 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |   20 +
 drivers/gpu/drm/msm/dp/dp_aux.c             |  548 +++++++++
 drivers/gpu/drm/msm/dp/dp_aux.h             |   37 +
 drivers/gpu/drm/msm/dp/dp_catalog.c         |  841 ++++++++++++++
 drivers/gpu/drm/msm/dp/dp_catalog.h         |   84 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c            | 1590 +++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_ctrl.h            |   34 +
 drivers/gpu/drm/msm/dp/dp_display.c         |  949 ++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_display.h         |   29 +
 drivers/gpu/drm/msm/dp/dp_drm.c             |  173 +++
 drivers/gpu/drm/msm/dp/dp_drm.h             |   20 +
 drivers/gpu/drm/msm/dp/dp_extcon.c          |  216 ++++
 drivers/gpu/drm/msm/dp/dp_extcon.h          |   84 ++
 drivers/gpu/drm/msm/dp/dp_link.c            | 1185 ++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_link.h            |  132 +++
 drivers/gpu/drm/msm/dp/dp_panel.c           |  450 ++++++++
 drivers/gpu/drm/msm/dp/dp_panel.h           |   92 ++
 drivers/gpu/drm/msm/dp/dp_parser.c          |  496 +++++++++
 drivers/gpu/drm/msm/dp/dp_parser.h          |  222 ++++
 drivers/gpu/drm/msm/dp/dp_power.c           |  558 ++++++++++
 drivers/gpu/drm/msm/dp/dp_power.h           |   52 +
 drivers/gpu/drm/msm/dp/dp_reg.h             |  488 ++++++++
 drivers/gpu/drm/msm/msm_drv.c               |    2 +
 drivers/gpu/drm/msm/msm_drv.h               |   42 +
 26 files changed, 8366 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_display.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_display.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_drm.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_drm.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_extcon.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_extcon.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_link.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_link.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_panel.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_panel.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_parser.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_parser.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_power.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_power.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_reg.h
drivers/gpu/drm/msm/Kconfig +9 -0
index 6deaa7d..7946cb1 100644
@@ -57,6 +57,15 @@ config DRM_MSM_HDMI_HDCP
 	help
 	  Choose this option to enable HDCP state machine
 
+config DRM_MSM_DP
+	bool "Enable DP support in MSM DRM driver"
+	depends on DRM_MSM
+	default n
+	help
+	  Compile in support for DP driver in msm drm driver. DP external
+	  display support is enabled through this config option. It can
+	  be primary or secondary display on device.
+
 config DRM_MSM_DSI
 	bool "Enable DSI support in MSM DRM driver"
 	depends on DRM_MSM
drivers/gpu/drm/msm/Makefile +13 -0
index 1579cf0..5939f41 100644
@@ -2,6 +2,7 @@
 ccflags-y := -I $(srctree)/$(src)
 ccflags-y += -I $(srctree)/$(src)/disp/dpu1
 ccflags-$(CONFIG_DRM_MSM_DSI) += -I $(srctree)/$(src)/dsi
+ccflags-$(CONFIG_DRM_MSM_DP) += -I $(srctree)/$(src)/dp
 
 msm-y := \
 	adreno/adreno_device.o \
@@ -96,8 +97,20 @@ msm-y := \
 
 msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o
 
+
 msm-$(CONFIG_DRM_MSM_GPU_STATE)	+= adreno/a6xx_gpu_state.o
 
+msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
+	dp/dp_catalog.o \
+	dp/dp_ctrl.o \
+	dp/dp_display.o \
+	dp/dp_drm.o \
+	dp/dp_extcon.o \
+	dp/dp_link.o \
+	dp/dp_panel.o \
+	dp/dp_parser.o \
+	dp/dp_power.o
+
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o
 msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +20 -0
index f96e142..29ac7d3 100644
@@ -967,6 +967,9 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 
 	trace_dpu_enc_mode_set(DRMID(drm_enc));
 
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp)
+		msm_dp_display_mode_set(priv->dp, drm_enc, mode, adj_mode);
+
 	list_for_each_entry(conn_iter, connector_list, head)
 		if (conn_iter->encoder == drm_enc)
 			conn = conn_iter;
@@ -1133,6 +1136,7 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 {
 	struct dpu_encoder_virt *dpu_enc = NULL;
 	int ret = 0;
+	struct msm_drm_private *priv;
 	struct drm_display_mode *cur_mode = NULL;
 
 	if (!drm_enc) {
@@ -1143,6 +1147,7 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 
 	mutex_lock(&dpu_enc->enc_lock);
 	cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
+	priv = drm_enc->dev->dev_private;
 
 	trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
 			     cur_mode->vdisplay);
@@ -1163,6 +1168,15 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 
 	_dpu_encoder_virt_enable_helper(drm_enc);
 
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
+		ret = msm_dp_display_enable(priv->dp,
+						drm_enc);
+		if (ret) {
+			DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n",
+				ret);
+			goto out;
+		}
+	}
 	dpu_enc->enabled = true;
 
 out:
@@ -1193,6 +1207,12 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
 	priv = drm_enc->dev->dev_private;
 	dpu_kms = to_dpu_kms(priv->kms);
 
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
+		if (msm_dp_display_disable(priv->dp, drm_enc)) {
+			DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n");
+			return;
+		  }
+	}
 	trace_dpu_enc_disable(DRMID(drm_enc));
 
 	/* wait for idle */
drivers/gpu/drm/msm/dp/dp_aux.c new file +548 -0

548 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_aux.h new file +37 -0
new file mode 100644
index 0000000..8ce2221
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DP_AUX_H_
+#define _DP_AUX_H_
+
+#include "dp_catalog.h"
+#include <drm/drm_dp_helper.h>
+
+enum dp_aux_error {
+	DP_AUX_ERR_NONE	= 0,
+	DP_AUX_ERR_ADDR	= -1,
+	DP_AUX_ERR_TOUT	= -2,
+	DP_AUX_ERR_NACK	= -3,
+	DP_AUX_ERR_DEFER	= -4,
+	DP_AUX_ERR_NACK_DEFER	= -5,
+};
+
+struct dp_aux {
+	struct drm_dp_aux *drm_aux;
+	struct dp_aux_cfg *cfg;
+};
+
+int dp_aux_register(struct dp_aux *aux);
+void dp_aux_unregister(struct dp_aux *aux);
+void dp_aux_isr(struct dp_aux *aux);
+void dp_aux_init(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
+void dp_aux_deinit(struct dp_aux *aux);
+void dp_aux_reconfig(struct dp_aux *aux);
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+			  struct dp_aux_cfg *aux_cfg);
+void dp_aux_put(struct dp_aux *aux);
+
+#endif /*__DP_AUX_H_*/
drivers/gpu/drm/msm/dp/dp_catalog.c new file +841 -0

841 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_catalog.h new file +84 -0

84 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +1590 -0

1,398 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_ctrl.h new file +34 -0
new file mode 100644
index 0000000..99ab4b2

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_display.c new file +949 -0

949 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_display.h new file +29 -0
new file mode 100644
index 0000000..c916408

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_drm.c new file +173 -0

173 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_drm.h new file +20 -0
new file mode 100644
index 0000000..cf472c5

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_extcon.c new file +216 -0

216 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_extcon.h new file +84 -0

84 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_link.c new file +1185 -0

1,185 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_link.h new file +132 -0

132 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_panel.c new file +450 -0

450 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_panel.h new file +92 -0

92 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_parser.c new file +496 -0

496 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_parser.h new file +222 -0

222 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_power.c new file +558 -0

558 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_power.h new file +52 -0

52 lines not on this page · raw message

drivers/gpu/drm/msm/dp/dp_reg.h new file +488 -0

488 lines not on this page · raw message

drivers/gpu/drm/msm/msm_drv.c +2 -0
index c84f0a8..e5e93e3 100644

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/msm_drv.h +42 -0

42 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

_______________________________________________
Freedreno mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/freedreno

Part of the diff is not shown here. View the raw message.

#7 lore raw

Re: [DPU PATCH v3 3/5] drm/msm/dp: add displayPort driver support

Quoted 41 lines · Chandan Uddaraju

Add the needed displayPort files to enable DP driver on msm target.

"dp_display" module is the main module that calls into other sub-modules. "dp_drm" file represents the interface between DRM framework and DP driver.

changes in v2:
-- Update copyright markings on all relevant files.
-- Change pr_err() to DRM_ERROR()
-- Use APIs directly instead of function pointers.
-- Use drm_display_mode structure to store link parameters in the driver. -- Use macros for register definitions instead of hardcoded values. -- Replace writel_relaxed/readl_relaxed with writel/readl
and remove memory barriers.
-- Remove unnecessary NULL checks.
-- Use drm helper functions for dpcd read/write.
-- Use DRM_DEBUG_DP for debug msgs.

changes in V3:
-- Removed changes in dpu_io_util.[ch]
-- Added locking around "is_connected" flag and removed atomic_set() -- Removed the argument validation checks in all the static functions
except initialization functions and few API calls across msm/dp files
-- Removed hardcoded values for register reads/writes
-- Removed vreg related generic structures.
-- Added return values where ever necessary.
-- Updated dp_ctrl_on function.
-- Calling the ctrl specific catalog functions directly instead of
function pointers.
-- Added seperate change that adds standard value in drm_dp_helper file. -- Added separate change in this list that is used to initialize
displayport in DPU driver.
-- Added change to use drm_dp_get_adjust_request_voltage() function.

---
+++ b/drivers/gpu/drm/msm/dp/dp_power.c

...

drivers/gpu/drm/msm/dp/dp_power.c line 464

Quoted 10 lines
drivers/gpu/drm/msm/dp/dp_power.c new file +10 -0
+int dp_power_init(struct dp_power *dp_power, bool flip)
+{
+	int rc = 0;
+	struct dp_power_private *power;
+
+	if (!dp_power) {
+		DRM_ERROR("invalid power data\n");
+		rc = -EINVAL;
+		goto exit;
+	}

drive-by comment:

this would lead to calling 'pm_runtime_put_sync(&power->pdev->dev)' below with 'power' being NULL, which doesn't seem a good idea.

It is probably sane to expect that 'dp_power' is not NULL, if that's the case the check can be removed. Otherwise the function should just return -EINVAL instead of jumping to 'exit'.

Quoted 30 lines
drivers/gpu/drm/msm/dp/dp_power.c new file +30 -0
+
+	power = container_of(dp_power, struct dp_power_private, dp_power);
+
+	pm_runtime_get_sync(&power->pdev->dev);
+	rc = dp_power_regulator_enable(power);
+	if (rc) {
+		DRM_ERROR("failed to enable regulators, %d\n", rc);
+		goto exit;
+	}
+
+	rc = dp_power_pinctrl_set(power, true);
+	if (rc) {
+		DRM_ERROR("failed to set pinctrl state, %d\n", rc);
+		goto err_pinctrl;
+	}
+
+	rc = dp_power_config_gpios(power, flip);
+	if (rc) {
+		DRM_ERROR("failed to enable gpios, %d\n", rc);
+		goto err_gpio;
+	}
+
+	rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
+	if (rc) {
+		DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
+		goto err_clk;
+	}
+
+	return 0;
+

drivers/gpu/drm/msm/dp/dp_power.c line 504

Quoted 10 lines
drivers/gpu/drm/msm/dp/dp_power.c new file +10 -0
+err_clk:
+	dp_power_disable_gpios(power);
+err_gpio:
+	dp_power_pinctrl_set(power, false);
+err_pinctrl:
+	dp_power_regulator_disable(power);
+exit:
+	pm_runtime_put_sync(&power->pdev->dev);
+	return rc;
+}

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#8 lore raw

Re: [DPU PATCH v3 3/5] drm/msm/dp: add displayPort driver support

Quoted 55 lines · Matthias Kaehlcke
Quoted 41 lines · Chandan Uddaraju

Add the needed displayPort files to enable DP driver on msm target.

"dp_display" module is the main module that calls into other sub-modules. "dp_drm" file represents the interface between DRM framework and DP driver.

changes in v2:
-- Update copyright markings on all relevant files.
-- Change pr_err() to DRM_ERROR()
-- Use APIs directly instead of function pointers.
-- Use drm_display_mode structure to store link parameters in the driver. -- Use macros for register definitions instead of hardcoded values. -- Replace writel_relaxed/readl_relaxed with writel/readl
and remove memory barriers.
-- Remove unnecessary NULL checks.
-- Use drm helper functions for dpcd read/write.
-- Use DRM_DEBUG_DP for debug msgs.

changes in V3:
-- Removed changes in dpu_io_util.[ch]
-- Added locking around "is_connected" flag and removed atomic_set() -- Removed the argument validation checks in all the static functions
except initialization functions and few API calls across msm/dp files
-- Removed hardcoded values for register reads/writes
-- Removed vreg related generic structures.
-- Added return values where ever necessary.
-- Updated dp_ctrl_on function.
-- Calling the ctrl specific catalog functions directly instead of
function pointers.
-- Added seperate change that adds standard value in drm_dp_helper file. -- Added separate change in this list that is used to initialize
displayport in DPU driver.
-- Added change to use drm_dp_get_adjust_request_voltage() function.

---
+++ b/drivers/gpu/drm/msm/dp/dp_power.c

...

drivers/gpu/drm/msm/dp/dp_power.c line 464

Quoted 10 lines
drivers/gpu/drm/msm/dp/dp_power.c new file +10 -0
+int dp_power_init(struct dp_power *dp_power, bool flip)
+{
+	int rc = 0;
+	struct dp_power_private *power;
+
+	if (!dp_power) {
+		DRM_ERROR("invalid power data\n");
+		rc = -EINVAL;
+		goto exit;
+	}

drive-by comment:

Quoted 2 lines

this would lead to calling 'pm_runtime_put_sync(&power->pdev->dev)' below with 'power' being NULL, which doesn't seem a good idea.

correction: with 'power' being uninitialized, which isn't a good idea either.

Quoted 44 lines

It is probably sane to expect that 'dp_power' is not NULL, if that's the case the check can be removed. Otherwise the function should just return -EINVAL instead of jumping to 'exit'.

Quoted 40 lines
drivers/gpu/drm/msm/dp/dp_power.c new file +40 -0
+
+	power = container_of(dp_power, struct dp_power_private, dp_power);
+
+	pm_runtime_get_sync(&power->pdev->dev);
+	rc = dp_power_regulator_enable(power);
+	if (rc) {
+		DRM_ERROR("failed to enable regulators, %d\n", rc);
+		goto exit;
+	}
+
+	rc = dp_power_pinctrl_set(power, true);
+	if (rc) {
+		DRM_ERROR("failed to set pinctrl state, %d\n", rc);
+		goto err_pinctrl;
+	}
+
+	rc = dp_power_config_gpios(power, flip);
+	if (rc) {
+		DRM_ERROR("failed to enable gpios, %d\n", rc);
+		goto err_gpio;
+	}
+
+	rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
+	if (rc) {
+		DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
+		goto err_clk;
+	}
+
+	return 0;
+
+err_clk:
+	dp_power_disable_gpios(power);
+err_gpio:
+	dp_power_pinctrl_set(power, false);
+err_pinctrl:
+	dp_power_regulator_disable(power);
+exit:
+	pm_runtime_put_sync(&power->pdev->dev);
+	return rc;
+}
#9 lore raw

Re: [DPU PATCH v3 3/5] drm/msm/dp: add displayPort driver support

In reply to Chandan Uddaraju

Hi Chandan,

I have no DRM background, but I suspect one reason this patch hasn't been reviewed in almost 3 months is its size, 8k LOC. I would suggest to split it up into multiple pieces to make a review less daunting. Not sure what the exact split would be, evaluating it per source file/self contained function could be a starting point.

And please make sure to run scripts/checkpatch.pl before sending patches (especially larger ones), reviewers don't like to spend time pointing out formatting issues that should have been fixed beforehand:

./scripts/checkpatch.pl DPU-v3-3-5-drm-msm-dp-add-displayPort-driver-support.patch

...

total: 2 errors, 141 warnings, 8440 lines checked

Thanks

Matthias

Quoted 8,684 lines · Chandan Uddaraju

Add the needed displayPort files to enable DP driver on msm target.

"dp_display" module is the main module that calls into other sub-modules. "dp_drm" file represents the interface between DRM framework and DP driver.

changes in v2:
-- Update copyright markings on all relevant files.
-- Change pr_err() to DRM_ERROR()
-- Use APIs directly instead of function pointers.
-- Use drm_display_mode structure to store link parameters in the driver. -- Use macros for register definitions instead of hardcoded values. -- Replace writel_relaxed/readl_relaxed with writel/readl
and remove memory barriers.
-- Remove unnecessary NULL checks.
-- Use drm helper functions for dpcd read/write.
-- Use DRM_DEBUG_DP for debug msgs.

changes in V3:
-- Removed changes in dpu_io_util.[ch]
-- Added locking around "is_connected" flag and removed atomic_set() -- Removed the argument validation checks in all the static functions
except initialization functions and few API calls across msm/dp files
-- Removed hardcoded values for register reads/writes
-- Removed vreg related generic structures.
-- Added return values where ever necessary.
-- Updated dp_ctrl_on function.
-- Calling the ctrl specific catalog functions directly instead of
function pointers.
-- Added seperate change that adds standard value in drm_dp_helper file. -- Added separate change in this list that is used to initialize
displayport in DPU driver.
-- Added change to use drm_dp_get_adjust_request_voltage() function.

---
 drivers/gpu/drm/msm/Kconfig                 |    9 +
 drivers/gpu/drm/msm/Makefile                |   13 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |   20 +
 drivers/gpu/drm/msm/dp/dp_aux.c             |  548 +++++++++
 drivers/gpu/drm/msm/dp/dp_aux.h             |   37 +
 drivers/gpu/drm/msm/dp/dp_catalog.c         |  841 ++++++++++++++
 drivers/gpu/drm/msm/dp/dp_catalog.h         |   84 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c            | 1590 +++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_ctrl.h            |   34 +
 drivers/gpu/drm/msm/dp/dp_display.c         |  949 ++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_display.h         |   29 +
 drivers/gpu/drm/msm/dp/dp_drm.c             |  173 +++
 drivers/gpu/drm/msm/dp/dp_drm.h             |   20 +
 drivers/gpu/drm/msm/dp/dp_extcon.c          |  216 ++++
 drivers/gpu/drm/msm/dp/dp_extcon.h          |   84 ++
 drivers/gpu/drm/msm/dp/dp_link.c            | 1185 ++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_link.h            |  132 +++
 drivers/gpu/drm/msm/dp/dp_panel.c           |  450 ++++++++
 drivers/gpu/drm/msm/dp/dp_panel.h           |   92 ++
 drivers/gpu/drm/msm/dp/dp_parser.c          |  496 +++++++++
 drivers/gpu/drm/msm/dp/dp_parser.h          |  222 ++++
 drivers/gpu/drm/msm/dp/dp_power.c           |  558 ++++++++++
 drivers/gpu/drm/msm/dp/dp_power.h           |   52 +
 drivers/gpu/drm/msm/dp/dp_reg.h             |  488 ++++++++
 drivers/gpu/drm/msm/msm_drv.c               |    2 +
 drivers/gpu/drm/msm/msm_drv.h               |   42 +
 26 files changed, 8366 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_display.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_display.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_drm.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_drm.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_extcon.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_extcon.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_link.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_link.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_panel.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_panel.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_parser.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_parser.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_power.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_power.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_reg.h
drivers/gpu/drm/msm/Kconfig +9 -0
index 6deaa7d..7946cb1 100644
@@ -57,6 +57,15 @@ config DRM_MSM_HDMI_HDCP
 	help
 	  Choose this option to enable HDCP state machine
 
+config DRM_MSM_DP
+	bool "Enable DP support in MSM DRM driver"
+	depends on DRM_MSM
+	default n
+	help
+	  Compile in support for DP driver in msm drm driver. DP external
+	  display support is enabled through this config option. It can
+	  be primary or secondary display on device.
+
 config DRM_MSM_DSI
 	bool "Enable DSI support in MSM DRM driver"
 	depends on DRM_MSM
drivers/gpu/drm/msm/Makefile +13 -0
index 1579cf0..5939f41 100644
@@ -2,6 +2,7 @@
 ccflags-y := -I $(srctree)/$(src)
 ccflags-y += -I $(srctree)/$(src)/disp/dpu1
 ccflags-$(CONFIG_DRM_MSM_DSI) += -I $(srctree)/$(src)/dsi
+ccflags-$(CONFIG_DRM_MSM_DP) += -I $(srctree)/$(src)/dp
 
 msm-y := \
 	adreno/adreno_device.o \
@@ -96,8 +97,20 @@ msm-y := \
 
 msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o
 
+
 msm-$(CONFIG_DRM_MSM_GPU_STATE)	+= adreno/a6xx_gpu_state.o
 
+msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
+	dp/dp_catalog.o \
+	dp/dp_ctrl.o \
+	dp/dp_display.o \
+	dp/dp_drm.o \
+	dp/dp_extcon.o \
+	dp/dp_link.o \
+	dp/dp_panel.o \
+	dp/dp_parser.o \
+	dp/dp_power.o
+
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o
 msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +20 -0
index f96e142..29ac7d3 100644
@@ -967,6 +967,9 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 
 	trace_dpu_enc_mode_set(DRMID(drm_enc));
 
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp)
+		msm_dp_display_mode_set(priv->dp, drm_enc, mode, adj_mode);
+
 	list_for_each_entry(conn_iter, connector_list, head)
 		if (conn_iter->encoder == drm_enc)
 			conn = conn_iter;
@@ -1133,6 +1136,7 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 {
 	struct dpu_encoder_virt *dpu_enc = NULL;
 	int ret = 0;
+	struct msm_drm_private *priv;
 	struct drm_display_mode *cur_mode = NULL;
 
 	if (!drm_enc) {
@@ -1143,6 +1147,7 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 
 	mutex_lock(&dpu_enc->enc_lock);
 	cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
+	priv = drm_enc->dev->dev_private;
 
 	trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
 			     cur_mode->vdisplay);
@@ -1163,6 +1168,15 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 
 	_dpu_encoder_virt_enable_helper(drm_enc);
 
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
+		ret = msm_dp_display_enable(priv->dp,
+						drm_enc);
+		if (ret) {
+			DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n",
+				ret);
+			goto out;
+		}
+	}
 	dpu_enc->enabled = true;
 
 out:
@@ -1193,6 +1207,12 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
 	priv = drm_enc->dev->dev_private;
 	dpu_kms = to_dpu_kms(priv->kms);
 
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
+		if (msm_dp_display_disable(priv->dp, drm_enc)) {
+			DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n");
+			return;
+		  }
+	}
 	trace_dpu_enc_disable(DRMID(drm_enc));
 
 	/* wait for idle */
drivers/gpu/drm/msm/dp/dp_aux.c new file +548 -0
new file mode 100644
index 0000000..a6bb52a
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
+
+#include <linux/delay.h>
+
+#include "dp_reg.h"
+#include "dp_aux.h"
+
+#define DP_AUX_ENUM_STR(x)		#x
+
+struct dp_aux_private {
+	struct device *dev;
+	struct dp_aux dp_aux;
+	struct dp_catalog *catalog;
+
+	struct mutex mutex;
+	struct completion comp;
+
+	u32 aux_error_num;
+	u32 retry_cnt;
+	bool cmd_busy;
+	bool native;
+	bool read;
+	bool no_send_addr;
+	bool no_send_stop;
+	u32 offset;
+	u32 segment;
+	u32 isr;
+
+	struct drm_dp_aux drm_aux;
+};
+
+static char *dp_aux_get_error(u32 aux_error)
+{
+	switch (aux_error) {
+	case DP_AUX_ERR_NONE:
+		return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE);
+	case DP_AUX_ERR_ADDR:
+		return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR);
+	case DP_AUX_ERR_TOUT:
+		return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT);
+	case DP_AUX_ERR_NACK:
+		return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK);
+	case DP_AUX_ERR_DEFER:
+		return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER);
+	case DP_AUX_ERR_NACK_DEFER:
+		return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER);
+	default:
+		return "unknown";
+	}
+}
+
+static u32 dp_aux_write(struct dp_aux_private *aux,
+			struct drm_dp_aux_msg *msg)
+{
+	u32 data[4], reg, len;
+	u8 *msgdata = msg->buffer;
+	int const aux_cmd_fifo_len = 128;
+	int i = 0;
+
+	if (aux->read)
+		len = 4;
+	else
+		len = msg->size + 4;
+
+	/*
+	 * cmd fifo only has depth of 144 bytes
+	 * limit buf length to 128 bytes here
+	 */
+	if (len > aux_cmd_fifo_len) {
+		DRM_ERROR("buf len error\n");
+		return 0;
+	}
+
+	/* Pack cmd and write to HW */
+	data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
+	if (aux->read)
+		data[0] |=  BIT(4); /* R/W */
+
+	data[1] = (msg->address >> 8) & 0xff;	/* addr[15:8] */
+	data[2] = msg->address & 0xff;		/* addr[7:0] */
+	data[3] = (msg->size - 1) & 0xff;	/* len[7:0] */
+
+	for (i = 0; i < len; i++) {
+		reg = (i < 4) ? data[i] : msgdata[i - 4];
+		/* index = 0, write */
+		reg = (((reg) << DP_AUX_DATA_OFFSET)
+		       & DP_AUX_DATA_MASK) | DP_AUX_DATA_WRITE;
+		if (i == 0)
+			reg |= DP_AUX_DATA_INDEX_WRITE;
+		aux->catalog->aux_data = reg;
+		dp_catalog_aux_write_data(aux->catalog);
+	}
+
+	dp_catalog_aux_clear_trans(aux->catalog, false);
+
+	reg = 0; /* Transaction number == 1 */
+	if (!aux->native) { /* i2c */
+		reg |= DP_AUX_TRANS_CTRL_I2C;
+
+		if (aux->no_send_addr)
+			reg |= DP_AUX_TRANS_CTRL_NO_SEND_ADDR;
+
+		if (aux->no_send_stop)
+			reg |= DP_AUX_TRANS_CTRL_NO_SEND_STOP;
+	}
+
+	reg |= DP_AUX_TRANS_CTRL_GO;
+	aux->catalog->aux_data = reg;
+	dp_catalog_aux_write_trans(aux->catalog);
+
+	return len;
+}
+
+static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
+			      struct drm_dp_aux_msg *msg)
+{
+	u32 ret = 0, len = 0, timeout;
+	int const aux_timeout_ms = HZ/4;
+
+	reinit_completion(&aux->comp);
+
+	len = dp_aux_write(aux, msg);
+	if (len == 0) {
+		DRM_ERROR("DP AUX write failed\n");
+		return -EINVAL;
+	}
+
+	timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
+	if (!timeout) {
+		DRM_ERROR("aux %s timeout\n", (aux->read ? "read" : "write"));
+		return -ETIMEDOUT;
+	}
+
+	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+		ret = len;
+	} else {
+		DRM_ERROR_RATELIMITED("aux err: %s\n",
+			dp_aux_get_error(aux->aux_error_num));
+
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg)
+{
+	u32 data;
+	u8 *dp;
+	u32 i, actual_i;
+	u32 len = msg->size;
+
+	dp_catalog_aux_clear_trans(aux->catalog, true);
+
+	data = 0;
+	data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
+	data |= DP_AUX_DATA_READ;  /* read */
+
+	aux->catalog->aux_data = data;
+	dp_catalog_aux_write_data(aux->catalog);
+
+	dp = msg->buffer;
+
+	/* discard first byte */
+	data = dp_catalog_aux_read_data(aux->catalog);
+
+	for (i = 0; i < len; i++) {
+		data = dp_catalog_aux_read_data(aux->catalog);
+		*dp++ = (u8)((data >> DP_AUX_DATA_OFFSET) & 0xff);
+
+		actual_i = (data >> DP_AUX_DATA_INDEX_OFFSET) & 0xFF;
+		if (i != actual_i)
+			pr_warn("Index mismatch: expected %d, found %d\n",
+				i, actual_i);
+	}
+}
+
+static void dp_aux_native_handler(struct dp_aux_private *aux)
+{
+	u32 isr = aux->isr;
+
+	if (isr & DP_INTR_AUX_I2C_DONE)
+		aux->aux_error_num = DP_AUX_ERR_NONE;
+	else if (isr & DP_INTR_WRONG_ADDR)
+		aux->aux_error_num = DP_AUX_ERR_ADDR;
+	else if (isr & DP_INTR_TIMEOUT)
+		aux->aux_error_num = DP_AUX_ERR_TOUT;
+	if (isr & DP_INTR_NACK_DEFER)
+		aux->aux_error_num = DP_AUX_ERR_NACK;
+
+	complete(&aux->comp);
+}
+
+static void dp_aux_i2c_handler(struct dp_aux_private *aux)
+{
+	u32 isr = aux->isr;
+
+	if (isr & DP_INTR_AUX_I2C_DONE) {
+		if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER))
+			aux->aux_error_num = DP_AUX_ERR_NACK;
+		else
+			aux->aux_error_num = DP_AUX_ERR_NONE;
+	} else {
+		if (isr & DP_INTR_WRONG_ADDR)
+			aux->aux_error_num = DP_AUX_ERR_ADDR;
+		else if (isr & DP_INTR_TIMEOUT)
+			aux->aux_error_num = DP_AUX_ERR_TOUT;
+		if (isr & DP_INTR_NACK_DEFER)
+			aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
+		if (isr & DP_INTR_I2C_NACK)
+			aux->aux_error_num = DP_AUX_ERR_NACK;
+		if (isr & DP_INTR_I2C_DEFER)
+			aux->aux_error_num = DP_AUX_ERR_DEFER;
+	}
+
+	complete(&aux->comp);
+}
+
+static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
+					     struct drm_dp_aux_msg *input_msg)
+{
+	u32 const edid_address = 0x50;
+	u32 const segment_address = 0x30;
+	bool i2c_read = input_msg->request &
+		(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+	u8 *data = NULL;
+
+	if (aux->native || i2c_read || ((input_msg->address != edid_address) &&
+		(input_msg->address != segment_address)))
+		return;
+
+
+	data = input_msg->buffer;
+	if (input_msg->address == segment_address)
+		aux->segment = *data;
+	else
+		aux->offset = *data;
+}
+
+/**
+ * dp_aux_transfer_helper() - helper function for EDID read transactions
+ *
+ * @aux: DP AUX private structure
+ * @input_msg: input message from DRM upstream APIs
+ *
+ * return: void
+ *
+ * This helper function is used to fix EDID reads for non-compliant
+ * sinks that do not handle the i2c middle-of-transaction flag correctly.
+ */
+static void dp_aux_transfer_helper(struct dp_aux_private *aux,
+				   struct drm_dp_aux_msg *input_msg)
+{
+	struct drm_dp_aux_msg helper_msg;
+	u32 const message_size = 0x10;
+	u32 const segment_address = 0x30;
+	bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
+	bool i2c_read = input_msg->request &
+		(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+	if (!i2c_mot || !i2c_read || (input_msg->size == 0))
+		return;
+
+	aux->read = false;
+	aux->cmd_busy = true;
+	aux->no_send_addr = true;
+	aux->no_send_stop = true;
+
+	/*
+	 * Send the segment address for every i2c read in which the
+	 * middle-of-tranaction flag is set. This is required to support EDID
+	 * reads of more than 2 blocks as the segment address is reset to 0
+	 * since we are overriding the middle-of-transaction flag for read
+	 * transactions.
+	 */
+	memset(&helper_msg, 0, sizeof(helper_msg));
+	helper_msg.address = segment_address;
+	helper_msg.buffer = &aux->segment;
+	helper_msg.size = 1;
+	dp_aux_cmd_fifo_tx(aux, &helper_msg);
+
+	/*
+	 * Send the offset address for every i2c read in which the
+	 * middle-of-transaction flag is set. This will ensure that the sink
+	 * will update its read pointer and return the correct portion of the
+	 * EDID buffer in the subsequent i2c read trasntion triggered in the
+	 * native AUX transfer function.
+	 */
+	memset(&helper_msg, 0, sizeof(helper_msg));
+	helper_msg.address = input_msg->address;
+	helper_msg.buffer = &aux->offset;
+	helper_msg.size = 1;
+	dp_aux_cmd_fifo_tx(aux, &helper_msg);
+	aux->offset += message_size;
+
+	if (aux->offset == 0x80 || aux->offset == 0x100)
+		aux->segment = 0x0; /* reset segment at end of block */
+}
+
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call aux_reset() function to reset the AUX channel,
+ * if the waiting is timeout.
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
+			       struct drm_dp_aux_msg *msg)
+{
+	ssize_t ret;
+	int const aux_cmd_native_max = 16;
+	int const aux_cmd_i2c_max = 128;
+	int const retry_count = 5;
+	struct dp_aux_private *aux = container_of(drm_aux,
+		struct dp_aux_private, drm_aux);
+
+	mutex_lock(&aux->mutex);
+
+	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		ret = msg->size;
+		goto unlock_exit;
+	}
+
+	/* msg sanity check */
+	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
+		(msg->size > aux_cmd_i2c_max)) {
+		DRM_ERROR("%s: invalid msg: size(%zu), request(%x)\n",
+			__func__, msg->size, msg->request);
+		ret = -EINVAL;
+		goto unlock_exit;
+	}
+
+	dp_aux_update_offset_and_segment(aux, msg);
+	dp_aux_transfer_helper(aux, msg);
+
+	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+	aux->cmd_busy = true;
+
+	if (aux->read) {
+		aux->no_send_addr = true;
+		aux->no_send_stop = false;
+	} else {
+		aux->no_send_addr = true;
+		aux->no_send_stop = true;
+	}
+
+	ret = dp_aux_cmd_fifo_tx(aux, msg);
+	if ((ret < 0) && aux->native) {
+		aux->retry_cnt++;
+		if (!(aux->retry_cnt % retry_count))
+			dp_catalog_aux_update_cfg(aux->catalog,
+				aux->dp_aux.cfg, PHY_AUX_CFG1);
+		dp_catalog_aux_reset(aux->catalog);
+		goto unlock_exit;
+	} else if (ret < 0) {
+		goto unlock_exit;
+	}
+
+	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+		if (aux->read)
+			dp_aux_cmd_fifo_rx(aux, msg);
+
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	} else {
+		/* Reply defer to retry */
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+	}
+
+	/* Return requested size for success or retry */
+	ret = msg->size;
+	aux->retry_cnt = 0;
+
+unlock_exit:
+	aux->cmd_busy = false;
+	mutex_unlock(&aux->mutex);
+	return ret;
+}
+
+static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg)
+{
+	int i = 0;
+
+	for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+		aux_cfg[i].current_index = 0;
+}
+
+void dp_aux_isr(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	aux->isr = dp_catalog_aux_get_irq(aux->catalog);
+
+	if (!aux->cmd_busy)
+		return;
+
+	if (aux->native)
+		dp_aux_native_handler(aux);
+	else
+		dp_aux_i2c_handler(aux);
+}
+
+void dp_aux_reconfig(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	dp_catalog_aux_update_cfg(aux->catalog,
+			dp_aux->cfg, PHY_AUX_CFG1);
+	dp_catalog_aux_reset(aux->catalog);
+}
+
+void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux || !aux_cfg) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	dp_aux_reset_phy_config_indices(aux_cfg);
+	dp_catalog_aux_setup(aux->catalog, aux_cfg);
+	dp_catalog_aux_reset(aux->catalog);
+	dp_catalog_aux_enable(aux->catalog, true);
+	aux->retry_cnt = 0;
+}
+
+void dp_aux_deinit(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	dp_catalog_aux_enable(aux->catalog, false);
+}
+
+int dp_aux_register(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+	int ret = 0;
+
+	if (!dp_aux) {
+		DRM_ERROR("invalid input\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	aux->drm_aux.name = "dpu_dp_aux";
+	aux->drm_aux.dev = aux->dev;
+	aux->drm_aux.transfer = dp_aux_transfer;
+	ret = drm_dp_aux_register(&aux->drm_aux);
+	if (ret) {
+		DRM_ERROR("%s: failed to register drm aux: %d\n", __func__, ret);
+		goto exit;
+	}
+	dp_aux->drm_aux = &aux->drm_aux;
+exit:
+	return ret;
+}
+
+void dp_aux_unregister(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+	drm_dp_aux_unregister(&aux->drm_aux);
+}
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+			  struct dp_aux_cfg *aux_cfg)
+{
+	int rc = 0;
+	struct dp_aux_private *aux;
+	struct dp_aux *dp_aux;
+
+	if (!catalog || !aux_cfg) {
+		DRM_ERROR("invalid input\n");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
+	if (!aux) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	init_completion(&aux->comp);
+	aux->cmd_busy = false;
+	mutex_init(&aux->mutex);
+
+	aux->dev = dev;
+	aux->catalog = catalog;
+	aux->dp_aux.cfg = aux_cfg;
+	dp_aux = &aux->dp_aux;
+	aux->retry_cnt = 0;
+
+	return dp_aux;
+error:
+	return ERR_PTR(rc);
+}
+
+void dp_aux_put(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux)
+		return;
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	mutex_destroy(&aux->mutex);
+
+	devm_kfree(aux->dev, aux);
+}
drivers/gpu/drm/msm/dp/dp_aux.h new file +37 -0
new file mode 100644
index 0000000..8ce2221
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DP_AUX_H_
+#define _DP_AUX_H_
+
+#include "dp_catalog.h"
+#include <drm/drm_dp_helper.h>
+
+enum dp_aux_error {
+	DP_AUX_ERR_NONE	= 0,
+	DP_AUX_ERR_ADDR	= -1,
+	DP_AUX_ERR_TOUT	= -2,
+	DP_AUX_ERR_NACK	= -3,
+	DP_AUX_ERR_DEFER	= -4,
+	DP_AUX_ERR_NACK_DEFER	= -5,
+};
+
+struct dp_aux {
+	struct drm_dp_aux *drm_aux;
+	struct dp_aux_cfg *cfg;
+};
+
+int dp_aux_register(struct dp_aux *aux);
+void dp_aux_unregister(struct dp_aux *aux);
+void dp_aux_isr(struct dp_aux *aux);
+void dp_aux_init(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
+void dp_aux_deinit(struct dp_aux *aux);
+void dp_aux_reconfig(struct dp_aux *aux);
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+			  struct dp_aux_cfg *aux_cfg);
+void dp_aux_put(struct dp_aux *aux);
+
+#endif /*__DP_AUX_H_*/
drivers/gpu/drm/msm/dp/dp_catalog.c new file +841 -0
new file mode 100644
index 0000000..51e21bb
@@ -0,0 +1,841 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <drm/drm_dp_helper.h>
+
+#include "dp_catalog.h"
+#include "dp_reg.h"
+
+#define POLLING_SLEEP_US			1000
+#define POLLING_TIMEOUT_US			10000
+
+#define REFTIMER_DEFAULT_VALUE			0x20000
+#define SCRAMBLER_RESET_COUNT_VALUE		0xFC
+
+#define DP_INTERRUPT_STATUS_ACK_SHIFT	1
+#define DP_INTERRUPT_STATUS_MASK_SHIFT	2
+
+#define DP_INTERRUPT_STATUS1 \
+	(DP_INTR_AUX_I2C_DONE| \
+	DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \
+	DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \
+	DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \
+	DP_INTR_PLL_UNLOCKED | DP_INTR_AUX_ERROR)
+
+#define DP_INTERRUPT_STATUS1_ACK (DP_INTERRUPT_STATUS1 << DP_INTERRUPT_STATUS_ACK_SHIFT)
+#define DP_INTERRUPT_STATUS1_MASK (DP_INTERRUPT_STATUS1 << DP_INTERRUPT_STATUS_MASK_SHIFT)
+
+#define DP_INTERRUPT_STATUS2 \
+	(DP_INTR_READY_FOR_VIDEO | DP_INTR_IDLE_PATTERN_SENT | \
+	DP_INTR_FRAME_END | DP_INTR_CRC_UPDATED)
+
+#define DP_INTERRUPT_STATUS2_ACK (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_ACK_SHIFT)
+#define DP_INTERRUPT_STATUS2_MASK (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
+
+static u8 const vm_pre_emphasis[4][4] = {
+	{0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
+	{0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
+	{0x00, 0x0C, 0xFF, 0xFF},       /* pe2, 6.0 db */
+	{0xFF, 0xFF, 0xFF, 0xFF}        /* pe3, 9.5 db */
+};
+
+/* voltage swing, 0.2v and 1.0v are not support */
+static u8 const vm_voltage_swing[4][4] = {
+	{0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v  */
+	{0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
+	{0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
+	{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
+};
+
+struct dp_catalog_private {
+	struct device *dev;
+	struct dp_io *io;
+	struct dp_catalog dp_catalog;
+};
+
+static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32 offset)
+{
+	return readl_relaxed(catalog->io->dp_aux.base + offset);
+}
+
+static inline void dp_write_aux(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	/*
+	 * To make sure aux reg writes happens before any other operation,
+	 * this function uses writel() instread of writel_relaxed()
+	 */
+	writel(data, catalog->io->dp_aux.base + offset);
+}
+
+static inline u32 dp_read_ahb(struct dp_catalog_private *catalog, u32 offset)
+{
+	return readl_relaxed(catalog->io->dp_ahb.base + offset);
+}
+
+static inline void dp_write_ahb(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	/*
+	 * To make sure phy reg writes happens before any other operation,
+	 * this function uses writel() instread of writel_relaxed()
+	 */
+	writel(data, catalog->io->dp_ahb.base + offset);
+}
+
+static inline u32 dp_read_cc(struct dp_catalog_private *catalog, u32 offset)
+{
+	return readl_relaxed(catalog->io->dp_cc_io.base + offset);
+}
+
+static inline void dp_write_phy(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	/*
+	 * To make sure phy reg writes happens before any other operation,
+	 * this function uses writel() instread of writel_relaxed()
+	 */
+	writel(data, catalog->io->phy_io.base + offset);
+}
+
+static inline void dp_write_pll(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	writel_relaxed(data, catalog->io->dp_pll_io.base + offset);
+}
+
+static inline void dp_write_ln_tx0(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	writel_relaxed(data, catalog->io->ln_tx0_io.base + offset);
+}
+
+static inline void dp_write_ln_tx1(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	writel_relaxed(data, catalog->io->ln_tx1_io.base + offset);
+}
+
+static inline void dp_write_usb_cm(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	/*
+	 * To make sure usb reg writes happens before any other operation,
+	 * this function uses writel() instread of writel_relaxed()
+	 */
+	writel(data, catalog->io->usb3_dp_com.base + offset);
+}
+
+static inline void dp_write_p0(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	/*
+	 * To make sure interface reg writes happens before any other operation,
+	 * this function uses writel() instread of writel_relaxed()
+	 */
+	writel(data, catalog->io->dp_p0.base + offset);
+}
+
+static inline u32 dp_read_link(struct dp_catalog_private *catalog, u32 offset)
+{
+	return readl_relaxed(catalog->io->dp_link.base + offset);
+}
+
+static inline void dp_write_link(struct dp_catalog_private *catalog,
+			       u32 offset, u32 data)
+{
+	/*
+	 * To make sure link reg writes happens before any other operation,
+	 * this function uses writel() instread of writel_relaxed()
+	 */
+	writel(data, catalog->io->dp_link.base + offset);
+}
+
+/* aux related catalog functions */
+u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	return dp_read_aux(catalog, REG_DP_AUX_DATA);
+}
+
+int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog)
+{
+	int rc = 0;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_aux(catalog, REG_DP_AUX_DATA, dp_catalog->aux_data);
+	return rc;
+}
+
+int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog)
+{
+	int rc = 0;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, dp_catalog->aux_data);
+	return rc;
+}
+
+int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool read)
+{
+	int rc = 0;
+	u32 data = 0;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	if (read) {
+		data = dp_read_aux(catalog, REG_DP_AUX_TRANS_CTRL);
+		data &= ~DP_AUX_TRANS_CTRL_GO;
+		dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, data);
+	} else {
+		dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, 0);
+	}
+	return rc;
+}
+
+void dp_catalog_aux_reset(struct dp_catalog *dp_catalog)
+{
+	u32 aux_ctrl;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	aux_ctrl = dp_read_aux(catalog, REG_DP_AUX_CTRL);
+
+	aux_ctrl |= DP_AUX_CTRL_RESET;
+	dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
+	usleep_range(1000, 1100); /* h/w recommended delay */
+
+	aux_ctrl &= ~DP_AUX_CTRL_RESET;
+	dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
+}
+
+void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable)
+{
+	u32 aux_ctrl;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	aux_ctrl = dp_read_aux(catalog, REG_DP_AUX_CTRL);
+
+	if (enable) {
+		dp_write_aux(catalog, REG_DP_TIMEOUT_COUNT, 0xffff);
+		dp_write_aux(catalog, REG_DP_AUX_LIMITS, 0xffff);
+		aux_ctrl |= DP_AUX_CTRL_ENABLE;
+	} else {
+		aux_ctrl &= ~DP_AUX_CTRL_ENABLE;
+	}
+
+	dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
+}
+
+void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog,
+		struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 new_index = 0, current_index = 0;
+
+	if (type >= PHY_AUX_CFG_MAX) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	current_index = cfg[type].current_index;
+	new_index = (current_index + 1) % cfg[type].cfg_cnt;
+	DRM_DEBUG_DP("Updating %s from 0x%08x to 0x%08x\n",
+		dp_phy_aux_config_type_to_string(type),
+	cfg[type].lut[current_index], cfg[type].lut[new_index]);
+
+	dp_write_phy(catalog, cfg[type].offset,
+			cfg[type].lut[new_index]);
+	cfg[type].current_index = new_index;
+}
+
+void dp_catalog_aux_setup(struct dp_catalog *dp_catalog,
+		struct dp_aux_cfg *cfg)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	int i = 0;
+
+	dp_write_phy(catalog, REG_DP_PHY_PD_CTL, DP_PHY_PD_CTL_PWRDN |
+		DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN |
+		DP_PHY_PD_CTL_DP_CLAMP_EN);
+
+	/* Turn on BIAS current for PHY/PLL */
+	dp_write_pll(catalog,
+		QSERDES_COM_BIAS_EN_CLKBUFLR_EN, QSERDES_COM_BIAS_EN |
+		QSERDES_COM_BIAS_EN_MUX | QSERDES_COM_CLKBUF_L_EN |
+		QSERDES_COM_EN_SYSCLK_TX_SEL);
+
+	/* DP AUX CFG register programming */
+	for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
+		DRM_DEBUG_DP("%s: offset=0x%08x, value=0x%08x\n",
+			dp_phy_aux_config_type_to_string(i),
+			cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
+		dp_write_phy(catalog, cfg[i].offset,
+			cfg[i].lut[cfg[i].current_index]);
+	}
+
+	dp_write_phy(catalog, REG_DP_PHY_AUX_INTERRUPT_MASK, PHY_AUX_STOP_ERR_MASK |
+			PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK |
+			PHY_AUX_ALIGN_ERR_MASK | PHY_AUX_REQ_ERR_MASK);
+}
+
+int dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 intr, intr_ack;
+
+	intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS);
+	intr &= ~DP_INTERRUPT_STATUS1_MASK;
+	intr_ack = (intr & DP_INTERRUPT_STATUS1) << DP_INTERRUPT_STATUS_ACK_SHIFT;
+	dp_write_ahb(catalog, REG_DP_INTR_STATUS, intr_ack | DP_INTERRUPT_STATUS1_MASK);
+
+	return intr;
+
+}
+
+/* controller related catalog functions */
+void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog *dp_catalog,
+				u32 dp_tu, u32 valid_boundary, u32 valid_boundary2)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_link(catalog, REG_DP_VALID_BOUNDARY, valid_boundary);
+	dp_write_link(catalog, REG_DP_TU, dp_tu);
+	dp_write_link(catalog, REG_DP_VALID_BOUNDARY_2, valid_boundary2);
+}
+
+void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_link(catalog, REG_DP_STATE_CTRL, state);
+}
+
+void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 cfg)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	DRM_DEBUG_DP("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
+
+	dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
+}
+
+void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
+	u32 ln_mapping;
+
+	ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
+	ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
+	ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
+	ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
+
+	dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, ln_mapping);
+}
+
+void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
+						bool enable)
+{
+	u32 mainlink_ctrl;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	if (enable) {
+		/*
+		* To make sure link reg writes happens before any other operation,
+		* dp_write_link() function uses writel() instread of writel_relaxed()
+		*/
+		dp_write_link(catalog, REG_DP_MAINLINK_CTRL, DP_MAINLINK_FB_BOUNDARY_SEL);
+		dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
+					DP_MAINLINK_FB_BOUNDARY_SEL | DP_MAINLINK_CTRL_RESET);
+		dp_write_link(catalog, REG_DP_MAINLINK_CTRL, DP_MAINLINK_FB_BOUNDARY_SEL);
+		dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
+					DP_MAINLINK_FB_BOUNDARY_SEL | DP_MAINLINK_CTRL_ENABLE);
+	} else {
+		mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+		mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE;
+		dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
+	}
+}
+
+void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog,
+					u32 colorimetry_cfg, u32 test_bits_depth)
+{
+	u32 misc_val;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	misc_val = dp_read_link(catalog, REG_DP_MISC1_MISC0);
+	misc_val |= colorimetry_cfg << DP_MISC0_COLORIMETRY_CFG_SHIFT;
+	misc_val |= test_bits_depth << DP_MISC0_TEST_BITS_DEPTH_SHIFT;
+	/* Configure clock to synchronous mode */
+	misc_val |= DP_MISC0_SYNCHRONOUS_CLK;
+
+	DRM_DEBUG_DP("misc settings = 0x%x\n", misc_val);
+	dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
+}
+
+void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
+					u32 rate, u32 stream_rate_khz,
+					bool fixed_nvid)
+{
+	u32 pixel_m, pixel_n;
+	u32 mvid, nvid;
+	u64 mvid_calc;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	if (fixed_nvid) {
+		nvid = DP_LINK_CONSTANT_N_VALUE;
+		DRM_DEBUG_DP("use fixed NVID=0x%x\n", nvid);
+
+		/*
+		 * For intermediate results, use 64 bit arithmetic to avoid
+		 * loss of precision.
+		 */
+		mvid_calc = (u64) stream_rate_khz * nvid;
+		mvid_calc = div_u64(mvid_calc, rate);
+
+		/*
+		 * truncate back to 32 bits as this final divided value will
+		 * always be within the range of a 32 bit unsigned int.
+		 */
+		mvid = (u32) mvid_calc;
+		DRM_DEBUG_DP("link rate=%dkbps, stream_rate_khz=%uKhz",
+			rate, stream_rate_khz);
+	} else {
+		pixel_m = dp_read_cc(catalog, MMSS_DP_PIXEL_M);
+		pixel_n = dp_read_cc(catalog, MMSS_DP_PIXEL_N);
+		DRM_DEBUG_DP("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
+
+		mvid = (pixel_m & 0xFFFF) * 5;
+		nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
+
+		DRM_DEBUG_DP("rate = %d\n", rate);
+
+		switch (drm_dp_link_rate_to_bw_code(rate)) {
+		case DP_LINK_BW_5_4:
+			nvid *= 2;
+			break;
+		case DP_LINK_BW_8_1:
+			nvid *= 3;
+			break;
+		default:
+			break;
+		}
+	}
+
+	DRM_DEBUG_DP("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
+	dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid);
+	dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid);
+}
+
+int dp_catalog_ctrl_set_pattern(struct dp_catalog *dp_catalog,
+					u32 pattern)
+{
+	int bit, ret;
+	u32 data;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	bit = BIT(pattern - 1);
+	DRM_DEBUG_DP("hw: bit=%d train=%d\n", bit, pattern);
+	dp_write_link(catalog, REG_DP_STATE_CTRL, bit);
+
+	bit = BIT(pattern - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT;
+
+	/* Poll for mainlink ready status */
+	ret = readx_poll_timeout(readl, catalog->io->dp_link.base + REG_DP_MAINLINK_READY,
+				 data, data & bit,
+				 POLLING_SLEEP_US, POLLING_TIMEOUT_US);
+	if (ret < 0) {
+		DRM_ERROR("set pattern for link_train=%d failed\n", pattern);
+		return ret;
+	}
+	return 0;
+}
+
+void dp_catalog_ctrl_usb_reset(struct dp_catalog *dp_catalog, bool flip)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 typec_ctrl;
+
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_RESET_OVRD_CTRL,
+			USB3_DP_COM_OVRD_CTRL_SW_DPPHY_RESET_MUX |
+			USB3_DP_COM_OVRD_CTRL_SW_USB3PHY_RESET_MUX);
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_PHY_MODE_CTRL,
+						USB3_DP_COM_PHY_MODE_DP);
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_SW_RESET,
+						USB3_DP_COM_SW_RESET_SET);
+
+	/* Default configuration i.e CC1 */
+	typec_ctrl = USB3_DP_COM_TYPEC_CTRL_PORTSEL_MUX;
+	if (flip)
+		typec_ctrl |= USB3_DP_COM_TYPEC_CTRL_PORTSEL;
+
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_TYPEC_CTRL, typec_ctrl);
+
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_SWI_CTRL, 0x00);
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_SW_RESET, 0x00);
+
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_POWER_DOWN_CTRL,
+						USB3_DP_COM_POWER_DOWN_CTRL_SW_PWRDN);
+	dp_write_usb_cm(catalog, REG_USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
+
+}
+
+void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog)
+{
+	u32 sw_reset;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	void __iomem *base;
+
+	base = catalog->io->dp_ahb.base;
+
+	sw_reset = dp_read_ahb(catalog, REG_DP_SW_RESET);
+
+	sw_reset |= DP_SW_RESET;
+	dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset);
+	usleep_range(1000, 1100); /* h/w recommended delay */
+
+	sw_reset &= ~DP_SW_RESET;
+	dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset);
+}
+
+bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog)
+{
+	u32 data;
+	int ret;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	/* Poll for mainlink ready status */
+	ret = readx_poll_timeout(readl,
+				 catalog->io->dp_link.base + REG_DP_MAINLINK_READY,
+				 data, data & DP_MAINLINK_READY_FOR_VIDEO,
+				 POLLING_SLEEP_US, POLLING_TIMEOUT_US);
+	if (ret < 0) {
+		DRM_ERROR("mainlink not ready\n");
+		return false;
+	}
+
+	return true;
+}
+
+void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog,
+						bool enable)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	void __iomem *base;
+
+	base = catalog->io->dp_ahb.base;
+
+	if (enable) {
+		dp_write_ahb(catalog, REG_DP_INTR_STATUS, DP_INTERRUPT_STATUS1_MASK);
+		dp_write_ahb(catalog, REG_DP_INTR_STATUS2, DP_INTERRUPT_STATUS2_MASK);
+	} else {
+		dp_write_ahb(catalog, REG_DP_INTR_STATUS, 0x00);
+		dp_write_ahb(catalog, REG_DP_INTR_STATUS2, 0x00);
+	}
+}
+
+void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog, bool en)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	if (en) {
+		u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER);
+
+		dp_write_aux(catalog, REG_DP_DP_HPD_INT_ACK,
+				DP_DP_HPD_PLUG_INT_ACK | DP_DP_IRQ_HPD_INT_ACK |
+				DP_DP_HPD_REPLUG_INT_ACK | DP_DP_HPD_UNPLUG_INT_ACK);
+		dp_write_aux(catalog, REG_DP_DP_HPD_INT_MASK,
+				DP_DP_HPD_PLUG_INT_MASK | DP_DP_IRQ_HPD_INT_MASK |
+				DP_DP_HPD_REPLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK);
+
+		/* Configure REFTIMER */
+		reftimer |= REFTIMER_DEFAULT_VALUE;
+		dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer);
+		/* Enable HPD */
+		dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
+	} else {
+		/* Disable HPD */
+		dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, 0x0);
+	}
+}
+
+int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 intr, intr_ack;
+
+	intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS2);
+	intr &= ~DP_INTERRUPT_STATUS2_MASK;
+	intr_ack = (intr & DP_INTERRUPT_STATUS2) << DP_INTERRUPT_STATUS_ACK_SHIFT;
+	dp_write_ahb(catalog, REG_DP_INTR_STATUS2, intr_ack | DP_INTERRUPT_STATUS2_MASK);
+
+	return intr;
+}
+
+void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_ahb(catalog, REG_DP_PHY_CTRL,
+			DP_PHY_CTRL_SW_RESET_PLL | DP_PHY_CTRL_SW_RESET);
+	usleep_range(1000, 1100); /* h/w recommended delay */
+	dp_write_ahb(catalog, REG_DP_PHY_CTRL, 0x0);
+}
+
+void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog *dp_catalog,
+		bool flipped, u8 ln_cnt)
+{
+	u32 info;
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u8 orientation = BIT(!!flipped);
+
+	info = ln_cnt & DP_PHY_SPARE0_MASK;
+	info |= (orientation & DP_PHY_SPARE0_MASK) << DP_PHY_SPARE0_ORIENTATION_INFO_SHIFT;
+	DRM_DEBUG_DP("Shared Info = 0x%x\n", info);
+
+	dp_write_phy(catalog, REG_DP_PHY_SPARE0, info);
+}
+
+int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog,
+		u8 v_level, u8 p_level)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u8 voltage_swing_cfg, pre_emphasis_cfg;
+
+	DRM_DEBUG_DP("hw: v=%d p=%d\n", v_level, p_level);
+
+	voltage_swing_cfg = vm_voltage_swing[v_level][p_level];
+	pre_emphasis_cfg = vm_pre_emphasis[v_level][p_level];
+
+	if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF) {
+		DRM_ERROR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
+			v_level, voltage_swing_cfg, p_level, pre_emphasis_cfg);
+		return -EINVAL;
+	}
+
+	/* Enable MUX to use Cursor values from these registers */
+	voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
+	pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
+
+	/* Configure host and panel only if both values are allowed */
+	dp_write_ln_tx0(catalog, REG_DP_PHY_TXn_TX_DRV_LVL, voltage_swing_cfg);
+	dp_write_ln_tx1(catalog, REG_DP_PHY_TXn_TX_DRV_LVL, voltage_swing_cfg);
+	dp_write_ln_tx0(catalog, REG_DP_PHY_TXn_TX_EMP_POST1_LVL, pre_emphasis_cfg);
+	dp_write_ln_tx1(catalog, REG_DP_PHY_TXn_TX_EMP_POST1_LVL, pre_emphasis_cfg);
+	DRM_DEBUG_DP("hw: vx_value=0x%x px_value=0x%x\n",
+			voltage_swing_cfg, pre_emphasis_cfg);
+
+	return 0;
+}
+
+void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
+			u32 pattern)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 value = 0x0;
+
+	/* Make sure to clear the current pattern before starting a new one */
+	dp_write_link(catalog, REG_DP_STATE_CTRL, 0x0);
+
+	switch (pattern) {
+	case DP_LINK_QUAL_PATTERN_D10_2:
+		dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_TRAINING_PATTERN1);
+		return;
+	case DP_LINK_QUAL_PATTERN_PRBS7:
+		dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_PRBS7);
+		return;
+	case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM:
+		dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN);
+		/* 00111110000011111000001111100000 */
+		dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
+		/* 00001111100000111110000011111000 */
+		dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
+		/* 1111100000111110 */
+		dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
+		return;
+	case DP_LINK_QUAL_PATTERN_HBR2_EYE:
+	case DP_LINK_QUAL_PATTERN_ERROR_RATE:
+		value &= ~DP_HBR2_ERM_PATTERN;
+		if (pattern == DP_LINK_QUAL_PATTERN_HBR2_EYE)
+			value = DP_HBR2_ERM_PATTERN;
+		dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		value |= SCRAMBLER_RESET_COUNT_VALUE;
+		dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
+		dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
+		return;
+	default:
+		DRM_DEBUG_DP("No valid test pattern requested: 0x%x\n", pattern);
+		return;
+	}
+}
+
+u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	return dp_read_link(catalog, REG_DP_MAINLINK_READY);
+}
+
+/* panel related catalog functions */
+int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_link(catalog, REG_DP_TOTAL_HOR_VER, dp_catalog->total);
+	dp_write_link(catalog, REG_DP_START_HOR_VER_FROM_SYNC, dp_catalog->sync_start);
+	dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY, dp_catalog->width_blanking);
+	dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_catalog->dp_active);
+	return 0;
+}
+
+void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
+				struct drm_display_mode *drm_mode)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 hsync_period, vsync_period;
+	u32 display_v_start, display_v_end;
+	u32 hsync_start_x, hsync_end_x;
+	u32 v_sync_width;
+	u32 hsync_ctl;
+	u32 display_hctl;
+
+	/* TPG config parameters*/
+	hsync_period = drm_mode->htotal;
+	vsync_period = drm_mode->vtotal;
+
+	display_v_start = ((drm_mode->vtotal - drm_mode->vsync_start) *
+					hsync_period);
+	display_v_end = ((vsync_period - drm_mode->vsync_start -
+					drm_mode->vdisplay) * hsync_period) - 1;
+
+	display_v_start += drm_mode->htotal - drm_mode->hsync_start;
+	display_v_end -= drm_mode->hsync_start - drm_mode->hdisplay;
+
+	hsync_start_x = drm_mode->htotal - drm_mode->hsync_start;
+	hsync_end_x = hsync_period - drm_mode->hsync_start -
+					drm_mode->hdisplay - 1;
+
+	v_sync_width = drm_mode->vsync_end - drm_mode->vsync_start;
+
+	hsync_ctl = (hsync_period << 16) |
+			(drm_mode->hsync_end - drm_mode->hsync_start);
+	display_hctl = (hsync_end_x << 16) | hsync_start_x;
+
+
+	dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0x0);
+	dp_write_p0(catalog, MMSS_DP_INTF_HSYNC_CTL, hsync_ctl);
+	dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F0, vsync_period *
+			hsync_period);
+	dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, v_sync_width *
+			hsync_period);
+	dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_HCTL, display_hctl);
+	dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_HCTL, 0);
+	dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F0, display_v_start);
+	dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F0, display_v_end);
+	dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F1, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
+	dp_write_p0(catalog, MMSS_DP_INTF_POLARITY_CTL, 0);
+
+	dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, DP_TPG_CHECKERED_RECT_PATTERN);
+	dp_write_p0(catalog, MMSS_DP_TPG_VIDEO_CONFIG,
+					DP_TPG_VIDEO_CONFIG_BPP_8BIT |
+					DP_TPG_VIDEO_CONFIG_RGB);
+	dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, DP_BIST_ENABLE_DPBIST_EN);
+	dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, DP_TIMING_ENGINE_EN_EN);
+	DRM_DEBUG_DP("%s: enabled tpg\n", __func__);
+}
+
+void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, 0x0);
+	dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, 0x0);
+	dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0);
+	return;
+}
+
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
+{
+	int rc = 0;
+	struct dp_catalog *dp_catalog;
+	struct dp_catalog_private *catalog;
+
+	if (!io) {
+		DRM_ERROR("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	catalog  = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL);
+	if (!catalog) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	catalog->dev = dev;
+	catalog->io = io;
+
+	dp_catalog = &catalog->dp_catalog;
+
+	return dp_catalog;
+error:
+	return ERR_PTR(rc);
+}
+
+void dp_catalog_put(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog;
+
+	if (!dp_catalog)
+		return;
+
+	catalog = container_of(dp_catalog, struct dp_catalog_private,
+				dp_catalog);
+
+	devm_kfree(catalog->dev, catalog);
+}
drivers/gpu/drm/msm/dp/dp_catalog.h new file +84 -0
new file mode 100644
index 0000000..51c82dd
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DP_CATALOG_H_
+#define _DP_CATALOG_H_
+
+#include "dp_parser.h"
+
+/* interrupts */
+#define DP_INTR_HPD		BIT(0)
+#define DP_INTR_AUX_I2C_DONE	BIT(3)
+#define DP_INTR_WRONG_ADDR	BIT(6)
+#define DP_INTR_TIMEOUT		BIT(9)
+#define DP_INTR_NACK_DEFER	BIT(12)
+#define DP_INTR_WRONG_DATA_CNT	BIT(15)
+#define DP_INTR_I2C_NACK	BIT(18)
+#define DP_INTR_I2C_DEFER	BIT(21)
+#define DP_INTR_PLL_UNLOCKED	BIT(24)
+#define DP_INTR_AUX_ERROR	BIT(27)
+
+#define DP_INTR_READY_FOR_VIDEO		BIT(0)
+#define DP_INTR_IDLE_PATTERN_SENT	BIT(3)
+#define DP_INTR_FRAME_END		BIT(6)
+#define DP_INTR_CRC_UPDATED		BIT(9)
+
+struct dp_catalog {
+	u32 aux_data;
+	u32 total;
+	u32 sync_start;
+	u32 width_blanking;
+	u32 dp_active;
+};
+
+/* AUX APIs */
+u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool read);
+void dp_catalog_aux_reset(struct dp_catalog *dp_catalog);
+void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable);
+void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog,
+			struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type);
+void dp_catalog_aux_setup(struct dp_catalog *dp_catalog,
+			struct dp_aux_cfg *aux_cfg);
+int dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
+
+/* DP Controller APIs */
+void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state);
+void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config);
+void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable);
+void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
+void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
+				u32 stream_rate_khz, bool fixed_nvid);
+int dp_catalog_ctrl_set_pattern(struct dp_catalog *dp_catalog, u32 pattern);
+void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_usb_reset(struct dp_catalog *dp_catalog, bool flip);
+bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable);
+void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog, bool enable);
+void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog *dp_catalog, bool flipped,
+				u8 lane_cnt);
+int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8 v_level,
+				u8 p_level);
+int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog *dp_catalog,
+				u32 dp_tu, u32 valid_boundary, u32 valid_boundary2);
+void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
+				u32 pattern);
+u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog);
+
+/* DP Panel APIs */
+int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog);
+void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
+				struct drm_display_mode *drm_mode);
+void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog);
+
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io);
+void dp_catalog_put(struct dp_catalog *catalog);
+
+#endif /* _DP_CATALOG_H_ */
drivers/gpu/drm/msm/dp/dp_ctrl.c new file +1590 -0
new file mode 100644
index 0000000..a4575ea
@@ -0,0 +1,1590 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <drm/drm_fixed.h>
+
+#include "dp_reg.h"
+#include "dp_ctrl.h"
+
+#define DP_KHZ_TO_HZ 1000
+#define IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES	(30 * HZ / 1000) /* 30 ms */
+#define WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES (HZ / 2)
+
+#define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0)
+#define DP_CTRL_INTR_IDLE_PATTERN_SENT  BIT(3)
+
+#define MR_LINK_TRAINING1  0x8
+#define MR_LINK_SYMBOL_ERM 0x80
+#define MR_LINK_PRBS7 0x100
+#define MR_LINK_CUSTOM80 0x200
+
+struct dp_tu_calc_input {
+	u64 lclk;        /* 162, 270, 540 and 810 */
+	u64 pclk_khz;    /* in KHz */
+	u64 hactive;     /* active h-width */
+	u64 hporch;      /* bp + fp + pulse */
+	int nlanes;      /* no.of.lanes */
+	int bpp;         /* bits */
+	int pixel_enc;   /* 444, 420, 422 */
+	int dsc_en;     /* dsc on/off */
+	int async_en;   /* async mode */
+};
+
+struct dp_vc_tu_mapping_table {
+	u8 valid_boundary_link;
+	u16 delay_start_link;
+	bool boundary_moderation_en;
+	u8 valid_lower_boundary_link;
+	u8 upper_boundary_count;
+	u8 lower_boundary_count;
+	u8 tu_size_minus1;
+};
+
+struct dp_ctrl_private {
+	struct dp_ctrl dp_ctrl;
+
+	struct device *dev;
+	struct dp_aux *aux;
+	struct dp_panel *panel;
+	struct dp_link *link;
+	struct dp_power *power;
+	struct dp_parser *parser;
+	struct dp_catalog *catalog;
+
+	struct completion idle_comp;
+	struct mutex push_idle_mutex;
+	struct completion video_comp;
+};
+
+void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+	mutex_lock(&ctrl->push_idle_mutex);
+
+	reinit_completion(&ctrl->idle_comp);
+	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_PUSH_IDLE);
+
+	if (!wait_for_completion_timeout(&ctrl->idle_comp,
+			IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES))
+		pr_warn("PUSH_IDLE pattern timedout\n");
+
+	mutex_unlock(&ctrl->push_idle_mutex);
+	pr_debug("mainlink off done\n");
+}
+
+static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
+{
+	u32 config = 0, tbd;
+	u8 *dpcd = ctrl->panel->dpcd;
+
+	/* Default-> LSCLK DIV: 1/4 LCLK  */
+	config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
+
+	/* Scrambler reset enable */
+	if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
+		config |= DP_CONFIGURATION_CTRL_ASSR;
+
+	tbd = dp_link_get_test_bits_depth(ctrl->link,
+			ctrl->panel->dp_mode.bpp);
+
+	if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) {
+		pr_debug("BIT_DEPTH not set. Configure default\n");
+		tbd = DP_TEST_BIT_DEPTH_8;
+	}
+
+	config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
+
+	/* Num of Lanes */
+	config |= ((ctrl->link->link_params.num_lanes - 1)
+			<< DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT);
+
+	if (drm_dp_enhanced_frame_cap(dpcd))
+		config |= DP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
+
+	config |= DP_CONFIGURATION_CTRL_P_INTERLACED; /* progressive video */
+
+	/* sync clock & static Mvid */
+	config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;
+	config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK;
+
+	dp_catalog_ctrl_config_ctrl(ctrl->catalog, config);
+}
+
+/**
+ * dp_ctrl_configure_source_params() - configures DP transmitter source params
+ * @ctrl: Display Port Driver data
+ *
+ * Configures the DP transmitter source params including details such as lane
+ * configuration, output format and sink/panel timing information.
+ */
+static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
+{
+	u32 cc, tb;
+
+	dp_catalog_ctrl_lane_mapping(ctrl->catalog);
+	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+
+	dp_ctrl_config_ctrl(ctrl);
+
+	tb = dp_link_get_test_bits_depth(ctrl->link,
+		ctrl->panel->dp_mode.bpp);
+	cc = dp_link_get_colorimetry_config(ctrl->link);
+	dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb);
+	dp_panel_timing_cfg(ctrl->panel);
+}
+
+/*
+ * The structure and few functions present below are IP/Hardware
+ * specific implementation. Most of the implementation will not
+ * have coding comments
+ */
+struct tu_algo_data {
+	s64 lclk_fp;
+	s64 pclk_fp;
+	s64 lwidth;
+	s64 hbp_relative_to_pclk;
+	int nlanes;
+	int bpp;
+	int pixelEnc;
+	int dsc_en;
+	int async_en;
+	int bpc;
+
+	uint delay_start_link_extra_pixclk;
+	int extra_buffer_margin;
+	s64 ratio_fp;
+	s64 original_ratio_fp;
+
+	s64 err_fp;
+	s64 n_err_fp;
+	s64 n_n_err_fp;
+	int tu_size;
+	int tu_size_desired;
+	int tu_size_minus1;
+
+	int valid_boundary_link;
+	s64 resulting_valid_fp;
+	s64 total_valid_fp;
+	s64 effective_valid_fp;
+	s64 effective_valid_recorded_fp;
+	int n_tus;
+	int n_tus_per_lane;
+	int paired_tus;
+	int remainder_tus;
+	int remainder_tus_upper;
+	int remainder_tus_lower;
+	int extra_bytes;
+	int filler_size;
+	int delay_start_link;
+
+	int extra_pclk_cycles;
+	int extra_pclk_cycles_in_link_clk;
+	s64 ratio_by_tu_fp;
+	s64 average_valid2_fp;
+	int new_valid_boundary_link;
+	int remainder_symbols_exist;
+	int n_symbols;
+	s64 n_remainder_symbols_per_lane_fp;
+	s64 last_partial_tu_fp;
+	s64 TU_ratio_err_fp;
+
+	int n_tus_incl_last_incomplete_tu;
+	int extra_pclk_cycles_tmp;
+	int extra_pclk_cycles_in_link_clk_tmp;
+	int extra_required_bytes_new_tmp;
+	int filler_size_tmp;
+	int lower_filler_size_tmp;
+	int delay_start_link_tmp;
+
+	bool boundary_moderation_en;
+	int boundary_mod_lower_err;
+	int upper_boundary_count;
+	int lower_boundary_count;
+	int i_upper_boundary_count;
+	int i_lower_boundary_count;
+	int valid_lower_boundary_link;
+	int even_distribution_BF;
+	int even_distribution_legacy;
+	int even_distribution;
+	int min_hblank_violated;
+	s64 delay_start_time_fp;
+	s64 hbp_time_fp;
+	s64 hactive_time_fp;
+	s64 diff_abs_fp;
+
+	s64 ratio;
+};
+
+static int _tu_param_compare(s64 a, s64 b)
+{
+	u32 a_int, a_frac;
+	u32 b_int, b_frac;
+
+	if (a == b)
+		return 0;
+
+	a_int = (a >> 32) & 0x7FFFFFFF;
+	a_frac = a & 0xFFFFFFFF;
+
+	b_int = (b >> 32) & 0x7FFFFFFF;
+	b_frac = b & 0xFFFFFFFF;
+
+	if (a_int > b_int)
+		return 1;
+	else if (a_int < b_int)
+		return 2;
+	else if (a_frac > b_frac)
+		return 1;
+	else
+		return 2;
+}
+
+static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
+{
+	s64 temp1_fp, temp2_fp, temp, temp1, temp2;
+	int compare_result_1, compare_result_2, compare_result_3;
+
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+
+	tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+
+	temp = (tu->i_upper_boundary_count *
+				tu->new_valid_boundary_link +
+				tu->i_lower_boundary_count *
+				(tu->new_valid_boundary_link-1));
+	tu->average_valid2_fp = drm_fixp_from_fraction(temp,
+					(tu->i_upper_boundary_count +
+					tu->i_lower_boundary_count));
+
+	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+	temp2_fp = drm_fixp_from_fraction(tu->lwidth, 1);
+	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+	temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
+	tu->n_tus = drm_fixp2int(temp2_fp);
+
+	temp1_fp = drm_fixp_from_fraction(tu->n_tus, 1);
+	temp2_fp = drm_fixp_mul(temp1_fp, tu->average_valid2_fp);
+	temp1_fp = drm_fixp_from_fraction(tu->n_symbols, 1);
+	temp2_fp = temp1_fp - temp2_fp;
+	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
+	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
+	tu->n_remainder_symbols_per_lane_fp = temp2_fp;
+
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+	tu->last_partial_tu_fp =
+			drm_fixp_div(tu->n_remainder_symbols_per_lane_fp,
+					temp1_fp);
+
+	if (tu->n_remainder_symbols_per_lane_fp != 0)
+		tu->remainder_symbols_exist = 1;
+	else
+		tu->remainder_symbols_exist = 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu->n_tus, tu->nlanes);
+	tu->n_tus_per_lane = drm_fixp2int(temp1_fp);
+
+	tu->paired_tus = (int)((tu->n_tus_per_lane) /
+					(tu->i_upper_boundary_count +
+					 tu->i_lower_boundary_count));
+
+	tu->remainder_tus = tu->n_tus_per_lane - tu->paired_tus *
+						(tu->i_upper_boundary_count +
+						tu->i_lower_boundary_count);
+
+	if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) {
+		tu->remainder_tus_upper = tu->i_upper_boundary_count;
+		tu->remainder_tus_lower = tu->remainder_tus -
+						tu->i_upper_boundary_count;
+	} else {
+		tu->remainder_tus_upper = tu->remainder_tus;
+		tu->remainder_tus_lower = 0;
+	}
+
+	temp = tu->paired_tus * (tu->i_upper_boundary_count *
+				tu->new_valid_boundary_link +
+				tu->i_lower_boundary_count *
+				(tu->new_valid_boundary_link - 1)) +
+				(tu->remainder_tus_upper *
+				 tu->new_valid_boundary_link) +
+				(tu->remainder_tus_lower *
+				(tu->new_valid_boundary_link - 1));
+	tu->total_valid_fp = drm_fixp_from_fraction(temp, 1);
+
+	if (tu->remainder_symbols_exist) {
+		temp1_fp = tu->total_valid_fp +
+				tu->n_remainder_symbols_per_lane_fp;
+		temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1);
+		temp2_fp = temp2_fp + tu->last_partial_tu_fp;
+		temp1_fp = drm_fixp_div(temp1_fp, temp2_fp);
+	} else {
+		temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1);
+		temp1_fp = drm_fixp_div(tu->total_valid_fp, temp2_fp);
+	}
+	tu->effective_valid_fp = temp1_fp;
+
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+	tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp;
+
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+	tu->n_err_fp = tu->average_valid2_fp - temp2_fp;
+
+	tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+	temp2_fp = drm_fixp_from_fraction(tu->lwidth, 1);
+	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+	temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
+
+	if (temp2_fp)
+		tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp);
+	else
+		tu->n_tus_incl_last_incomplete_tu = 0;
+
+	temp1 = 0;
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+	temp1_fp = tu->average_valid2_fp - temp2_fp;
+	temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1);
+	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+	if (temp1_fp)
+		temp1 = drm_fixp2int_ceil(temp1_fp);
+
+	temp = tu->i_upper_boundary_count * tu->nlanes;
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+	temp1_fp = drm_fixp_from_fraction(tu->new_valid_boundary_link, 1);
+	temp2_fp = temp1_fp - temp2_fp;
+	temp1_fp = drm_fixp_from_fraction(temp, 1);
+	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+	if (temp2_fp)
+		temp2 = drm_fixp2int_ceil(temp2_fp);
+	else
+		temp2 = 0;
+	tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2);
+
+	temp1_fp = drm_fixp_from_fraction(8, tu->bpp);
+	temp2_fp = drm_fixp_from_fraction(
+	tu->extra_required_bytes_new_tmp, 1);
+	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+	if (temp1_fp)
+		tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp);
+	else
+		tu->extra_pclk_cycles_tmp = 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1);
+	temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
+	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+	if (temp1_fp)
+		tu->extra_pclk_cycles_in_link_clk_tmp =
+						drm_fixp2int_ceil(temp1_fp);
+	else
+		tu->extra_pclk_cycles_in_link_clk_tmp = 0;
+
+	tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link;
+
+	tu->lower_filler_size_tmp = tu->filler_size_tmp + 1;
+
+	tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp +
+					tu->lower_filler_size_tmp +
+					tu->extra_buffer_margin;
+
+	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1);
+	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
+
+	compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp);
+	if (compare_result_1 == 2)
+		compare_result_1 = 1;
+	else
+		compare_result_1 = 0;
+
+	compare_result_2 = _tu_param_compare(tu->n_n_err_fp, tu->err_fp);
+	if (compare_result_2 == 2)
+		compare_result_2 = 1;
+	else
+		compare_result_2 = 0;
+
+	compare_result_3 = _tu_param_compare(tu->hbp_time_fp,
+					tu->delay_start_time_fp);
+	if (compare_result_3 == 2)
+		compare_result_3 = 0;
+	else
+		compare_result_3 = 1;
+
+	if (((tu->even_distribution == 1) ||
+			((tu->even_distribution_BF == 0) &&
+			(tu->even_distribution_legacy == 0))) &&
+			tu->n_err_fp >= 0 && tu->n_n_err_fp >= 0 &&
+			compare_result_2 &&
+			(compare_result_1 || (tu->min_hblank_violated == 1)) &&
+			(tu->new_valid_boundary_link - 1) > 0 &&
+			compare_result_3 &&
+			(tu->delay_start_link_tmp <= 1023)) {
+		tu->upper_boundary_count = tu->i_upper_boundary_count;
+		tu->lower_boundary_count = tu->i_lower_boundary_count;
+		tu->err_fp = tu->n_n_err_fp;
+		tu->boundary_moderation_en = true;
+		tu->tu_size_desired = tu->tu_size;
+		tu->valid_boundary_link = tu->new_valid_boundary_link;
+		tu->effective_valid_recorded_fp = tu->effective_valid_fp;
+		tu->even_distribution_BF = 1;
+		tu->delay_start_link = tu->delay_start_link_tmp;
+	} else if (tu->boundary_mod_lower_err == 0) {
+		compare_result_1 = _tu_param_compare(tu->n_n_err_fp,
+							tu->diff_abs_fp);
+		if (compare_result_1 == 2)
+			tu->boundary_mod_lower_err = 1;
+	}
+}
+
+static void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
+				   struct dp_vc_tu_mapping_table *tu_table)
+{
+	struct tu_algo_data tu;
+	int compare_result_1, compare_result_2;
+	u64 temp = 0;
+	s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
+
+	s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */
+	s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */
+	s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */
+	s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000);
+
+	u8 DP_BRUTE_FORCE = 1;
+	s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */
+	uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
+	uint HBLANK_MARGIN = 4;
+
+	memset(&tu, 0, sizeof(tu));
+
+	tu.lclk_fp              = drm_fixp_from_fraction(in->lclk, 1);
+	tu.pclk_fp              = drm_fixp_from_fraction(in->pclk_khz, 1000);
+	tu.lwidth               = in->hactive;
+	tu.hbp_relative_to_pclk = in->hporch;
+	tu.nlanes               = in->nlanes;
+	tu.bpp                  = in->bpp;
+	tu.pixelEnc             = in->pixel_enc;
+	tu.dsc_en               = in->dsc_en;
+	tu.async_en             = in->async_en;
+
+	tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
+
+	if (tu.pixelEnc == 420) {
+		temp_fp = drm_fixp_from_fraction(2, 1);
+		tu.pclk_fp = drm_fixp_div(tu.pclk_fp, temp_fp);
+		tu.lwidth /= 2;
+		tu.hbp_relative_to_pclk /= 2;
+	}
+
+	if (tu.pixelEnc == 422) {
+		switch (tu.bpp) {
+		case 24:
+			tu.bpp = 16;
+			tu.bpc = 8;
+			break;
+		case 30:
+			tu.bpp = 20;
+			tu.bpc = 10;
+			break;
+		default:
+			tu.bpp = 16;
+			tu.bpc = 8;
+			break;
+		}
+	} else {
+		tu.bpc = tu.bpp/3;
+	}
+
+	temp1_fp = drm_fixp_from_fraction(4, 1);
+	temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
+	temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
+	tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
+
+	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+	temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
+	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
+	tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
+
+	tu.original_ratio_fp = tu.ratio_fp;
+	tu.boundary_moderation_en = false;
+	tu.upper_boundary_count = 0;
+	tu.lower_boundary_count = 0;
+	tu.i_upper_boundary_count = 0;
+	tu.i_lower_boundary_count = 0;
+	tu.valid_lower_boundary_link = 0;
+	tu.even_distribution_BF = 0;
+	tu.even_distribution_legacy = 0;
+	tu.even_distribution = 0;
+	tu.delay_start_time_fp = 0;
+
+	tu.err_fp = drm_fixp_from_fraction(1000, 1);
+	tu.n_err_fp = 0;
+	tu.n_n_err_fp = 0;
+
+	tu.ratio = drm_fixp2int(tu.ratio_fp);
+	if ((((u32)tu.lwidth % tu.nlanes) != 0) &&
+			!tu.ratio && tu.dsc_en == 0) {
+		tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
+		tu.ratio = drm_fixp2int(tu.ratio_fp);
+		if (tu.ratio)
+			tu.ratio_fp = drm_fixp_from_fraction(1, 1);
+	}
+
+	if (tu.ratio > 1)
+		tu.ratio = 1;
+
+	if (tu.ratio == 1)
+		goto tu_size_calc;
+
+	compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp);
+	if (!compare_result_1 || compare_result_1 == 1)
+		compare_result_1 = 1;
+	else
+		compare_result_1 = 0;
+
+	compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp);
+	if (!compare_result_2 || compare_result_2 == 2)
+		compare_result_2 = 1;
+	else
+		compare_result_2 = 0;
+
+	if (tu.dsc_en && compare_result_1 && compare_result_2) {
+		HBLANK_MARGIN += 4;
+		DRM_DEBUG_DP("Info: increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN);
+	}
+
+tu_size_calc:
+	for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
+		temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
+		temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+		temp = drm_fixp2int_ceil(temp2_fp);
+		temp1_fp = drm_fixp_from_fraction(temp, 1);
+		tu.n_err_fp = temp1_fp - temp2_fp;
+
+		if (tu.n_err_fp < tu.err_fp) {
+			tu.err_fp = tu.n_err_fp;
+			tu.tu_size_desired = tu.tu_size;
+		}
+	}
+
+	tu.tu_size_minus1 = tu.tu_size_desired - 1;
+
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+	tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+
+	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+	temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+	temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
+	tu.n_tus = drm_fixp2int(temp2_fp);
+
+	tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
+	DRM_DEBUG_DP("Info: n_sym = %d, num_of_tus = %d\n",
+		tu.valid_boundary_link, tu.n_tus);
+
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+	temp2_fp = temp1_fp - temp2_fp;
+	temp1_fp = drm_fixp_from_fraction(tu.n_tus + 1, 1);
+	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+	temp = drm_fixp2int(temp2_fp);
+	if (temp && temp2_fp)
+		tu.extra_bytes = drm_fixp2int_ceil(temp2_fp);
+	else
+		tu.extra_bytes = 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu.extra_bytes, 1);
+	temp2_fp = drm_fixp_from_fraction(8, tu.bpp);
+	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+	temp = drm_fixp2int(temp1_fp);
+	if (temp && temp1_fp)
+		tu.extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
+	else
+		tu.extra_pclk_cycles = 0;
+
+	temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
+	temp2_fp = drm_fixp_from_fraction(tu.extra_pclk_cycles, 1);
+	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+	temp = drm_fixp2int(temp1_fp);
+	if (temp && temp1_fp)
+		tu.extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
+	else
+		tu.extra_pclk_cycles_in_link_clk = 0;
+
+	tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
+
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+
+	tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
+				tu.filler_size + tu.extra_buffer_margin;
+
+	tu.resulting_valid_fp =
+			drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
+	tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
+
+	temp1_fp = drm_fixp_from_fraction(
+			(tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1);
+	tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
+
+	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
+	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
+
+	compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
+					tu.delay_start_time_fp);
+	if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */
+		tu.min_hblank_violated = 1;
+
+	temp1_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+	tu.hactive_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
+
+	compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
+						tu.delay_start_time_fp);
+	if (compare_result_2 == 2)
+		tu.min_hblank_violated = 1;
+
+	tu.delay_start_time_fp = 0;
+
+	/* brute force */
+
+	tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
+	tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
+
+	temp = drm_fixp2int(tu.diff_abs_fp);
+	if (!temp && tu.diff_abs_fp <= 0xffff)
+		tu.diff_abs_fp = 0;
+
+	/* if(diff_abs < 0) diff_abs *= -1 */
+	if (tu.diff_abs_fp < 0)
+		tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
+
+	tu.boundary_mod_lower_err = 0;
+	if ((tu.diff_abs_fp != 0 &&
+			((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
+			 (tu.even_distribution_legacy == 0) ||
+			 (DP_BRUTE_FORCE == 1))) ||
+			(tu.min_hblank_violated == 1)) {
+		do {
+			tu.err_fp = drm_fixp_from_fraction(1000, 1);
+
+			temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
+			temp2_fp = drm_fixp_from_fraction(
+					tu.delay_start_link_extra_pixclk, 1);
+			temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+			if (temp1_fp)
+				tu.extra_buffer_margin =
+					drm_fixp2int_ceil(temp1_fp);
+			else
+				tu.extra_buffer_margin = 0;
+
+			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+			temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+			temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+			if (temp1_fp)
+				tu.n_symbols = drm_fixp2int_ceil(temp1_fp);
+			else
+				tu.n_symbols = 0;
+
+			for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
+				for (tu.i_upper_boundary_count = 1;
+					tu.i_upper_boundary_count <= 15;
+					tu.i_upper_boundary_count++) {
+					for (tu.i_lower_boundary_count = 1;
+						tu.i_lower_boundary_count <= 15;
+						tu.i_lower_boundary_count++) {
+						_tu_valid_boundary_calc(&tu);
+					}
+				}
+			}
+			tu.delay_start_link_extra_pixclk--;
+		} while (tu.boundary_moderation_en != true &&
+			tu.boundary_mod_lower_err == 1 &&
+			tu.delay_start_link_extra_pixclk != 0);
+
+		if (tu.boundary_moderation_en == true) {
+			temp1_fp = drm_fixp_from_fraction(
+					(tu.upper_boundary_count *
+					tu.valid_boundary_link +
+					tu.lower_boundary_count *
+					(tu.valid_boundary_link - 1)), 1);
+			temp2_fp = drm_fixp_from_fraction(
+					(tu.upper_boundary_count +
+					tu.lower_boundary_count), 1);
+			tu.resulting_valid_fp =
+					drm_fixp_div(temp1_fp, temp2_fp);
+
+			temp1_fp = drm_fixp_from_fraction(
+					tu.tu_size_desired, 1);
+			tu.ratio_by_tu_fp =
+				drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+
+			tu.valid_lower_boundary_link =
+				tu.valid_boundary_link - 1;
+
+			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+			temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+			temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+			temp2_fp = drm_fixp_div(temp1_fp,
+						tu.resulting_valid_fp);
+			tu.n_tus = drm_fixp2int(temp2_fp);
+
+			tu.tu_size_minus1 = tu.tu_size_desired - 1;
+			tu.even_distribution_BF = 1;
+
+			temp1_fp =
+				drm_fixp_from_fraction(tu.tu_size_desired, 1);
+			temp2_fp =
+				drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
+			tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
+		}
+	}
+
+	temp1_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+	temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, temp1_fp);
+
+	if (temp2_fp)
+		temp = drm_fixp2int_ceil(temp2_fp);
+	else
+		temp = 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
+	temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+	temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
+	temp1_fp = drm_fixp_from_fraction(temp, 1);
+	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+	temp = drm_fixp2int(temp2_fp);
+
+	if (tu.async_en)
+		tu.delay_start_link += (int)temp;
+
+	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
+	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
+
+	/* OUTPUTS */
+	tu_table->valid_boundary_link       = tu.valid_boundary_link;
+	tu_table->delay_start_link          = tu.delay_start_link;
+	tu_table->boundary_moderation_en    = tu.boundary_moderation_en;
+	tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
+	tu_table->upper_boundary_count      = tu.upper_boundary_count;
+	tu_table->lower_boundary_count      = tu.lower_boundary_count;
+	tu_table->tu_size_minus1            = tu.tu_size_minus1;
+
+	DRM_DEBUG_DP("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link);
+	DRM_DEBUG_DP("TU: delay_start_link: %d\n", tu_table->delay_start_link);
+	DRM_DEBUG_DP("TU: boundary_moderation_en: %d\n",
+			tu_table->boundary_moderation_en);
+	DRM_DEBUG_DP("TU: valid_lower_boundary_link: %d\n",
+			tu_table->valid_lower_boundary_link);
+	DRM_DEBUG_DP("TU: upper_boundary_count: %d\n",
+			tu_table->upper_boundary_count);
+	DRM_DEBUG_DP("TU: lower_boundary_count: %d\n",
+			tu_table->lower_boundary_count);
+	DRM_DEBUG_DP("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
+}
+
+static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
+		struct dp_vc_tu_mapping_table *tu_table)
+{
+	struct dp_tu_calc_input in;
+	struct drm_display_mode *drm_mode;
+
+	drm_mode = &ctrl->panel->dp_mode.drm_mode;
+
+	in.lclk = ctrl->link->link_params.rate / 1000;
+	in.pclk_khz = drm_mode->clock;
+	in.hactive = drm_mode->hdisplay;
+	in.hporch = drm_mode->htotal - drm_mode->hdisplay;
+	in.nlanes = ctrl->link->link_params.num_lanes;
+	in.bpp = ctrl->panel->dp_mode.bpp;
+	in.pixel_enc = 444;
+	in.dsc_en = 0;
+	in.async_en = 0;
+
+	_dp_ctrl_calc_tu(&in, tu_table);
+}
+
+static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
+{
+	u32 dp_tu = 0x0;
+	u32 valid_boundary = 0x0;
+	u32 valid_boundary2 = 0x0;
+	struct dp_vc_tu_mapping_table tu_calc_table;
+
+	dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
+
+	dp_tu |= tu_calc_table.tu_size_minus1;
+	valid_boundary |= tu_calc_table.valid_boundary_link;
+	valid_boundary |= (tu_calc_table.delay_start_link << 16);
+
+	valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
+	valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
+	valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
+
+	if (tu_calc_table.boundary_moderation_en)
+		valid_boundary2 |= BIT(0);
+
+	pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
+			dp_tu, valid_boundary, valid_boundary2);
+
+	dp_catalog_ctrl_update_transfer_unit(ctrl->catalog,
+				dp_tu, valid_boundary, valid_boundary2);
+}
+
+static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+
+	if (!wait_for_completion_timeout(&ctrl->video_comp,
+				WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES)) {
+		DRM_ERROR("Link Train timedout\n");
+		ret = -ETIMEDOUT;
+	}
+	return ret;
+}
+
+static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
+{
+	struct dp_link *link = ctrl->link;
+	int ret = 0, lane, lane_cnt;
+	u8 buf[4];
+	u32 max_level_reached = 0;
+	u32 voltage_swing_level = link->phy_params.v_level;
+	u32 pre_emphasis_level = link->phy_params.p_level;
+
+	ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
+		voltage_swing_level, pre_emphasis_level);
+	if (ret)
+		return ret;
+
+	if (voltage_swing_level > DP_TRAIN_VOLTAGE_SWING_MAX) {
+		DRM_DEBUG_DP("max. voltage swing level reached %d\n",
+				voltage_swing_level);
+		max_level_reached |= DP_TRAIN_MAX_SWING_REACHED;
+	}
+
+	if (pre_emphasis_level == DP_TRAIN_PRE_EMPHASIS_MAX) {
+		DRM_DEBUG_DP("max. pre-emphasis level reached %d\n",
+				pre_emphasis_level);
+		max_level_reached  |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+	}
+
+	pre_emphasis_level <<= DP_TRAIN_PRE_EMPHASIS_SHIFT;
+
+	lane_cnt = ctrl->link->link_params.num_lanes;
+	for (lane = 0; lane < lane_cnt; lane++)
+		buf[lane] = voltage_swing_level | pre_emphasis_level | max_level_reached;
+
+	DRM_DEBUG_DP("sink: p|v=0x%x\n", voltage_swing_level | pre_emphasis_level);
+	ret = drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_LANE0_SET, buf, lane_cnt);
+	if (ret == lane_cnt)
+		ret = 0;
+
+	return ret;
+}
+
+static bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
+		u8 pattern)
+{
+	u8 buf;
+	int ret = 0;
+
+	DRM_DEBUG_DP("sink: pattern=%x\n", pattern);
+
+	buf = pattern;
+	ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf);
+	return ret == 1;
+}
+
+static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
+				    u8 *link_status)
+{
+	int len = 0;
+	u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
+	u32 link_status_read_max_retries = 100;
+
+	while (--link_status_read_max_retries) {
+		len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+			link_status);
+		if (len != DP_LINK_STATUS_SIZE) {
+			DRM_ERROR("DP link status read failed, err: %d\n", len);
+			return len;
+		}
+
+		if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
+{
+	int tries, old_v_level, ret = 0;
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	int const maximum_retries = 5;
+
+	dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+
+	ret = dp_catalog_ctrl_set_pattern(ctrl->catalog, DP_TRAINING_PATTERN_1);
+	if (ret)
+		return ret;
+	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
+		DP_LINK_SCRAMBLING_DISABLE);
+	ret = dp_ctrl_update_vx_px(ctrl);
+	if (ret)
+		return ret;
+
+	tries = 0;
+	old_v_level = ctrl->link->phy_params.v_level;
+	for (tries = 0; tries < maximum_retries; tries++) {
+		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
+
+		ret = dp_ctrl_read_link_status(ctrl, link_status);
+		if (ret)
+			return ret;
+
+		if (drm_dp_clock_recovery_ok(link_status,
+			ctrl->link->link_params.num_lanes)) {
+			return ret;
+		}
+
+		if (ctrl->link->phy_params.v_level > DP_TRAIN_VOLTAGE_SWING_MAX) {
+			DRM_ERROR_RATELIMITED("max v_level reached\n");
+			return -EAGAIN;
+		}
+
+		if (old_v_level != ctrl->link->phy_params.v_level) {
+			tries = 0;
+			old_v_level = ctrl->link->phy_params.v_level;
+		}
+
+		DRM_DEBUG_DP("clock recovery not done, adjusting vx px\n");
+
+		dp_link_adjust_levels(ctrl->link, link_status);
+		ret = dp_ctrl_update_vx_px(ctrl);
+		if (ret)
+			return ret;
+	}
+
+	DRM_ERROR("max tries reached\n");
+	return -ETIMEDOUT;
+}
+
+static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+
+	switch (ctrl->link->link_params.rate) {
+	case 810000:
+		ctrl->link->link_params.rate = 540000;
+		break;
+	case 540000:
+		ctrl->link->link_params.rate = 270000;
+		break;
+	case 270000:
+	case 162000:
+	default:
+		ctrl->link->link_params.rate = 162000;
+		break;
+	};
+
+	DRM_DEBUG_DP("new rate=0x%x\n", ctrl->link->link_params.rate);
+
+	return ret;
+}
+
+static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
+{
+	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE);
+	drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
+}
+
+static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
+{
+	int tries = 0, ret = 0;
+	char pattern;
+	int const maximum_retries = 5;
+	u8 link_status[DP_LINK_STATUS_SIZE];
+
+	dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+
+	if (drm_dp_tps3_supported(ctrl->panel->dpcd))
+		pattern = DP_TRAINING_PATTERN_3;
+	else
+		pattern = DP_TRAINING_PATTERN_2;
+
+	ret = dp_ctrl_update_vx_px(ctrl);
+	if (ret)
+		return ret;
+
+	ret = dp_catalog_ctrl_set_pattern(ctrl->catalog, pattern);
+	if (ret)
+		return ret;
+
+	dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
+
+	for (tries = 0; tries <= maximum_retries; tries++) {
+		drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
+
+		ret = dp_ctrl_read_link_status(ctrl, link_status);
+		if (ret)
+			return ret;
+
+		if (drm_dp_channel_eq_ok(link_status,
+			ctrl->link->link_params.num_lanes))
+			return ret;
+
+		dp_link_adjust_levels(ctrl->link, link_status);
+		ret = dp_ctrl_update_vx_px(ctrl);
+		if (ret)
+			return ret;
+
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+	u8 encoding = DP_SET_ANSI_8B10B;
+	struct drm_dp_link link_info = {0};
+
+	ctrl->link->phy_params.p_level = 0;
+	ctrl->link->phy_params.v_level = 0;
+
+	dp_ctrl_config_ctrl(ctrl);
+
+	ret = drm_dp_link_probe(ctrl->aux->drm_aux, &link_info);
+	if (ret < 0) {
+		DRM_ERROR("failed to retrieve link capabilities. ret=%d\n", ret);
+		dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+		return ret;
+	}
+
+	drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
+	drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
+				&encoding, 1);
+
+	ret = dp_ctrl_link_train_1(ctrl);
+	if (ret) {
+		DRM_ERROR("link training #1 failed. ret=%d\n", ret);
+		goto end;
+	}
+
+	/* print success info as this is a result of user initiated action */
+	DRM_DEBUG_DP("link training #1 successful\n");
+
+	ret = dp_ctrl_link_training_2(ctrl);
+	if (ret) {
+		DRM_ERROR("link training #2 failed. ret=%d\n", ret);
+		goto end;
+	}
+
+	/* print success info as this is a result of user initiated action */
+	DRM_DEBUG_DP("link training #2 successful\n");
+
+end:
+	dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+
+	dp_ctrl_clear_training_pattern(ctrl);
+	return ret;
+}
+
+static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
+{
+	bool mainlink_ready = false;
+	int ret = 0;
+
+	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+
+	ret = dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, false);
+	if (ret)
+		return ret;
+
+	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
+		return ret;
+
+	if (train) {
+		/*
+		 * As part of previous calls, DP controller state might have
+		 * transitioned to PUSH_IDLE. In order to start transmitting a link
+		 * training pattern, we have to first do a DP software reset.
+		 */
+		dp_catalog_ctrl_reset(ctrl->catalog);
+
+		ret = dp_ctrl_link_train(ctrl);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Set up transfer unit values and set controller state to send
+	 * video.
+	 */
+	dp_ctrl_setup_tr_unit(ctrl);
+	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
+
+	ret = dp_ctrl_wait4video_ready(ctrl);
+	if (ret)
+		return ret;
+
+	mainlink_ready = dp_catalog_ctrl_mainlink_ready(ctrl->catalog);
+	DRM_DEBUG_DP("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
+	return ret;
+}
+
+static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
+				   char *name, u32 rate)
+{
+	u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk;
+	struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config;
+
+	while (num && strcmp(cfg->clk_name, name)) {
+		num--;
+		cfg++;
+	}
+
+	DRM_DEBUG_DP("setting rate=%d on clk=%s\n", rate, name);
+
+	if (num)
+		cfg->rate = rate;
+	else
+		DRM_ERROR("%s clock could not be set with rate %d\n", name, rate);
+}
+
+static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+
+	dp_power_set_link_clk_parent(ctrl->power);
+	dp_power_set_pixel_clk_parent(ctrl->power);
+
+	dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk", ctrl->link->link_params.rate);
+
+	dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->dp_ctrl.pixel_rate);
+
+	ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true);
+	if (ret)
+		DRM_ERROR("Unabled to start link clocks. ret=%d\n", ret);
+
+	return ret;
+}
+
+int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)
+{
+	struct dp_ctrl_private *ctrl;
+
+	if (!dp_ctrl) {
+		DRM_ERROR("Invalid input data\n");
+		return -EINVAL;
+	}
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+	ctrl->dp_ctrl.orientation = flip;
+
+	dp_catalog_ctrl_usb_reset(ctrl->catalog, flip);
+	dp_catalog_ctrl_phy_reset(ctrl->catalog);
+	dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
+
+	return 0;
+}
+
+/**
+ * dp_ctrl_host_deinit() - Uninitialize DP controller
+ * @ctrl: Display Port Driver data
+ *
+ * Perform required steps to uninitialize DP controller
+ * and its resources.
+ */
+void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
+
+	if (!dp_ctrl) {
+		DRM_ERROR("Invalid input data\n");
+		return;
+	}
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+	dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
+
+	DRM_DEBUG_DP("Host deinitialized successfully\n");
+}
+
+static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
+{
+	u8 *dpcd = ctrl->panel->dpcd;
+
+	/*
+	 * For better interop experience, used a fixed NVID=0x8000
+	 * whenever connected to a VGA dongle downstream.
+	 */
+	if (drm_dp_is_branch(dpcd))
+		return (drm_dp_has_quirk(&ctrl->panel->desc,
+				DP_DPCD_QUIRK_CONSTANT_N));
+
+	return false;
+}
+
+static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+
+	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
+	dp_catalog_ctrl_phy_lane_cfg(ctrl->catalog,
+		ctrl->dp_ctrl.orientation, ctrl->link->link_params.num_lanes);
+	/*
+	 * Disable and re-enable the mainlink clock since the
+	 * link clock might have been adjusted as part of the
+	 * link maintenance.
+	 */
+	ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
+	if (ret) {
+		DRM_ERROR("Failed to disable clocks. ret=%d\n", ret);
+		return ret;
+	}
+	/* hw recommended delay before re-enabling clocks */
+	msleep(20);
+
+	ret = dp_ctrl_enable_mainlink_clocks(ctrl);
+	if (ret) {
+		DRM_ERROR("Failed to enable mainlink clks. ret=%d\n", ret);
+		return ret;
+	}
+
+	dp_ctrl_configure_source_params(ctrl);
+	dp_catalog_ctrl_config_msa(ctrl->catalog,
+		ctrl->link->link_params.rate,
+		ctrl->dp_ctrl.pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
+	reinit_completion(&ctrl->idle_comp);
+
+	return ret;
+}
+
+static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+	int tries, max_tries = 10;
+
+	dp_ctrl_push_idle(&ctrl->dp_ctrl);
+	dp_catalog_ctrl_reset(ctrl->catalog);
+
+	ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
+
+	for (tries = 0; tries < max_tries; tries++) {
+		ret = dp_ctrl_reinitialize_mainlink(ctrl);
+		if (ret) {
+			DRM_ERROR("Failed to reinitialize mainlink. ret=%d\n", ret);
+			break;
+		}
+
+		ret = dp_ctrl_setup_main_link(ctrl, true);
+		if (ret == -EAGAIN) /* try with lower link rate */
+			dp_ctrl_link_rate_down_shift(ctrl);
+	}
+	return ret;
+}
+
+static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
+{
+	int ret = 0;
+
+	if (!ctrl->link->phy_params.phy_test_pattern_sel) {
+		DRM_DEBUG_DP("no test pattern selected by sink\n");
+		return ret;
+	}
+
+	dp_ctrl_push_idle(&ctrl->dp_ctrl);
+	/*
+	 * The global reset will need DP link related clocks to be
+	 * running. Add the global reset just before disabling the
+	 * link clocks and core clocks.
+	 */
+	dp_catalog_ctrl_reset(ctrl->catalog);
+	ret = dp_ctrl_off(&ctrl->dp_ctrl);
+	if (ret) {
+		DRM_ERROR("failed to disable DP controller\n");
+		return ret;
+	}
+
+	ret = dp_ctrl_on(&ctrl->dp_ctrl);
+	if (ret)
+		DRM_ERROR("failed to enable DP controller\n");
+
+	return ret;
+}
+
+static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
+{
+	bool success = false;
+	u32 pattern_sent = 0x0;
+	u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
+
+	DRM_DEBUG_DP("request: 0x%x\n", pattern_requested);
+
+	if (dp_catalog_ctrl_update_vx_px(ctrl->catalog,
+			ctrl->link->phy_params.v_level,
+			ctrl->link->phy_params.p_level)) {
+		DRM_ERROR("Failed to set v/p levels\n");
+		return false;
+	}
+	dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
+	dp_link_send_test_response(ctrl->link);
+
+	pattern_sent = dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
+
+	switch (pattern_sent) {
+	case MR_LINK_TRAINING1:
+		success = pattern_requested ==
+				DP_LINK_QUAL_PATTERN_D10_2;
+		break;
+	case MR_LINK_SYMBOL_ERM:
+		success = (pattern_requested ==
+				DP_LINK_QUAL_PATTERN_ERROR_RATE)
+			|| (pattern_requested ==
+				DP_LINK_QUAL_PATTERN_HBR2_EYE);
+		break;
+	case MR_LINK_PRBS7:
+		success = pattern_requested == DP_LINK_QUAL_PATTERN_PRBS7;
+		break;
+	case MR_LINK_CUSTOM80:
+		success = pattern_requested ==
+				DP_LINK_QUAL_PATTERN_80BIT_CUSTOM;
+		break;
+	default:
+		success = false;
+	}
+
+	DRM_DEBUG_DP("%s: test->0x%x\n", success ? "success" : "failed",
+						pattern_requested);
+	return success;
+}
+
+void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_ctrl.h new file +34 -0
new file mode 100644
index 0000000..99ab4b2

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_display.c new file +949 -0
new file mode 100644
index 0000000..a893542

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_display.h new file +29 -0
new file mode 100644
index 0000000..c916408

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_drm.c new file +173 -0
new file mode 100644
index 0000000..a72b0bb

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_drm.h new file +20 -0
new file mode 100644
index 0000000..cf472c5

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_extcon.c new file +216 -0
new file mode 100644
index 0000000..0fb34ef

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_extcon.h new file +84 -0
new file mode 100644
index 0000000..c6c3051

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_link.c new file +1185 -0
new file mode 100644
index 0000000..9f5b7bc8

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_link.h new file +132 -0
new file mode 100644
index 0000000..607904b

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_panel.c new file +450 -0
new file mode 100644
index 0000000..a3150f4

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_panel.h new file +92 -0
new file mode 100644
index 0000000..68c5650

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_parser.c new file +496 -0
new file mode 100644
index 0000000..3fa2a1f

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_parser.h new file +222 -0
new file mode 100644
index 0000000..b606b40

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_power.c new file +558 -0
new file mode 100644
index 0000000..3fa4c9b

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_power.h new file +52 -0
new file mode 100644
index 0000000..40d7e73

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_reg.h new file +488 -0
new file mode 100644
index 0000000..5468f7b

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/msm_drv.c +2 -0
index c84f0a8..e5e93e3 100644

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/msm_drv.h +42 -0
index 71547e7..8b068ec 100644

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): BYAPR02MB5288D92EF7422BF5C86FC45BA9E70@BYAPR02MB5288.namprd02.prod.outlook.com

#12 lore raw

Re: FW: Re: [DPU PATCH v3 3/5] drm/msm/dp: add displayPort driver support

Hi Matthias

The earlier patchsets of the same series were reviewed by Sean so we were spending our efforts addressing the comments based on the earlier versions. We think the delay in getting reviews and also posting newer versions was not specifically due to the size of the code but also due to business reasons around that time. This is the basic version of the DP driver where all the files are tightly coupled. We understand that this is a big series and we have tried to break it up functionality-wise. For example, we are going to post hot-plug related changes and some more functionality like audio in a later patch. Also, we shall be posting a newer version of this series within a day or two which shall address the comments posted so far along with the checkpatch fixes and changes needed to make DP work on Trogdor. Hence we request that the new version which shall be posted be reviewed first and if there is some split-up which can be done further, let us know and we shall try to address that in the next patchsets.

Thanks

Vara (on behalf of Display team)

Quoted 9,007 lines

-------- Original Message --------
Subject: Re: [DPU PATCH v3 3/5] drm/msm/dp: add displayPort driver support
Date: 2020-02-28 13:49
From: Matthias Kaehlcke <[email protected]>
To: Chandan Uddaraju <[email protected]>
Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]

Hi Chandan,

I have no DRM background, but I suspect one reason this patch hasn't been reviewed in almost 3 months is its size, 8k LOC. I would suggest to split it up into multiple pieces to make a review less daunting. Not sure
what the exact split would be, evaluating it per source file/self contained function could be a starting point.

And please make sure to run scripts/checkpatch.pl before sending patches (especially larger ones), reviewers don't like to spend time pointing out
formatting issues that should have been fixed beforehand:

./scripts/checkpatch.pl DPU-v3-3-5-drm-msm-dp-add-displayPort-driver-support.patch

...

total: 2 errors, 141 warnings, 8440 lines checked

Thanks

Matthias

drivers/gpu/drm/msm/msm_drv.h

Quoted 8,966 lines · Chandan Uddaraju

Add the needed displayPort files to enable DP driver on msm target.

"dp_display" module is the main module that calls into other sub-modules. "dp_drm" file represents the interface between DRM framework and DP driver.

changes in v2:
-- Update copyright markings on all relevant files.
-- Change pr_err() to DRM_ERROR()
-- Use APIs directly instead of function pointers.
-- Use drm_display_mode structure to store link parameters in the driver.
-- Use macros for register definitions instead of hardcoded values. -- Replace writel_relaxed/readl_relaxed with writel/readl
and remove memory barriers.
-- Remove unnecessary NULL checks.
-- Use drm helper functions for dpcd read/write.
-- Use DRM_DEBUG_DP for debug msgs.

changes in V3:
-- Removed changes in dpu_io_util.[ch]
-- Added locking around "is_connected" flag and removed atomic_set() -- Removed the argument validation checks in all the static functions
except initialization functions and few API calls across msm/dp
files
-- Removed hardcoded values for register reads/writes
-- Removed vreg related generic structures.
-- Added return values where ever necessary.
-- Updated dp_ctrl_on function.
-- Calling the ctrl specific catalog functions directly instead of
function pointers.
-- Added seperate change that adds standard value in drm_dp_helper file.
-- Added separate change in this list that is used to initialize
displayport in DPU driver.
-- Added change to use drm_dp_get_adjust_request_voltage() function.

---
 drivers/gpu/drm/msm/Kconfig                 |    9 +
 drivers/gpu/drm/msm/Makefile                |   13 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |   20 +
 drivers/gpu/drm/msm/dp/dp_aux.c             |  548 +++++++++
 drivers/gpu/drm/msm/dp/dp_aux.h             |   37 +
 drivers/gpu/drm/msm/dp/dp_catalog.c         |  841 ++++++++++++++
 drivers/gpu/drm/msm/dp/dp_catalog.h         |   84 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c            | 1590
+++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_ctrl.h            |   34 +
 drivers/gpu/drm/msm/dp/dp_display.c         |  949 ++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_display.h         |   29 +
 drivers/gpu/drm/msm/dp/dp_drm.c             |  173 +++
 drivers/gpu/drm/msm/dp/dp_drm.h             |   20 +
 drivers/gpu/drm/msm/dp/dp_extcon.c          |  216 ++++
 drivers/gpu/drm/msm/dp/dp_extcon.h          |   84 ++
 drivers/gpu/drm/msm/dp/dp_link.c            | 1185
++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_link.h            |  132 +++
 drivers/gpu/drm/msm/dp/dp_panel.c           |  450 ++++++++
 drivers/gpu/drm/msm/dp/dp_panel.h           |   92 ++
 drivers/gpu/drm/msm/dp/dp_parser.c          |  496 +++++++++
 drivers/gpu/drm/msm/dp/dp_parser.h          |  222 ++++
 drivers/gpu/drm/msm/dp/dp_power.c           |  558 ++++++++++
 drivers/gpu/drm/msm/dp/dp_power.h           |   52 +
 drivers/gpu/drm/msm/dp/dp_reg.h             |  488 ++++++++
 drivers/gpu/drm/msm/msm_drv.c               |    2 +
 drivers/gpu/drm/msm/msm_drv.h               |   42 +
 26 files changed, 8366 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_display.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_display.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_drm.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_drm.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_extcon.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_extcon.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_link.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_link.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_panel.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_panel.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_parser.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_parser.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_power.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_power.h
 create mode 100644 drivers/gpu/drm/msm/dp/dp_reg.h
drivers/gpu/drm/msm/Kconfig +9 -0
index 6deaa7d..7946cb1 100644
@@ -57,6 +57,15 @@ config DRM_MSM_HDMI_HDCP
 help
   Choose this option to enable HDCP state machine
 
+config DRM_MSM_DP
+bool "Enable DP support in MSM DRM driver"
+depends on DRM_MSM
+default n
+help
+  Compile in support for DP driver in msm drm driver. DP external
+  display support is enabled through this config option. It can
+  be primary or secondary display on device.
+
 config DRM_MSM_DSI
 bool "Enable DSI support in MSM DRM driver"
 depends on DRM_MSM
drivers/gpu/drm/msm/Makefile +13 -0
index 1579cf0..5939f41 100644
@@ -2,6 +2,7 @@
 ccflags-y := -I $(srctree)/$(src)
 ccflags-y += -I $(srctree)/$(src)/disp/dpu1
 ccflags-$(CONFIG_DRM_MSM_DSI) += -I $(srctree)/$(src)/dsi
+ccflags-$(CONFIG_DRM_MSM_DP) += -I $(srctree)/$(src)/dp
 
 msm-y := \
 adreno/adreno_device.o \
@@ -96,8 +97,20 @@ msm-y := \
 
 msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o
 
+
 msm-$(CONFIG_DRM_MSM_GPU_STATE)+= adreno/a6xx_gpu_state.o
 
+msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
+dp/dp_catalog.o \
+dp/dp_ctrl.o \
+dp/dp_display.o \
+dp/dp_drm.o \
+dp/dp_extcon.o \
+dp/dp_link.o \
+dp/dp_panel.o \
+dp/dp_parser.o \
+dp/dp_power.o
+
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o
 msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +3 -0
index f96e142..29ac7d3 100644
@@ -967,6 +967,9 @@ static void dpu_encoder_virt_mode_set(struct
 drm_encoder *drm_enc,
 
 trace_dpu_enc_mode_set(DRMID(drm_enc));
 
+if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp)
+msm_dp_display_mode_set(priv->dp, drm_enc, mode, adj_mode);
+
 list_for_each_entry(conn_iter, connector_list, head)
 if (conn_iter->encoder == drm_enc)

conn = conn_iter;

drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +1 -0
@@ -1133,6 +1136,7 @@ static void dpu_encoder_virt_enable(struct
 drm_encoder *drm_enc)
 {
 struct dpu_encoder_virt *dpu_enc = NULL;
 int ret = 0;
+struct msm_drm_private *priv;
 struct drm_display_mode *cur_mode = NULL;
 

if (!drm_enc) {

drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +1 -0
@@ -1143,6 +1147,7 @@ static void dpu_encoder_virt_enable(struct
 drm_encoder *drm_enc)
 
 mutex_lock(&dpu_enc->enc_lock);
 cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
+priv = drm_enc->dev->dev_private;
 
 trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
      cur_mode->vdisplay);
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +9 -0
@@ -1163,6 +1168,15 @@ static void dpu_encoder_virt_enable(struct
 drm_encoder *drm_enc)
 
 _dpu_encoder_virt_enable_helper(drm_enc);
 
+if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
+ret = msm_dp_display_enable(priv->dp,
+drm_enc);
+if (ret) {
+DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n",
+ret);
+goto out;
+}
+}
 dpu_enc->enabled = true;
 

out:

drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +6 -0
@@ -1193,6 +1207,12 @@ static void dpu_encoder_virt_disable(struct
 drm_encoder *drm_enc)
 priv = drm_enc->dev->dev_private;
 dpu_kms = to_dpu_kms(priv->kms);
 
+if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
+if (msm_dp_display_disable(priv->dp, drm_enc)) {
+DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n");
+return;
+  }
+}
 trace_dpu_enc_disable(DRMID(drm_enc));
 

/* wait for idle */

drivers/gpu/drm/msm/dp/dp_aux.c new file +3 -0
new file mode 100644
index 0000000..a6bb52a
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights 

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_aux.c new file +221 -0
+
+#define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__
+
+#include <linux/delay.h>
+
+#include "dp_reg.h"
+#include "dp_aux.h"
+
+#define DP_AUX_ENUM_STR(x)#x
+
+struct dp_aux_private {
+struct device *dev;
+struct dp_aux dp_aux;
+struct dp_catalog *catalog;
+
+struct mutex mutex;
+struct completion comp;
+
+u32 aux_error_num;
+u32 retry_cnt;
+bool cmd_busy;
+bool native;
+bool read;
+bool no_send_addr;
+bool no_send_stop;
+u32 offset;
+u32 segment;
+u32 isr;
+
+struct drm_dp_aux drm_aux;
+};
+
+static char *dp_aux_get_error(u32 aux_error)
+{
+switch (aux_error) {
+case DP_AUX_ERR_NONE:
+return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE);
+case DP_AUX_ERR_ADDR:
+return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR);
+case DP_AUX_ERR_TOUT:
+return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT);
+case DP_AUX_ERR_NACK:
+return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK);
+case DP_AUX_ERR_DEFER:
+return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER);
+case DP_AUX_ERR_NACK_DEFER:
+return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER);
+default:
+return "unknown";
+}
+}
+
+static u32 dp_aux_write(struct dp_aux_private *aux,
+struct drm_dp_aux_msg *msg)
+{
+u32 data[4], reg, len;
+u8 *msgdata = msg->buffer;
+int const aux_cmd_fifo_len = 128;
+int i = 0;
+
+if (aux->read)
+len = 4;
+else
+len = msg->size + 4;
+
+/*
+ * cmd fifo only has depth of 144 bytes
+ * limit buf length to 128 bytes here
+ */
+if (len > aux_cmd_fifo_len) {
+DRM_ERROR("buf len error\n");
+return 0;
+}
+
+/* Pack cmd and write to HW */
+data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
+if (aux->read)
+data[0] |=  BIT(4); /* R/W */
+
+data[1] = (msg->address >> 8) & 0xff;/* addr[15:8] */
+data[2] = msg->address & 0xff;/* addr[7:0] */
+data[3] = (msg->size - 1) & 0xff;/* len[7:0] */
+
+for (i = 0; i < len; i++) {
+reg = (i < 4) ? data[i] : msgdata[i - 4];
+/* index = 0, write */
+reg = (((reg) << DP_AUX_DATA_OFFSET)
+       & DP_AUX_DATA_MASK) | DP_AUX_DATA_WRITE;
+if (i == 0)
+reg |= DP_AUX_DATA_INDEX_WRITE;
+aux->catalog->aux_data = reg;
+dp_catalog_aux_write_data(aux->catalog);
+}
+
+dp_catalog_aux_clear_trans(aux->catalog, false);
+
+reg = 0; /* Transaction number == 1 */
+if (!aux->native) { /* i2c */
+reg |= DP_AUX_TRANS_CTRL_I2C;
+
+if (aux->no_send_addr)
+reg |= DP_AUX_TRANS_CTRL_NO_SEND_ADDR;
+
+if (aux->no_send_stop)
+reg |= DP_AUX_TRANS_CTRL_NO_SEND_STOP;
+}
+
+reg |= DP_AUX_TRANS_CTRL_GO;
+aux->catalog->aux_data = reg;
+dp_catalog_aux_write_trans(aux->catalog);
+
+return len;
+}
+
+static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
+      struct drm_dp_aux_msg *msg)
+{
+u32 ret = 0, len = 0, timeout;
+int const aux_timeout_ms = HZ/4;
+
+reinit_completion(&aux->comp);
+
+len = dp_aux_write(aux, msg);
+if (len == 0) {
+DRM_ERROR("DP AUX write failed\n");
+return -EINVAL;
+}
+
+timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
+if (!timeout) {
+DRM_ERROR("aux %s timeout\n", (aux->read ? "read" : "write"));
+return -ETIMEDOUT;
+}
+
+if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+ret = len;
+} else {
+DRM_ERROR_RATELIMITED("aux err: %s\n",
+dp_aux_get_error(aux->aux_error_num));
+
+ret = -EINVAL;
+}
+
+return ret;
+}
+
+static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
+struct drm_dp_aux_msg *msg)
+{
+u32 data;
+u8 *dp;
+u32 i, actual_i;
+u32 len = msg->size;
+
+dp_catalog_aux_clear_trans(aux->catalog, true);
+
+data = 0;
+data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
+data |= DP_AUX_DATA_READ;  /* read */
+
+aux->catalog->aux_data = data;
+dp_catalog_aux_write_data(aux->catalog);
+
+dp = msg->buffer;
+
+/* discard first byte */
+data = dp_catalog_aux_read_data(aux->catalog);
+
+for (i = 0; i < len; i++) {
+data = dp_catalog_aux_read_data(aux->catalog);
+*dp++ = (u8)((data >> DP_AUX_DATA_OFFSET) & 0xff);
+
+actual_i = (data >> DP_AUX_DATA_INDEX_OFFSET) & 0xFF;
+if (i != actual_i)
+pr_warn("Index mismatch: expected %d, found %d\n",
+i, actual_i);
+}
+}
+
+static void dp_aux_native_handler(struct dp_aux_private *aux)
+{
+u32 isr = aux->isr;
+
+if (isr & DP_INTR_AUX_I2C_DONE)
+aux->aux_error_num = DP_AUX_ERR_NONE;
+else if (isr & DP_INTR_WRONG_ADDR)
+aux->aux_error_num = DP_AUX_ERR_ADDR;
+else if (isr & DP_INTR_TIMEOUT)
+aux->aux_error_num = DP_AUX_ERR_TOUT;
+if (isr & DP_INTR_NACK_DEFER)
+aux->aux_error_num = DP_AUX_ERR_NACK;
+
+complete(&aux->comp);
+}
+
+static void dp_aux_i2c_handler(struct dp_aux_private *aux)
+{
+u32 isr = aux->isr;
+
+if (isr & DP_INTR_AUX_I2C_DONE) {
+if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER))
+aux->aux_error_num = DP_AUX_ERR_NACK;
+else
+aux->aux_error_num = DP_AUX_ERR_NONE;
+} else {
+if (isr & DP_INTR_WRONG_ADDR)
+aux->aux_error_num = DP_AUX_ERR_ADDR;
+else if (isr & DP_INTR_TIMEOUT)
+aux->aux_error_num = DP_AUX_ERR_TOUT;
+if (isr & DP_INTR_NACK_DEFER)
+aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
+if (isr & DP_INTR_I2C_NACK)
+aux->aux_error_num = DP_AUX_ERR_NACK;
+if (isr & DP_INTR_I2C_DEFER)
+aux->aux_error_num = DP_AUX_ERR_DEFER;
+}
+
+complete(&aux->comp);
+}
+
+static void dp_aux_update_offset_and_segment(struct dp_aux_private

*aux,

drivers/gpu/drm/msm/dp/dp_aux.c new file +9 -0
+     struct drm_dp_aux_msg *input_msg)
+{
+u32 const edid_address = 0x50;
+u32 const segment_address = 0x30;
+bool i2c_read = input_msg->request &
+(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+u8 *data = NULL;
+
+if (aux->native || i2c_read || ((input_msg->address != edid_address)

&&

drivers/gpu/drm/msm/dp/dp_aux.c new file +13 -0
+(input_msg->address != segment_address)))
+return;
+
+
+data = input_msg->buffer;
+if (input_msg->address == segment_address)
+aux->segment = *data;
+else
+aux->offset = *data;
+}
+
+/**
+ * dp_aux_transfer_helper() - helper function for EDID read

transactions
+ *
+ * @aux: DP AUX private structure
+ * @input_msg: input message from DRM upstream APIs
+ *
+ * return: void
+ *
+ * This helper function is used to fix EDID reads for non-compliant
+ * sinks that do not handle the i2c middle-of-transaction flag correctly.
+ */

drivers/gpu/drm/msm/dp/dp_aux.c new file +67 -0
+static void dp_aux_transfer_helper(struct dp_aux_private *aux,
+   struct drm_dp_aux_msg *input_msg)
+{
+struct drm_dp_aux_msg helper_msg;
+u32 const message_size = 0x10;
+u32 const segment_address = 0x30;
+bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
+bool i2c_read = input_msg->request &
+(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+if (!i2c_mot || !i2c_read || (input_msg->size == 0))
+return;
+
+aux->read = false;
+aux->cmd_busy = true;
+aux->no_send_addr = true;
+aux->no_send_stop = true;
+
+/*
+ * Send the segment address for every i2c read in which the
+ * middle-of-tranaction flag is set. This is required to support EDID
+ * reads of more than 2 blocks as the segment address is reset to 0
+ * since we are overriding the middle-of-transaction flag for read
+ * transactions.
+ */
+memset(&helper_msg, 0, sizeof(helper_msg));
+helper_msg.address = segment_address;
+helper_msg.buffer = &aux->segment;
+helper_msg.size = 1;
+dp_aux_cmd_fifo_tx(aux, &helper_msg);
+
+/*
+ * Send the offset address for every i2c read in which the
+ * middle-of-transaction flag is set. This will ensure that the sink
+ * will update its read pointer and return the correct portion of the
+ * EDID buffer in the subsequent i2c read trasntion triggered in the
+ * native AUX transfer function.
+ */
+memset(&helper_msg, 0, sizeof(helper_msg));
+helper_msg.address = input_msg->address;
+helper_msg.buffer = &aux->offset;
+helper_msg.size = 1;
+dp_aux_cmd_fifo_tx(aux, &helper_msg);
+aux->offset += message_size;
+
+if (aux->offset == 0x80 || aux->offset == 0x100)
+aux->segment = 0x0; /* reset segment at end of block */
+}
+
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call aux_reset() function to reset the AUX channel,
+ * if the waiting is timeout.
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
+       struct drm_dp_aux_msg *msg)
+{
+ssize_t ret;
+int const aux_cmd_native_max = 16;
+int const aux_cmd_i2c_max = 128;
+int const retry_count = 5;
+struct dp_aux_private *aux = container_of(drm_aux,
+struct dp_aux_private, drm_aux);
+
+mutex_lock(&aux->mutex);
+
+aux->native = msg->request & (DP_AUX_NATIVE_WRITE &

DP_AUX_NATIVE_READ);

drivers/gpu/drm/msm/dp/dp_aux.c new file +67 -0
+
+/* Ignore address only message */
+if ((msg->size == 0) || (msg->buffer == NULL)) {
+msg->reply = aux->native ?
+DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+ret = msg->size;
+goto unlock_exit;
+}
+
+/* msg sanity check */
+if ((aux->native && (msg->size > aux_cmd_native_max)) ||
+(msg->size > aux_cmd_i2c_max)) {
+DRM_ERROR("%s: invalid msg: size(%zu), request(%x)\n",
+__func__, msg->size, msg->request);
+ret = -EINVAL;
+goto unlock_exit;
+}
+
+dp_aux_update_offset_and_segment(aux, msg);
+dp_aux_transfer_helper(aux, msg);
+
+aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+aux->cmd_busy = true;
+
+if (aux->read) {
+aux->no_send_addr = true;
+aux->no_send_stop = false;
+} else {
+aux->no_send_addr = true;
+aux->no_send_stop = true;
+}
+
+ret = dp_aux_cmd_fifo_tx(aux, msg);
+if ((ret < 0) && aux->native) {
+aux->retry_cnt++;
+if (!(aux->retry_cnt % retry_count))
+dp_catalog_aux_update_cfg(aux->catalog,
+aux->dp_aux.cfg, PHY_AUX_CFG1);
+dp_catalog_aux_reset(aux->catalog);
+goto unlock_exit;
+} else if (ret < 0) {
+goto unlock_exit;
+}
+
+if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+if (aux->read)
+dp_aux_cmd_fifo_rx(aux, msg);
+
+msg->reply = aux->native ?
+DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+} else {
+/* Reply defer to retry */
+msg->reply = aux->native ?
+DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+}
+
+/* Return requested size for success or retry */
+ret = msg->size;
+aux->retry_cnt = 0;
+
+unlock_exit:
+aux->cmd_busy = false;
+mutex_unlock(&aux->mutex);
+return ret;
+}
+
+static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg

*aux_cfg)

drivers/gpu/drm/msm/dp/dp_aux.c new file +112 -0
+{
+int i = 0;
+
+for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+aux_cfg[i].current_index = 0;
+}
+
+void dp_aux_isr(struct dp_aux *dp_aux)
+{
+struct dp_aux_private *aux;
+
+if (!dp_aux) {
+DRM_ERROR("invalid input\n");
+return;
+}
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+aux->isr = dp_catalog_aux_get_irq(aux->catalog);
+
+if (!aux->cmd_busy)
+return;
+
+if (aux->native)
+dp_aux_native_handler(aux);
+else
+dp_aux_i2c_handler(aux);
+}
+
+void dp_aux_reconfig(struct dp_aux *dp_aux)
+{
+struct dp_aux_private *aux;
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+dp_catalog_aux_update_cfg(aux->catalog,
+dp_aux->cfg, PHY_AUX_CFG1);
+dp_catalog_aux_reset(aux->catalog);
+}
+
+void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
+{
+struct dp_aux_private *aux;
+
+if (!dp_aux || !aux_cfg) {
+DRM_ERROR("invalid input\n");
+return;
+}
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+dp_aux_reset_phy_config_indices(aux_cfg);
+dp_catalog_aux_setup(aux->catalog, aux_cfg);
+dp_catalog_aux_reset(aux->catalog);
+dp_catalog_aux_enable(aux->catalog, true);
+aux->retry_cnt = 0;
+}
+
+void dp_aux_deinit(struct dp_aux *dp_aux)
+{
+struct dp_aux_private *aux;
+
+if (!dp_aux) {
+DRM_ERROR("invalid input\n");
+return;
+}
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+dp_catalog_aux_enable(aux->catalog, false);
+}
+
+int dp_aux_register(struct dp_aux *dp_aux)
+{
+struct dp_aux_private *aux;
+int ret = 0;
+
+if (!dp_aux) {
+DRM_ERROR("invalid input\n");
+ret = -EINVAL;
+goto exit;
+}
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+aux->drm_aux.name = "dpu_dp_aux";
+aux->drm_aux.dev = aux->dev;
+aux->drm_aux.transfer = dp_aux_transfer;
+ret = drm_dp_aux_register(&aux->drm_aux);
+if (ret) {
+DRM_ERROR("%s: failed to register drm aux: %d\n", __func__, ret);
+goto exit;
+}
+dp_aux->drm_aux = &aux->drm_aux;
+exit:
+return ret;
+}
+
+void dp_aux_unregister(struct dp_aux *dp_aux)
+{
+struct dp_aux_private *aux;
+
+if (!dp_aux) {
+DRM_ERROR("invalid input\n");
+return;
+}
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+drm_dp_aux_unregister(&aux->drm_aux);
+}
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog

*catalog,

drivers/gpu/drm/msm/dp/dp_aux.c new file +46 -0
+  struct dp_aux_cfg *aux_cfg)
+{
+int rc = 0;
+struct dp_aux_private *aux;
+struct dp_aux *dp_aux;
+
+if (!catalog || !aux_cfg) {
+DRM_ERROR("invalid input\n");
+rc = -ENODEV;
+goto error;
+}
+
+aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
+if (!aux) {
+rc = -ENOMEM;
+goto error;
+}
+
+init_completion(&aux->comp);
+aux->cmd_busy = false;
+mutex_init(&aux->mutex);
+
+aux->dev = dev;
+aux->catalog = catalog;
+aux->dp_aux.cfg = aux_cfg;
+dp_aux = &aux->dp_aux;
+aux->retry_cnt = 0;
+
+return dp_aux;
+error:
+return ERR_PTR(rc);
+}
+
+void dp_aux_put(struct dp_aux *dp_aux)
+{
+struct dp_aux_private *aux;
+
+if (!dp_aux)
+return;
+
+aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+mutex_destroy(&aux->mutex);
+
+devm_kfree(aux->dev, aux);
+}
drivers/gpu/drm/msm/dp/dp_aux.h new file +3 -0
new file mode 100644
index 0000000..8ce2221
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights 

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_aux.h new file +29 -0
+
+#ifndef _DP_AUX_H_
+#define _DP_AUX_H_
+
+#include "dp_catalog.h"
+#include <drm/drm_dp_helper.h>
+
+enum dp_aux_error {
+DP_AUX_ERR_NONE= 0,
+DP_AUX_ERR_ADDR= -1,
+DP_AUX_ERR_TOUT= -2,
+DP_AUX_ERR_NACK= -3,
+DP_AUX_ERR_DEFER= -4,
+DP_AUX_ERR_NACK_DEFER= -5,
+};
+
+struct dp_aux {
+struct drm_dp_aux *drm_aux;
+struct dp_aux_cfg *cfg;
+};
+
+int dp_aux_register(struct dp_aux *aux);
+void dp_aux_unregister(struct dp_aux *aux);
+void dp_aux_isr(struct dp_aux *aux);
+void dp_aux_init(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
+void dp_aux_deinit(struct dp_aux *aux);
+void dp_aux_reconfig(struct dp_aux *aux);
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog

*catalog,

drivers/gpu/drm/msm/dp/dp_aux.h new file +4 -0
+  struct dp_aux_cfg *aux_cfg);
+void dp_aux_put(struct dp_aux *aux);
+
+#endif /*__DP_AUX_H_*/
drivers/gpu/drm/msm/dp/dp_catalog.c new file +3 -0
new file mode 100644
index 0000000..51e21bb
@@ -0,0 +1,841 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights 

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_catalog.c new file +27 -0
+
+#define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <drm/drm_dp_helper.h>
+
+#include "dp_catalog.h"
+#include "dp_reg.h"
+
+#define POLLING_SLEEP_US1000
+#define POLLING_TIMEOUT_US10000
+
+#define REFTIMER_DEFAULT_VALUE0x20000
+#define SCRAMBLER_RESET_COUNT_VALUE0xFC
+
+#define DP_INTERRUPT_STATUS_ACK_SHIFT1
+#define DP_INTERRUPT_STATUS_MASK_SHIFT2
+
+#define DP_INTERRUPT_STATUS1 \
+(DP_INTR_AUX_I2C_DONE| \
+DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \
+DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \
+DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \
+DP_INTR_PLL_UNLOCKED | DP_INTR_AUX_ERROR)
+
+#define DP_INTERRUPT_STATUS1_ACK (DP_INTERRUPT_STATUS1 <<

DP_INTERRUPT_STATUS_ACK_SHIFT)
+#define DP_INTERRUPT_STATUS1_MASK (DP_INTERRUPT_STATUS1 << DP_INTERRUPT_STATUS_MASK_SHIFT)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +6 -0
+
+#define DP_INTERRUPT_STATUS2 \
+(DP_INTR_READY_FOR_VIDEO | DP_INTR_IDLE_PATTERN_SENT | \
+DP_INTR_FRAME_END | DP_INTR_CRC_UPDATED)
+
+#define DP_INTERRUPT_STATUS2_ACK (DP_INTERRUPT_STATUS2 <<

DP_INTERRUPT_STATUS_ACK_SHIFT)
+#define DP_INTERRUPT_STATUS2_MASK (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +23 -0
+
+static u8 const vm_pre_emphasis[4][4] = {
+{0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
+{0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
+{0x00, 0x0C, 0xFF, 0xFF},       /* pe2, 6.0 db */
+{0xFF, 0xFF, 0xFF, 0xFF}        /* pe3, 9.5 db */
+};
+
+/* voltage swing, 0.2v and 1.0v are not support */
+static u8 const vm_voltage_swing[4][4] = {
+{0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v  */
+{0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
+{0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
+{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
+};
+
+struct dp_catalog_private {
+struct device *dev;
+struct dp_io *io;
+struct dp_catalog dp_catalog;
+};
+
+static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32

offset)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +15 -0
+{
+return readl_relaxed(catalog->io->dp_aux.base + offset);
+}
+
+static inline void dp_write_aux(struct dp_catalog_private *catalog,
+       u32 offset, u32 data)
+{
+/*
+ * To make sure aux reg writes happens before any other operation,
+ * this function uses writel() instread of writel_relaxed()
+ */
+writel(data, catalog->io->dp_aux.base + offset);
+}
+
+static inline u32 dp_read_ahb(struct dp_catalog_private *catalog, u32

offset)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +15 -0
+{
+return readl_relaxed(catalog->io->dp_ahb.base + offset);
+}
+
+static inline void dp_write_ahb(struct dp_catalog_private *catalog,
+       u32 offset, u32 data)
+{
+/*
+ * To make sure phy reg writes happens before any other operation,
+ * this function uses writel() instread of writel_relaxed()
+ */
+writel(data, catalog->io->dp_ahb.base + offset);
+}
+
+static inline u32 dp_read_cc(struct dp_catalog_private *catalog, u32

offset)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +21 -0
+{
+return readl_relaxed(catalog->io->dp_cc_io.base + offset);
+}
+
+static inline void dp_write_phy(struct dp_catalog_private *catalog,
+       u32 offset, u32 data)
+{
+/*
+ * To make sure phy reg writes happens before any other operation,
+ * this function uses writel() instread of writel_relaxed()
+ */
+writel(data, catalog->io->phy_io.base + offset);
+}
+
+static inline void dp_write_pll(struct dp_catalog_private *catalog,
+       u32 offset, u32 data)
+{
+writel_relaxed(data, catalog->io->dp_pll_io.base + offset);
+}
+
+static inline void dp_write_ln_tx0(struct dp_catalog_private 

*catalog,

drivers/gpu/drm/msm/dp/dp_catalog.c new file +6 -0
+       u32 offset, u32 data)
+{
+writel_relaxed(data, catalog->io->ln_tx0_io.base + offset);
+}
+
+static inline void dp_write_ln_tx1(struct dp_catalog_private 

*catalog,

drivers/gpu/drm/msm/dp/dp_catalog.c new file +6 -0
+       u32 offset, u32 data)
+{
+writel_relaxed(data, catalog->io->ln_tx1_io.base + offset);
+}
+
+static inline void dp_write_usb_cm(struct dp_catalog_private 

*catalog,

drivers/gpu/drm/msm/dp/dp_catalog.c new file +14 -0
+       u32 offset, u32 data)
+{
+/*
+ * To make sure usb reg writes happens before any other operation,
+ * this function uses writel() instread of writel_relaxed()
+ */
+writel(data, catalog->io->usb3_dp_com.base + offset);
+}
+
+static inline void dp_write_p0(struct dp_catalog_private *catalog,
+       u32 offset, u32 data)
+{
+/*
+ * To make sure interface reg writes happens before any other

operation,
+ * this function uses writel() instread of writel_relaxed()
+ */

drivers/gpu/drm/msm/dp/dp_catalog.c new file +4 -0
+writel(data, catalog->io->dp_p0.base + offset);
+}
+
+static inline u32 dp_read_link(struct dp_catalog_private *catalog, 

u32
offset)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +44 -0
+{
+return readl_relaxed(catalog->io->dp_link.base + offset);
+}
+
+static inline void dp_write_link(struct dp_catalog_private *catalog,
+       u32 offset, u32 data)
+{
+/*
+ * To make sure link reg writes happens before any other operation,
+ * this function uses writel() instread of writel_relaxed()
+ */
+writel(data, catalog->io->dp_link.base + offset);
+}
+
+/* aux related catalog functions */
+u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+return dp_read_aux(catalog, REG_DP_AUX_DATA);
+}
+
+int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog)
+{
+int rc = 0;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_aux(catalog, REG_DP_AUX_DATA, dp_catalog->aux_data);
+return rc;
+}
+
+int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog)
+{
+int rc = 0;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, dp_catalog->aux_data);
+return rc;
+}
+
+int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool

read)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +33 -0
+{
+int rc = 0;
+u32 data = 0;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+if (read) {
+data = dp_read_aux(catalog, REG_DP_AUX_TRANS_CTRL);
+data &= ~DP_AUX_TRANS_CTRL_GO;
+dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, data);
+} else {
+dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, 0);
+}
+return rc;
+}
+
+void dp_catalog_aux_reset(struct dp_catalog *dp_catalog)
+{
+u32 aux_ctrl;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+aux_ctrl = dp_read_aux(catalog, REG_DP_AUX_CTRL);
+
+aux_ctrl |= DP_AUX_CTRL_RESET;
+dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
+usleep_range(1000, 1100); /* h/w recommended delay */
+
+aux_ctrl &= ~DP_AUX_CTRL_RESET;
+dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
+}
+
+void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool 

enable)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +68 -0
+{
+u32 aux_ctrl;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+aux_ctrl = dp_read_aux(catalog, REG_DP_AUX_CTRL);
+
+if (enable) {
+dp_write_aux(catalog, REG_DP_TIMEOUT_COUNT, 0xffff);
+dp_write_aux(catalog, REG_DP_AUX_LIMITS, 0xffff);
+aux_ctrl |= DP_AUX_CTRL_ENABLE;
+} else {
+aux_ctrl &= ~DP_AUX_CTRL_ENABLE;
+}
+
+dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
+}
+
+void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog,
+struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 new_index = 0, current_index = 0;
+
+if (type >= PHY_AUX_CFG_MAX) {
+DRM_ERROR("invalid input\n");
+return;
+}
+
+current_index = cfg[type].current_index;
+new_index = (current_index + 1) % cfg[type].cfg_cnt;
+DRM_DEBUG_DP("Updating %s from 0x%08x to 0x%08x\n",
+dp_phy_aux_config_type_to_string(type),
+cfg[type].lut[current_index], cfg[type].lut[new_index]);
+
+dp_write_phy(catalog, cfg[type].offset,
+cfg[type].lut[new_index]);
+cfg[type].current_index = new_index;
+}
+
+void dp_catalog_aux_setup(struct dp_catalog *dp_catalog,
+struct dp_aux_cfg *cfg)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+int i = 0;
+
+dp_write_phy(catalog, REG_DP_PHY_PD_CTL, DP_PHY_PD_CTL_PWRDN |
+DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN |
+DP_PHY_PD_CTL_DP_CLAMP_EN);
+
+/* Turn on BIAS current for PHY/PLL */
+dp_write_pll(catalog,
+QSERDES_COM_BIAS_EN_CLKBUFLR_EN, QSERDES_COM_BIAS_EN |
+QSERDES_COM_BIAS_EN_MUX | QSERDES_COM_CLKBUF_L_EN |
+QSERDES_COM_EN_SYSCLK_TX_SEL);
+
+/* DP AUX CFG register programming */
+for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
+DRM_DEBUG_DP("%s: offset=0x%08x, value=0x%08x\n",
+dp_phy_aux_config_type_to_string(i),
+cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
+dp_write_phy(catalog, cfg[i].offset,
+cfg[i].lut[cfg[i].current_index]);
+}
+
+dp_write_phy(catalog, REG_DP_PHY_AUX_INTERRUPT_MASK,

PHY_AUX_STOP_ERR_MASK |

drivers/gpu/drm/msm/dp/dp_catalog.c new file +13 -0
+PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK |
+PHY_AUX_ALIGN_ERR_MASK | PHY_AUX_REQ_ERR_MASK);
+}
+
+int dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 intr, intr_ack;
+
+intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS);
+intr &= ~DP_INTERRUPT_STATUS1_MASK;
+intr_ack = (intr & DP_INTERRUPT_STATUS1) <<

DP_INTERRUPT_STATUS_ACK_SHIFT; +dp_write_ahb(catalog, REG_DP_INTR_STATUS, intr_ack | DP_INTERRUPT_STATUS1_MASK);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +7 -0
+
+return intr;
+
+}
+
+/* controller related catalog functions */
+void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog

*dp_catalog,

drivers/gpu/drm/msm/dp/dp_catalog.c new file +11 -0
+u32 dp_tu, u32 valid_boundary, u32 valid_boundary2)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_link(catalog, REG_DP_VALID_BOUNDARY, valid_boundary);
+dp_write_link(catalog, REG_DP_TU, dp_tu);
+dp_write_link(catalog, REG_DP_VALID_BOUNDARY_2, valid_boundary2);
+}
+
+void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32

state)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +8 -0
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_link(catalog, REG_DP_STATE_CTRL, state);
+}
+
+void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32

cfg)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +22 -0
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+DRM_DEBUG_DP("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
+
+dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
+}
+
+void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
+u32 ln_mapping;
+
+ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
+ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
+ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
+ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
+
+dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING,

ln_mapping);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +13 -0
+}
+
+void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
+bool enable)
+{
+u32 mainlink_ctrl;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+if (enable) {
+/*
+* To make sure link reg writes happens before any other operation,
+* dp_write_link() function uses writel() instread of

writel_relaxed()

drivers/gpu/drm/msm/dp/dp_catalog.c new file +2 -0
+*/
+dp_write_link(catalog, REG_DP_MAINLINK_CTRL,

DP_MAINLINK_FB_BOUNDARY_SEL);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +3 -0
+dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
+DP_MAINLINK_FB_BOUNDARY_SEL | DP_MAINLINK_CTRL_RESET);
+dp_write_link(catalog, REG_DP_MAINLINK_CTRL,

DP_MAINLINK_FB_BOUNDARY_SEL);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +97 -0
+dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
+DP_MAINLINK_FB_BOUNDARY_SEL | DP_MAINLINK_CTRL_ENABLE);
+} else {
+mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE;
+dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
+}
+}
+
+void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog,
+u32 colorimetry_cfg, u32 test_bits_depth)
+{
+u32 misc_val;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+misc_val = dp_read_link(catalog, REG_DP_MISC1_MISC0);
+misc_val |= colorimetry_cfg << DP_MISC0_COLORIMETRY_CFG_SHIFT;
+misc_val |= test_bits_depth << DP_MISC0_TEST_BITS_DEPTH_SHIFT;
+/* Configure clock to synchronous mode */
+misc_val |= DP_MISC0_SYNCHRONOUS_CLK;
+
+DRM_DEBUG_DP("misc settings = 0x%x\n", misc_val);
+dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
+}
+
+void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
+u32 rate, u32 stream_rate_khz,
+bool fixed_nvid)
+{
+u32 pixel_m, pixel_n;
+u32 mvid, nvid;
+u64 mvid_calc;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+if (fixed_nvid) {
+nvid = DP_LINK_CONSTANT_N_VALUE;
+DRM_DEBUG_DP("use fixed NVID=0x%x\n", nvid);
+
+/*
+ * For intermediate results, use 64 bit arithmetic to avoid
+ * loss of precision.
+ */
+mvid_calc = (u64) stream_rate_khz * nvid;
+mvid_calc = div_u64(mvid_calc, rate);
+
+/*
+ * truncate back to 32 bits as this final divided value will
+ * always be within the range of a 32 bit unsigned int.
+ */
+mvid = (u32) mvid_calc;
+DRM_DEBUG_DP("link rate=%dkbps, stream_rate_khz=%uKhz",
+rate, stream_rate_khz);
+} else {
+pixel_m = dp_read_cc(catalog, MMSS_DP_PIXEL_M);
+pixel_n = dp_read_cc(catalog, MMSS_DP_PIXEL_N);
+DRM_DEBUG_DP("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
+
+mvid = (pixel_m & 0xFFFF) * 5;
+nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
+
+DRM_DEBUG_DP("rate = %d\n", rate);
+
+switch (drm_dp_link_rate_to_bw_code(rate)) {
+case DP_LINK_BW_5_4:
+nvid *= 2;
+break;
+case DP_LINK_BW_8_1:
+nvid *= 3;
+break;
+default:
+break;
+}
+}
+
+DRM_DEBUG_DP("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
+dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid);
+dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid);
+}
+
+int dp_catalog_ctrl_set_pattern(struct dp_catalog *dp_catalog,
+u32 pattern)
+{
+int bit, ret;
+u32 data;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+bit = BIT(pattern - 1);
+DRM_DEBUG_DP("hw: bit=%d train=%d\n", bit, pattern);
+dp_write_link(catalog, REG_DP_STATE_CTRL, bit);
+
+bit = BIT(pattern - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT;
+
+/* Poll for mainlink ready status */
+ret = readx_poll_timeout(readl, catalog->io->dp_link.base +

REG_DP_MAINLINK_READY,
+ data, data & bit,
+ POLLING_SLEEP_US, POLLING_TIMEOUT_US);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +8 -0
+if (ret < 0) {
+DRM_ERROR("set pattern for link_train=%d failed\n", pattern);
+return ret;
+}
+return 0;
+}
+
+void dp_catalog_ctrl_usb_reset(struct dp_catalog *dp_catalog, bool

flip)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +79 -0
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 typec_ctrl;
+
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_RESET_OVRD_CTRL,
+USB3_DP_COM_OVRD_CTRL_SW_DPPHY_RESET_MUX |
+USB3_DP_COM_OVRD_CTRL_SW_USB3PHY_RESET_MUX);
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_PHY_MODE_CTRL,
+USB3_DP_COM_PHY_MODE_DP);
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_SW_RESET,
+USB3_DP_COM_SW_RESET_SET);
+
+/* Default configuration i.e CC1 */
+typec_ctrl = USB3_DP_COM_TYPEC_CTRL_PORTSEL_MUX;
+if (flip)
+typec_ctrl |= USB3_DP_COM_TYPEC_CTRL_PORTSEL;
+
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_TYPEC_CTRL, typec_ctrl);
+
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_SWI_CTRL, 0x00);
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_SW_RESET, 0x00);
+
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_POWER_DOWN_CTRL,
+USB3_DP_COM_POWER_DOWN_CTRL_SW_PWRDN);
+dp_write_usb_cm(catalog, REG_USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
+
+}
+
+void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog)
+{
+u32 sw_reset;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+void __iomem *base;
+
+base = catalog->io->dp_ahb.base;
+
+sw_reset = dp_read_ahb(catalog, REG_DP_SW_RESET);
+
+sw_reset |= DP_SW_RESET;
+dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset);
+usleep_range(1000, 1100); /* h/w recommended delay */
+
+sw_reset &= ~DP_SW_RESET;
+dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset);
+}
+
+bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog)
+{
+u32 data;
+int ret;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+/* Poll for mainlink ready status */
+ret = readx_poll_timeout(readl,
+ catalog->io->dp_link.base + REG_DP_MAINLINK_READY,
+ data, data & DP_MAINLINK_READY_FOR_VIDEO,
+ POLLING_SLEEP_US, POLLING_TIMEOUT_US);
+if (ret < 0) {
+DRM_ERROR("mainlink not ready\n");
+return false;
+}
+
+return true;
+}
+
+void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog,
+bool enable)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+void __iomem *base;
+
+base = catalog->io->dp_ahb.base;
+
+if (enable) {
+dp_write_ahb(catalog, REG_DP_INTR_STATUS,

DP_INTERRUPT_STATUS1_MASK);
+dp_write_ahb(catalog, REG_DP_INTR_STATUS2,
DP_INTERRUPT_STATUS2_MASK);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +7 -0
+} else {
+dp_write_ahb(catalog, REG_DP_INTR_STATUS, 0x00);
+dp_write_ahb(catalog, REG_DP_INTR_STATUS2, 0x00);
+}
+}
+
+void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog, bool

en)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +34 -0
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+if (en) {
+u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER);
+
+dp_write_aux(catalog, REG_DP_DP_HPD_INT_ACK,
+DP_DP_HPD_PLUG_INT_ACK | DP_DP_IRQ_HPD_INT_ACK |
+DP_DP_HPD_REPLUG_INT_ACK | DP_DP_HPD_UNPLUG_INT_ACK);
+dp_write_aux(catalog, REG_DP_DP_HPD_INT_MASK,
+DP_DP_HPD_PLUG_INT_MASK | DP_DP_IRQ_HPD_INT_MASK |
+DP_DP_HPD_REPLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK);
+
+/* Configure REFTIMER */
+reftimer |= REFTIMER_DEFAULT_VALUE;
+dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer);
+/* Enable HPD */
+dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
+} else {
+/* Disable HPD */
+dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, 0x0);
+}
+}
+
+int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 intr, intr_ack;
+
+intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS2);
+intr &= ~DP_INTERRUPT_STATUS2_MASK;
+intr_ack = (intr & DP_INTERRUPT_STATUS2) <<

DP_INTERRUPT_STATUS_ACK_SHIFT; +dp_write_ahb(catalog, REG_DP_INTR_STATUS2, intr_ack | DP_INTERRUPT_STATUS2_MASK);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +25 -0
+
+return intr;
+}
+
+void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_ahb(catalog, REG_DP_PHY_CTRL,
+DP_PHY_CTRL_SW_RESET_PLL | DP_PHY_CTRL_SW_RESET);
+usleep_range(1000, 1100); /* h/w recommended delay */
+dp_write_ahb(catalog, REG_DP_PHY_CTRL, 0x0);
+}
+
+void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog *dp_catalog,
+bool flipped, u8 ln_cnt)
+{
+u32 info;
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u8 orientation = BIT(!!flipped);
+
+info = ln_cnt & DP_PHY_SPARE0_MASK;
+info |= (orientation & DP_PHY_SPARE0_MASK) <<

DP_PHY_SPARE0_ORIENTATION_INFO_SHIFT;

drivers/gpu/drm/msm/dp/dp_catalog.c new file +29 -0
+DRM_DEBUG_DP("Shared Info = 0x%x\n", info);
+
+dp_write_phy(catalog, REG_DP_PHY_SPARE0, info);
+}
+
+int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog,
+u8 v_level, u8 p_level)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u8 voltage_swing_cfg, pre_emphasis_cfg;
+
+DRM_DEBUG_DP("hw: v=%d p=%d\n", v_level, p_level);
+
+voltage_swing_cfg = vm_voltage_swing[v_level][p_level];
+pre_emphasis_cfg = vm_pre_emphasis[v_level][p_level];
+
+if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF) {
+DRM_ERROR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
+v_level, voltage_swing_cfg, p_level, pre_emphasis_cfg);
+return -EINVAL;
+}
+
+/* Enable MUX to use Cursor values from these registers */
+voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
+pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
+
+/* Configure host and panel only if both values are allowed */
+dp_write_ln_tx0(catalog, REG_DP_PHY_TXn_TX_DRV_LVL,

voltage_swing_cfg);
+dp_write_ln_tx1(catalog, REG_DP_PHY_TXn_TX_DRV_LVL, voltage_swing_cfg);
+dp_write_ln_tx0(catalog, REG_DP_PHY_TXn_TX_EMP_POST1_LVL, pre_emphasis_cfg);
+dp_write_ln_tx1(catalog, REG_DP_PHY_TXn_TX_EMP_POST1_LVL, pre_emphasis_cfg);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +14 -0
+DRM_DEBUG_DP("hw: vx_value=0x%x px_value=0x%x\n",
+voltage_swing_cfg, pre_emphasis_cfg);
+
+return 0;
+}
+
+void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
+u32 pattern)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 value = 0x0;
+
+/* Make sure to clear the current pattern before starting a new one

*/

drivers/gpu/drm/msm/dp/dp_catalog.c new file +5 -0
+dp_write_link(catalog, REG_DP_STATE_CTRL, 0x0);
+
+switch (pattern) {
+case DP_LINK_QUAL_PATTERN_D10_2:
+dp_write_link(catalog, REG_DP_STATE_CTRL,

DP_STATE_CTRL_LINK_TRAINING_PATTERN1);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +6 -0
+return;
+case DP_LINK_QUAL_PATTERN_PRBS7:
+dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_PRBS7);
+return;
+case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM:
+dp_write_link(catalog, REG_DP_STATE_CTRL,

DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +2 -0
+/* 00111110000011111000001111100000 */
+dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0,

0x3E0F83E0);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +2 -0
+/* 00001111100000111110000011111000 */
+dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1,

0x0F83E0F8);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +2 -0
+/* 1111100000111110 */
+dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2,

0x0000F83E);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +7 -0
+return;
+case DP_LINK_QUAL_PATTERN_HBR2_EYE:
+case DP_LINK_QUAL_PATTERN_ERROR_RATE:
+value &= ~DP_HBR2_ERM_PATTERN;
+if (pattern == DP_LINK_QUAL_PATTERN_HBR2_EYE)
+value = DP_HBR2_ERM_PATTERN;
+dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,

value);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +2 -0
+value |= SCRAMBLER_RESET_COUNT_VALUE;
+dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,

value);
+dp_write_link(catalog, REG_DP_MAINLINK_LEVELS,
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
+dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +23 -0
+return;
+default:
+DRM_DEBUG_DP("No valid test pattern requested: 0x%x\n", pattern);
+return;
+}
+}
+
+u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+return dp_read_link(catalog, REG_DP_MAINLINK_READY);
+}
+
+/* panel related catalog functions */
+int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_link(catalog, REG_DP_TOTAL_HOR_VER, dp_catalog->total);
+dp_write_link(catalog, REG_DP_START_HOR_VER_FROM_SYNC,

dp_catalog->sync_start);
+dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY, dp_catalog->width_blanking);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +44 -0
+dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_catalog->dp_active);
+return 0;
+}
+
+void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
+struct drm_display_mode *drm_mode)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+u32 hsync_period, vsync_period;
+u32 display_v_start, display_v_end;
+u32 hsync_start_x, hsync_end_x;
+u32 v_sync_width;
+u32 hsync_ctl;
+u32 display_hctl;
+
+/* TPG config parameters*/
+hsync_period = drm_mode->htotal;
+vsync_period = drm_mode->vtotal;
+
+display_v_start = ((drm_mode->vtotal - drm_mode->vsync_start) *
+hsync_period);
+display_v_end = ((vsync_period - drm_mode->vsync_start -
+drm_mode->vdisplay) * hsync_period) - 1;
+
+display_v_start += drm_mode->htotal - drm_mode->hsync_start;
+display_v_end -= drm_mode->hsync_start - drm_mode->hdisplay;
+
+hsync_start_x = drm_mode->htotal - drm_mode->hsync_start;
+hsync_end_x = hsync_period - drm_mode->hsync_start -
+drm_mode->hdisplay - 1;
+
+v_sync_width = drm_mode->vsync_end - drm_mode->vsync_start;
+
+hsync_ctl = (hsync_period << 16) |
+(drm_mode->hsync_end - drm_mode->hsync_start);
+display_hctl = (hsync_end_x << 16) | hsync_start_x;
+
+
+dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0x0);
+dp_write_p0(catalog, MMSS_DP_INTF_HSYNC_CTL, hsync_ctl);
+dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F0, vsync_period *
+hsync_period);
+dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, v_sync_width

*

drivers/gpu/drm/msm/dp/dp_catalog.c new file +16 -0
+hsync_period);
+dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_HCTL, display_hctl);
+dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_HCTL, 0);
+dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F0, display_v_start);
+dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F0, display_v_end);
+dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F1, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
+dp_write_p0(catalog, MMSS_DP_INTF_POLARITY_CTL, 0);
+
+dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL,

DP_TPG_CHECKERED_RECT_PATTERN);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +5 -0
+dp_write_p0(catalog, MMSS_DP_TPG_VIDEO_CONFIG,
+DP_TPG_VIDEO_CONFIG_BPP_8BIT |
+DP_TPG_VIDEO_CONFIG_RGB);
+dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, DP_BIST_ENABLE_DPBIST_EN);
+dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN,

DP_TIMING_ENGINE_EN_EN);

drivers/gpu/drm/msm/dp/dp_catalog.c new file +15 -0
+DRM_DEBUG_DP("%s: enabled tpg\n", __func__);
+}
+
+void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog = container_of(dp_catalog,
+struct dp_catalog_private, dp_catalog);
+
+dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, 0x0);
+dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, 0x0);
+dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0);
+return;
+}
+
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io

*io)

drivers/gpu/drm/msm/dp/dp_catalog.c new file +39 -0
+{
+int rc = 0;
+struct dp_catalog *dp_catalog;
+struct dp_catalog_private *catalog;
+
+if (!io) {
+DRM_ERROR("invalid input\n");
+rc = -EINVAL;
+goto error;
+}
+
+catalog  = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL);
+if (!catalog) {
+rc = -ENOMEM;
+goto error;
+}
+
+catalog->dev = dev;
+catalog->io = io;
+
+dp_catalog = &catalog->dp_catalog;
+
+return dp_catalog;
+error:
+return ERR_PTR(rc);
+}
+
+void dp_catalog_put(struct dp_catalog *dp_catalog)
+{
+struct dp_catalog_private *catalog;
+
+if (!dp_catalog)
+return;
+
+catalog = container_of(dp_catalog, struct dp_catalog_private,
+dp_catalog);
+
+devm_kfree(catalog->dev, catalog);
+}
drivers/gpu/drm/msm/dp/dp_catalog.h new file +3 -0
new file mode 100644
index 0000000..51c82dd
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights 

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_catalog.h new file +36 -0
+
+#ifndef _DP_CATALOG_H_
+#define _DP_CATALOG_H_
+
+#include "dp_parser.h"
+
+/* interrupts */
+#define DP_INTR_HPDBIT(0)
+#define DP_INTR_AUX_I2C_DONEBIT(3)
+#define DP_INTR_WRONG_ADDRBIT(6)
+#define DP_INTR_TIMEOUTBIT(9)
+#define DP_INTR_NACK_DEFERBIT(12)
+#define DP_INTR_WRONG_DATA_CNTBIT(15)
+#define DP_INTR_I2C_NACKBIT(18)
+#define DP_INTR_I2C_DEFERBIT(21)
+#define DP_INTR_PLL_UNLOCKEDBIT(24)
+#define DP_INTR_AUX_ERRORBIT(27)
+
+#define DP_INTR_READY_FOR_VIDEOBIT(0)
+#define DP_INTR_IDLE_PATTERN_SENTBIT(3)
+#define DP_INTR_FRAME_ENDBIT(6)
+#define DP_INTR_CRC_UPDATEDBIT(9)
+
+struct dp_catalog {
+u32 aux_data;
+u32 total;
+u32 sync_start;
+u32 width_blanking;
+u32 dp_active;
+};
+
+/* AUX APIs */
+u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool

read);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+void dp_catalog_aux_reset(struct dp_catalog *dp_catalog);
+void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool

enable);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +8 -0
+void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog,
+struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type);
+void dp_catalog_aux_setup(struct dp_catalog *dp_catalog,
+struct dp_aux_cfg *aux_cfg);
+int dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
+
+/* DP Controller APIs */
+void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32

state);
+void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, 

bool
enable);
+void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
+void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+u32 stream_rate_khz, bool fixed_nvid);
+int dp_catalog_ctrl_set_pattern(struct dp_catalog *dp_catalog, u32

pattern);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_usb_reset(struct dp_catalog *dp_catalog, bool

flip);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool

enable);
+void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog, bool enable);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog *dp_catalog, bool

flipped,

drivers/gpu/drm/msm/dp/dp_catalog.h new file +2 -0
+u8 lane_cnt);
+int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8

v_level,

drivers/gpu/drm/msm/dp/dp_catalog.h new file +3 -0
+u8 p_level);
+int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog

*dp_catalog,

drivers/gpu/drm/msm/dp/dp_catalog.h new file +12 -0
+u32 dp_tu, u32 valid_boundary, u32 valid_boundary2);
+void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
+u32 pattern);
+u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog);
+
+/* DP Panel APIs */
+int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog);
+void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
+struct drm_display_mode *drm_mode);
+void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog);
+
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io

*io);

drivers/gpu/drm/msm/dp/dp_catalog.h new file +3 -0
+void dp_catalog_put(struct dp_catalog *catalog);
+
+#endif /* _DP_CATALOG_H_ */
drivers/gpu/drm/msm/dp/dp_ctrl.c new file +3 -0
new file mode 100644
index 0000000..a4575ea
@@ -0,0 +1,1590 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights 

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +13 -0
+
+#define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <drm/drm_fixed.h>
+
+#include "dp_reg.h"
+#include "dp_ctrl.h"
+
+#define DP_KHZ_TO_HZ 1000
+#define IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES(30 * HZ / 1000) /* 30

ms */

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +77 -0
+#define WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES (HZ / 2)
+
+#define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0)
+#define DP_CTRL_INTR_IDLE_PATTERN_SENT  BIT(3)
+
+#define MR_LINK_TRAINING1  0x8
+#define MR_LINK_SYMBOL_ERM 0x80
+#define MR_LINK_PRBS7 0x100
+#define MR_LINK_CUSTOM80 0x200
+
+struct dp_tu_calc_input {
+u64 lclk;        /* 162, 270, 540 and 810 */
+u64 pclk_khz;    /* in KHz */
+u64 hactive;     /* active h-width */
+u64 hporch;      /* bp + fp + pulse */
+int nlanes;      /* no.of.lanes */
+int bpp;         /* bits */
+int pixel_enc;   /* 444, 420, 422 */
+int dsc_en;     /* dsc on/off */
+int async_en;   /* async mode */
+};
+
+struct dp_vc_tu_mapping_table {
+u8 valid_boundary_link;
+u16 delay_start_link;
+bool boundary_moderation_en;
+u8 valid_lower_boundary_link;
+u8 upper_boundary_count;
+u8 lower_boundary_count;
+u8 tu_size_minus1;
+};
+
+struct dp_ctrl_private {
+struct dp_ctrl dp_ctrl;
+
+struct device *dev;
+struct dp_aux *aux;
+struct dp_panel *panel;
+struct dp_link *link;
+struct dp_power *power;
+struct dp_parser *parser;
+struct dp_catalog *catalog;
+
+struct completion idle_comp;
+struct mutex push_idle_mutex;
+struct completion video_comp;
+};
+
+void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
+{
+struct dp_ctrl_private *ctrl;
+
+ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+mutex_lock(&ctrl->push_idle_mutex);
+
+reinit_completion(&ctrl->idle_comp);
+dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_PUSH_IDLE);
+
+if (!wait_for_completion_timeout(&ctrl->idle_comp,
+IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES))
+pr_warn("PUSH_IDLE pattern timedout\n");
+
+mutex_unlock(&ctrl->push_idle_mutex);
+pr_debug("mainlink off done\n");
+}
+
+static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
+{
+u32 config = 0, tbd;
+u8 *dpcd = ctrl->panel->dpcd;
+
+/* Default-> LSCLK DIV: 1/4 LCLK  */
+config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
+
+/* Scrambler reset enable */
+if (dpcd[DP_EDP_CONFIGURATION_CAP] &

DP_ALTERNATE_SCRAMBLER_RESET_CAP)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +30 -0
+config |= DP_CONFIGURATION_CTRL_ASSR;
+
+tbd = dp_link_get_test_bits_depth(ctrl->link,
+ctrl->panel->dp_mode.bpp);
+
+if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) {
+pr_debug("BIT_DEPTH not set. Configure default\n");
+tbd = DP_TEST_BIT_DEPTH_8;
+}
+
+config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
+
+/* Num of Lanes */
+config |= ((ctrl->link->link_params.num_lanes - 1)
+<< DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT);
+
+if (drm_dp_enhanced_frame_cap(dpcd))
+config |= DP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
+
+config |= DP_CONFIGURATION_CTRL_P_INTERLACED; /* progressive video */
+
+/* sync clock & static Mvid */
+config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;
+config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK;
+
+dp_catalog_ctrl_config_ctrl(ctrl->catalog, config);
+}
+
+/**
+ * dp_ctrl_configure_source_params() - configures DP transmitter

source params
+ * @ctrl: Display Port Driver data
+ *
+ * Configures the DP transmitter source params including details such as lane
+ * configuration, output format and sink/panel timing information.
+ */
+static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +230 -0
+{
+u32 cc, tb;
+
+dp_catalog_ctrl_lane_mapping(ctrl->catalog);
+dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+
+dp_ctrl_config_ctrl(ctrl);
+
+tb = dp_link_get_test_bits_depth(ctrl->link,
+ctrl->panel->dp_mode.bpp);
+cc = dp_link_get_colorimetry_config(ctrl->link);
+dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb);
+dp_panel_timing_cfg(ctrl->panel);
+}
+
+/*
+ * The structure and few functions present below are IP/Hardware
+ * specific implementation. Most of the implementation will not
+ * have coding comments
+ */
+struct tu_algo_data {
+s64 lclk_fp;
+s64 pclk_fp;
+s64 lwidth;
+s64 hbp_relative_to_pclk;
+int nlanes;
+int bpp;
+int pixelEnc;
+int dsc_en;
+int async_en;
+int bpc;
+
+uint delay_start_link_extra_pixclk;
+int extra_buffer_margin;
+s64 ratio_fp;
+s64 original_ratio_fp;
+
+s64 err_fp;
+s64 n_err_fp;
+s64 n_n_err_fp;
+int tu_size;
+int tu_size_desired;
+int tu_size_minus1;
+
+int valid_boundary_link;
+s64 resulting_valid_fp;
+s64 total_valid_fp;
+s64 effective_valid_fp;
+s64 effective_valid_recorded_fp;
+int n_tus;
+int n_tus_per_lane;
+int paired_tus;
+int remainder_tus;
+int remainder_tus_upper;
+int remainder_tus_lower;
+int extra_bytes;
+int filler_size;
+int delay_start_link;
+
+int extra_pclk_cycles;
+int extra_pclk_cycles_in_link_clk;
+s64 ratio_by_tu_fp;
+s64 average_valid2_fp;
+int new_valid_boundary_link;
+int remainder_symbols_exist;
+int n_symbols;
+s64 n_remainder_symbols_per_lane_fp;
+s64 last_partial_tu_fp;
+s64 TU_ratio_err_fp;
+
+int n_tus_incl_last_incomplete_tu;
+int extra_pclk_cycles_tmp;
+int extra_pclk_cycles_in_link_clk_tmp;
+int extra_required_bytes_new_tmp;
+int filler_size_tmp;
+int lower_filler_size_tmp;
+int delay_start_link_tmp;
+
+bool boundary_moderation_en;
+int boundary_mod_lower_err;
+int upper_boundary_count;
+int lower_boundary_count;
+int i_upper_boundary_count;
+int i_lower_boundary_count;
+int valid_lower_boundary_link;
+int even_distribution_BF;
+int even_distribution_legacy;
+int even_distribution;
+int min_hblank_violated;
+s64 delay_start_time_fp;
+s64 hbp_time_fp;
+s64 hactive_time_fp;
+s64 diff_abs_fp;
+
+s64 ratio;
+};
+
+static int _tu_param_compare(s64 a, s64 b)
+{
+u32 a_int, a_frac;
+u32 b_int, b_frac;
+
+if (a == b)
+return 0;
+
+a_int = (a >> 32) & 0x7FFFFFFF;
+a_frac = a & 0xFFFFFFFF;
+
+b_int = (b >> 32) & 0x7FFFFFFF;
+b_frac = b & 0xFFFFFFFF;
+
+if (a_int > b_int)
+return 1;
+else if (a_int < b_int)
+return 2;
+else if (a_frac > b_frac)
+return 1;
+else
+return 2;
+}
+
+static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
+{
+s64 temp1_fp, temp2_fp, temp, temp1, temp2;
+int compare_result_1, compare_result_2, compare_result_3;
+
+temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+
+tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+
+temp = (tu->i_upper_boundary_count *
+tu->new_valid_boundary_link +
+tu->i_lower_boundary_count *
+(tu->new_valid_boundary_link-1));
+tu->average_valid2_fp = drm_fixp_from_fraction(temp,
+(tu->i_upper_boundary_count +
+tu->i_lower_boundary_count));
+
+temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+temp2_fp = drm_fixp_from_fraction(tu->lwidth, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
+tu->n_tus = drm_fixp2int(temp2_fp);
+
+temp1_fp = drm_fixp_from_fraction(tu->n_tus, 1);
+temp2_fp = drm_fixp_mul(temp1_fp, tu->average_valid2_fp);
+temp1_fp = drm_fixp_from_fraction(tu->n_symbols, 1);
+temp2_fp = temp1_fp - temp2_fp;
+temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
+temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
+tu->n_remainder_symbols_per_lane_fp = temp2_fp;
+
+temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+tu->last_partial_tu_fp =
+drm_fixp_div(tu->n_remainder_symbols_per_lane_fp,
+temp1_fp);
+
+if (tu->n_remainder_symbols_per_lane_fp != 0)
+tu->remainder_symbols_exist = 1;
+else
+tu->remainder_symbols_exist = 0;
+
+temp1_fp = drm_fixp_from_fraction(tu->n_tus, tu->nlanes);
+tu->n_tus_per_lane = drm_fixp2int(temp1_fp);
+
+tu->paired_tus = (int)((tu->n_tus_per_lane) /
+(tu->i_upper_boundary_count +
+ tu->i_lower_boundary_count));
+
+tu->remainder_tus = tu->n_tus_per_lane - tu->paired_tus *
+(tu->i_upper_boundary_count +
+tu->i_lower_boundary_count);
+
+if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) {
+tu->remainder_tus_upper = tu->i_upper_boundary_count;
+tu->remainder_tus_lower = tu->remainder_tus -
+tu->i_upper_boundary_count;
+} else {
+tu->remainder_tus_upper = tu->remainder_tus;
+tu->remainder_tus_lower = 0;
+}
+
+temp = tu->paired_tus * (tu->i_upper_boundary_count *
+tu->new_valid_boundary_link +
+tu->i_lower_boundary_count *
+(tu->new_valid_boundary_link - 1)) +
+(tu->remainder_tus_upper *
+ tu->new_valid_boundary_link) +
+(tu->remainder_tus_lower *
+(tu->new_valid_boundary_link - 1));
+tu->total_valid_fp = drm_fixp_from_fraction(temp, 1);
+
+if (tu->remainder_symbols_exist) {
+temp1_fp = tu->total_valid_fp +
+tu->n_remainder_symbols_per_lane_fp;
+temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1);
+temp2_fp = temp2_fp + tu->last_partial_tu_fp;
+temp1_fp = drm_fixp_div(temp1_fp, temp2_fp);
+} else {
+temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1);
+temp1_fp = drm_fixp_div(tu->total_valid_fp, temp2_fp);
+}
+tu->effective_valid_fp = temp1_fp;
+
+temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp;
+
+temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+tu->n_err_fp = tu->average_valid2_fp - temp2_fp;
+
+tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
+
+temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+temp2_fp = drm_fixp_from_fraction(tu->lwidth, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
+
+if (temp2_fp)
+tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp);
+else
+tu->n_tus_incl_last_incomplete_tu = 0;
+
+temp1 = 0;
+temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+temp1_fp = tu->average_valid2_fp - temp2_fp;
+temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu,

1);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +51 -0
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+if (temp1_fp)
+temp1 = drm_fixp2int_ceil(temp1_fp);
+
+temp = tu->i_upper_boundary_count * tu->nlanes;
+temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+temp1_fp = drm_fixp_from_fraction(tu->new_valid_boundary_link, 1);
+temp2_fp = temp1_fp - temp2_fp;
+temp1_fp = drm_fixp_from_fraction(temp, 1);
+temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+if (temp2_fp)
+temp2 = drm_fixp2int_ceil(temp2_fp);
+else
+temp2 = 0;
+tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2);
+
+temp1_fp = drm_fixp_from_fraction(8, tu->bpp);
+temp2_fp = drm_fixp_from_fraction(
+tu->extra_required_bytes_new_tmp, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+if (temp1_fp)
+tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp);
+else
+tu->extra_pclk_cycles_tmp = 0;
+
+temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1);
+temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
+temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+if (temp1_fp)
+tu->extra_pclk_cycles_in_link_clk_tmp =
+drm_fixp2int_ceil(temp1_fp);
+else
+tu->extra_pclk_cycles_in_link_clk_tmp = 0;
+
+tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link;
+
+tu->lower_filler_size_tmp = tu->filler_size_tmp + 1;
+
+tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp +
+tu->lower_filler_size_tmp +
+tu->extra_buffer_margin;
+
+temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1);
+tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
+
+compare_result_1 = _tu_param_compare(tu->n_n_err_fp,

tu->diff_abs_fp);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +53 -0
+if (compare_result_1 == 2)
+compare_result_1 = 1;
+else
+compare_result_1 = 0;
+
+compare_result_2 = _tu_param_compare(tu->n_n_err_fp, tu->err_fp);
+if (compare_result_2 == 2)
+compare_result_2 = 1;
+else
+compare_result_2 = 0;
+
+compare_result_3 = _tu_param_compare(tu->hbp_time_fp,
+tu->delay_start_time_fp);
+if (compare_result_3 == 2)
+compare_result_3 = 0;
+else
+compare_result_3 = 1;
+
+if (((tu->even_distribution == 1) ||
+((tu->even_distribution_BF == 0) &&
+(tu->even_distribution_legacy == 0))) &&
+tu->n_err_fp >= 0 && tu->n_n_err_fp >= 0 &&
+compare_result_2 &&
+(compare_result_1 || (tu->min_hblank_violated == 1)) &&
+(tu->new_valid_boundary_link - 1) > 0 &&
+compare_result_3 &&
+(tu->delay_start_link_tmp <= 1023)) {
+tu->upper_boundary_count = tu->i_upper_boundary_count;
+tu->lower_boundary_count = tu->i_lower_boundary_count;
+tu->err_fp = tu->n_n_err_fp;
+tu->boundary_moderation_en = true;
+tu->tu_size_desired = tu->tu_size;
+tu->valid_boundary_link = tu->new_valid_boundary_link;
+tu->effective_valid_recorded_fp = tu->effective_valid_fp;
+tu->even_distribution_BF = 1;
+tu->delay_start_link = tu->delay_start_link_tmp;
+} else if (tu->boundary_mod_lower_err == 0) {
+compare_result_1 = _tu_param_compare(tu->n_n_err_fp,
+tu->diff_abs_fp);
+if (compare_result_1 == 2)
+tu->boundary_mod_lower_err = 1;
+}
+}
+
+static void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
+   struct dp_vc_tu_mapping_table *tu_table)
+{
+struct tu_algo_data tu;
+int compare_result_1, compare_result_2;
+u64 temp = 0;
+s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
+
+s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006

*/

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +6 -0
+s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */
+s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */
+s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000);
+
+u8 DP_BRUTE_FORCE = 1;
+s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1

*/

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +192 -0
+uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
+uint HBLANK_MARGIN = 4;
+
+memset(&tu, 0, sizeof(tu));
+
+tu.lclk_fp              = drm_fixp_from_fraction(in->lclk, 1);
+tu.pclk_fp              = drm_fixp_from_fraction(in->pclk_khz, 1000);
+tu.lwidth               = in->hactive;
+tu.hbp_relative_to_pclk = in->hporch;
+tu.nlanes               = in->nlanes;
+tu.bpp                  = in->bpp;
+tu.pixelEnc             = in->pixel_enc;
+tu.dsc_en               = in->dsc_en;
+tu.async_en             = in->async_en;
+
+tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
+
+if (tu.pixelEnc == 420) {
+temp_fp = drm_fixp_from_fraction(2, 1);
+tu.pclk_fp = drm_fixp_div(tu.pclk_fp, temp_fp);
+tu.lwidth /= 2;
+tu.hbp_relative_to_pclk /= 2;
+}
+
+if (tu.pixelEnc == 422) {
+switch (tu.bpp) {
+case 24:
+tu.bpp = 16;
+tu.bpc = 8;
+break;
+case 30:
+tu.bpp = 20;
+tu.bpc = 10;
+break;
+default:
+tu.bpp = 16;
+tu.bpc = 8;
+break;
+}
+} else {
+tu.bpc = tu.bpp/3;
+}
+
+temp1_fp = drm_fixp_from_fraction(4, 1);
+temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
+temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
+tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
+
+temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
+temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
+temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
+tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
+
+tu.original_ratio_fp = tu.ratio_fp;
+tu.boundary_moderation_en = false;
+tu.upper_boundary_count = 0;
+tu.lower_boundary_count = 0;
+tu.i_upper_boundary_count = 0;
+tu.i_lower_boundary_count = 0;
+tu.valid_lower_boundary_link = 0;
+tu.even_distribution_BF = 0;
+tu.even_distribution_legacy = 0;
+tu.even_distribution = 0;
+tu.delay_start_time_fp = 0;
+
+tu.err_fp = drm_fixp_from_fraction(1000, 1);
+tu.n_err_fp = 0;
+tu.n_n_err_fp = 0;
+
+tu.ratio = drm_fixp2int(tu.ratio_fp);
+if ((((u32)tu.lwidth % tu.nlanes) != 0) &&
+!tu.ratio && tu.dsc_en == 0) {
+tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
+tu.ratio = drm_fixp2int(tu.ratio_fp);
+if (tu.ratio)
+tu.ratio_fp = drm_fixp_from_fraction(1, 1);
+}
+
+if (tu.ratio > 1)
+tu.ratio = 1;
+
+if (tu.ratio == 1)
+goto tu_size_calc;
+
+compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp);
+if (!compare_result_1 || compare_result_1 == 1)
+compare_result_1 = 1;
+else
+compare_result_1 = 0;
+
+compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp);
+if (!compare_result_2 || compare_result_2 == 2)
+compare_result_2 = 1;
+else
+compare_result_2 = 0;
+
+if (tu.dsc_en && compare_result_1 && compare_result_2) {
+HBLANK_MARGIN += 4;
+DRM_DEBUG_DP("Info: increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN);
+}
+
+tu_size_calc:
+for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
+temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
+temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+temp = drm_fixp2int_ceil(temp2_fp);
+temp1_fp = drm_fixp_from_fraction(temp, 1);
+tu.n_err_fp = temp1_fp - temp2_fp;
+
+if (tu.n_err_fp < tu.err_fp) {
+tu.err_fp = tu.n_err_fp;
+tu.tu_size_desired = tu.tu_size;
+}
+}
+
+tu.tu_size_minus1 = tu.tu_size_desired - 1;
+
+temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+
+temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
+tu.n_tus = drm_fixp2int(temp2_fp);
+
+tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
+DRM_DEBUG_DP("Info: n_sym = %d, num_of_tus = %d\n",
+tu.valid_boundary_link, tu.n_tus);
+
+temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+temp2_fp = temp1_fp - temp2_fp;
+temp1_fp = drm_fixp_from_fraction(tu.n_tus + 1, 1);
+temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+temp = drm_fixp2int(temp2_fp);
+if (temp && temp2_fp)
+tu.extra_bytes = drm_fixp2int_ceil(temp2_fp);
+else
+tu.extra_bytes = 0;
+
+temp1_fp = drm_fixp_from_fraction(tu.extra_bytes, 1);
+temp2_fp = drm_fixp_from_fraction(8, tu.bpp);
+temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+temp = drm_fixp2int(temp1_fp);
+if (temp && temp1_fp)
+tu.extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
+else
+tu.extra_pclk_cycles = 0;
+
+temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
+temp2_fp = drm_fixp_from_fraction(tu.extra_pclk_cycles, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+temp = drm_fixp2int(temp1_fp);
+if (temp && temp1_fp)
+tu.extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
+else
+tu.extra_pclk_cycles_in_link_clk = 0;
+
+tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
+
+temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+
+tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
+tu.filler_size + tu.extra_buffer_margin;
+
+tu.resulting_valid_fp =
+drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+
+temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
+tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
+
+temp1_fp = drm_fixp_from_fraction(
+(tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1);
+tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
+
+temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
+tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
+
+compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
+tu.delay_start_time_fp);
+if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp)

*/

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +140 -0
+tu.min_hblank_violated = 1;
+
+temp1_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+tu.hactive_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
+
+compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
+tu.delay_start_time_fp);
+if (compare_result_2 == 2)
+tu.min_hblank_violated = 1;
+
+tu.delay_start_time_fp = 0;
+
+/* brute force */
+
+tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
+tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
+
+temp = drm_fixp2int(tu.diff_abs_fp);
+if (!temp && tu.diff_abs_fp <= 0xffff)
+tu.diff_abs_fp = 0;
+
+/* if(diff_abs < 0) diff_abs *= -1 */
+if (tu.diff_abs_fp < 0)
+tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
+
+tu.boundary_mod_lower_err = 0;
+if ((tu.diff_abs_fp != 0 &&
+((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
+ (tu.even_distribution_legacy == 0) ||
+ (DP_BRUTE_FORCE == 1))) ||
+(tu.min_hblank_violated == 1)) {
+do {
+tu.err_fp = drm_fixp_from_fraction(1000, 1);
+
+temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
+temp2_fp = drm_fixp_from_fraction(
+tu.delay_start_link_extra_pixclk, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+if (temp1_fp)
+tu.extra_buffer_margin =
+drm_fixp2int_ceil(temp1_fp);
+else
+tu.extra_buffer_margin = 0;
+
+temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+
+if (temp1_fp)
+tu.n_symbols = drm_fixp2int_ceil(temp1_fp);
+else
+tu.n_symbols = 0;
+
+for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
+for (tu.i_upper_boundary_count = 1;
+tu.i_upper_boundary_count <= 15;
+tu.i_upper_boundary_count++) {
+for (tu.i_lower_boundary_count = 1;
+tu.i_lower_boundary_count <= 15;
+tu.i_lower_boundary_count++) {
+_tu_valid_boundary_calc(&tu);
+}
+}
+}
+tu.delay_start_link_extra_pixclk--;
+} while (tu.boundary_moderation_en != true &&
+tu.boundary_mod_lower_err == 1 &&
+tu.delay_start_link_extra_pixclk != 0);
+
+if (tu.boundary_moderation_en == true) {
+temp1_fp = drm_fixp_from_fraction(
+(tu.upper_boundary_count *
+tu.valid_boundary_link +
+tu.lower_boundary_count *
+(tu.valid_boundary_link - 1)), 1);
+temp2_fp = drm_fixp_from_fraction(
+(tu.upper_boundary_count +
+tu.lower_boundary_count), 1);
+tu.resulting_valid_fp =
+drm_fixp_div(temp1_fp, temp2_fp);
+
+temp1_fp = drm_fixp_from_fraction(
+tu.tu_size_desired, 1);
+tu.ratio_by_tu_fp =
+drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+
+tu.valid_lower_boundary_link =
+tu.valid_boundary_link - 1;
+
+temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+temp2_fp = drm_fixp_div(temp1_fp,
+tu.resulting_valid_fp);
+tu.n_tus = drm_fixp2int(temp2_fp);
+
+tu.tu_size_minus1 = tu.tu_size_desired - 1;
+tu.even_distribution_BF = 1;
+
+temp1_fp =
+drm_fixp_from_fraction(tu.tu_size_desired, 1);
+temp2_fp =
+drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
+tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
+}
+}
+
+temp1_fp = drm_fixp_from_fraction(tu.lwidth, 1);
+temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, temp1_fp);
+
+if (temp2_fp)
+temp = drm_fixp2int_ceil(temp2_fp);
+else
+temp = 0;
+
+temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
+temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
+temp1_fp = drm_fixp_from_fraction(temp, 1);
+temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+temp = drm_fixp2int(temp2_fp);
+
+if (tu.async_en)
+tu.delay_start_link += (int)temp;
+
+temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
+tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
+
+/* OUTPUTS */
+tu_table->valid_boundary_link       = tu.valid_boundary_link;
+tu_table->delay_start_link          = tu.delay_start_link;
+tu_table->boundary_moderation_en    = tu.boundary_moderation_en;
+tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
+tu_table->upper_boundary_count      = tu.upper_boundary_count;
+tu_table->lower_boundary_count      = tu.lower_boundary_count;
+tu_table->tu_size_minus1            = tu.tu_size_minus1;
+
+DRM_DEBUG_DP("TU: valid_boundary_link: %d\n",

tu_table->valid_boundary_link);
+DRM_DEBUG_DP("TU: delay_start_link: %d\n",
tu_table->delay_start_link);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +102 -0
+DRM_DEBUG_DP("TU: boundary_moderation_en: %d\n",
+tu_table->boundary_moderation_en);
+DRM_DEBUG_DP("TU: valid_lower_boundary_link: %d\n",
+tu_table->valid_lower_boundary_link);
+DRM_DEBUG_DP("TU: upper_boundary_count: %d\n",
+tu_table->upper_boundary_count);
+DRM_DEBUG_DP("TU: lower_boundary_count: %d\n",
+tu_table->lower_boundary_count);
+DRM_DEBUG_DP("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
+}
+
+static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
+struct dp_vc_tu_mapping_table *tu_table)
+{
+struct dp_tu_calc_input in;
+struct drm_display_mode *drm_mode;
+
+drm_mode = &ctrl->panel->dp_mode.drm_mode;
+
+in.lclk = ctrl->link->link_params.rate / 1000;
+in.pclk_khz = drm_mode->clock;
+in.hactive = drm_mode->hdisplay;
+in.hporch = drm_mode->htotal - drm_mode->hdisplay;
+in.nlanes = ctrl->link->link_params.num_lanes;
+in.bpp = ctrl->panel->dp_mode.bpp;
+in.pixel_enc = 444;
+in.dsc_en = 0;
+in.async_en = 0;
+
+_dp_ctrl_calc_tu(&in, tu_table);
+}
+
+static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
+{
+u32 dp_tu = 0x0;
+u32 valid_boundary = 0x0;
+u32 valid_boundary2 = 0x0;
+struct dp_vc_tu_mapping_table tu_calc_table;
+
+dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
+
+dp_tu |= tu_calc_table.tu_size_minus1;
+valid_boundary |= tu_calc_table.valid_boundary_link;
+valid_boundary |= (tu_calc_table.delay_start_link << 16);
+
+valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
+valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
+valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
+
+if (tu_calc_table.boundary_moderation_en)
+valid_boundary2 |= BIT(0);
+
+pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
+dp_tu, valid_boundary, valid_boundary2);
+
+dp_catalog_ctrl_update_transfer_unit(ctrl->catalog,
+dp_tu, valid_boundary, valid_boundary2);
+}
+
+static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
+{
+int ret = 0;
+
+if (!wait_for_completion_timeout(&ctrl->video_comp,
+WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES)) {
+DRM_ERROR("Link Train timedout\n");
+ret = -ETIMEDOUT;
+}
+return ret;
+}
+
+static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
+{
+struct dp_link *link = ctrl->link;
+int ret = 0, lane, lane_cnt;
+u8 buf[4];
+u32 max_level_reached = 0;
+u32 voltage_swing_level = link->phy_params.v_level;
+u32 pre_emphasis_level = link->phy_params.p_level;
+
+ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
+voltage_swing_level, pre_emphasis_level);
+if (ret)
+return ret;
+
+if (voltage_swing_level > DP_TRAIN_VOLTAGE_SWING_MAX) {
+DRM_DEBUG_DP("max. voltage swing level reached %d\n",
+voltage_swing_level);
+max_level_reached |= DP_TRAIN_MAX_SWING_REACHED;
+}
+
+if (pre_emphasis_level == DP_TRAIN_PRE_EMPHASIS_MAX) {
+DRM_DEBUG_DP("max. pre-emphasis level reached %d\n",
+pre_emphasis_level);
+max_level_reached  |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+}
+
+pre_emphasis_level <<= DP_TRAIN_PRE_EMPHASIS_SHIFT;
+
+lane_cnt = ctrl->link->link_params.num_lanes;
+for (lane = 0; lane < lane_cnt; lane++)
+buf[lane] = voltage_swing_level | pre_emphasis_level |

max_level_reached;

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +2 -0
+
+DRM_DEBUG_DP("sink: p|v=0x%x\n", voltage_swing_level |

pre_emphasis_level);
+ret = drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_LANE0_SET, buf, lane_cnt);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +16 -0
+if (ret == lane_cnt)
+ret = 0;
+
+return ret;
+}
+
+static bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
+u8 pattern)
+{
+u8 buf;
+int ret = 0;
+
+DRM_DEBUG_DP("sink: pattern=%x\n", pattern);
+
+buf = pattern;
+ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET,

buf);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +34 -0
+return ret == 1;
+}
+
+static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
+    u8 *link_status)
+{
+int len = 0;
+u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
+u32 link_status_read_max_retries = 100;
+
+while (--link_status_read_max_retries) {
+len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+link_status);
+if (len != DP_LINK_STATUS_SIZE) {
+DRM_ERROR("DP link status read failed, err: %d\n", len);
+return len;
+}
+
+if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
+return 0;
+}
+
+return -ETIMEDOUT;
+}
+
+static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
+{
+int tries, old_v_level, ret = 0;
+u8 link_status[DP_LINK_STATUS_SIZE];
+int const maximum_retries = 5;
+
+dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+
+ret = dp_catalog_ctrl_set_pattern(ctrl->catalog,

DP_TRAINING_PATTERN_1);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +68 -0
+if (ret)
+return ret;
+dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
+DP_LINK_SCRAMBLING_DISABLE);
+ret = dp_ctrl_update_vx_px(ctrl);
+if (ret)
+return ret;
+
+tries = 0;
+old_v_level = ctrl->link->phy_params.v_level;
+for (tries = 0; tries < maximum_retries; tries++) {
+drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
+
+ret = dp_ctrl_read_link_status(ctrl, link_status);
+if (ret)
+return ret;
+
+if (drm_dp_clock_recovery_ok(link_status,
+ctrl->link->link_params.num_lanes)) {
+return ret;
+}
+
+if (ctrl->link->phy_params.v_level > DP_TRAIN_VOLTAGE_SWING_MAX) {
+DRM_ERROR_RATELIMITED("max v_level reached\n");
+return -EAGAIN;
+}
+
+if (old_v_level != ctrl->link->phy_params.v_level) {
+tries = 0;
+old_v_level = ctrl->link->phy_params.v_level;
+}
+
+DRM_DEBUG_DP("clock recovery not done, adjusting vx px\n");
+
+dp_link_adjust_levels(ctrl->link, link_status);
+ret = dp_ctrl_update_vx_px(ctrl);
+if (ret)
+return ret;
+}
+
+DRM_ERROR("max tries reached\n");
+return -ETIMEDOUT;
+}
+
+static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
+{
+int ret = 0;
+
+switch (ctrl->link->link_params.rate) {
+case 810000:
+ctrl->link->link_params.rate = 540000;
+break;
+case 540000:
+ctrl->link->link_params.rate = 270000;
+break;
+case 270000:
+case 162000:
+default:
+ctrl->link->link_params.rate = 162000;
+break;
+};
+
+DRM_DEBUG_DP("new rate=0x%x\n", ctrl->link->link_params.rate);
+
+return ret;
+}
+
+static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private

*ctrl)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +70 -0
+{
+dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE);
+drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
+}
+
+static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
+{
+int tries = 0, ret = 0;
+char pattern;
+int const maximum_retries = 5;
+u8 link_status[DP_LINK_STATUS_SIZE];
+
+dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+
+if (drm_dp_tps3_supported(ctrl->panel->dpcd))
+pattern = DP_TRAINING_PATTERN_3;
+else
+pattern = DP_TRAINING_PATTERN_2;
+
+ret = dp_ctrl_update_vx_px(ctrl);
+if (ret)
+return ret;
+
+ret = dp_catalog_ctrl_set_pattern(ctrl->catalog, pattern);
+if (ret)
+return ret;
+
+dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
+
+for (tries = 0; tries <= maximum_retries; tries++) {
+drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
+
+ret = dp_ctrl_read_link_status(ctrl, link_status);
+if (ret)
+return ret;
+
+if (drm_dp_channel_eq_ok(link_status,
+ctrl->link->link_params.num_lanes))
+return ret;
+
+dp_link_adjust_levels(ctrl->link, link_status);
+ret = dp_ctrl_update_vx_px(ctrl);
+if (ret)
+return ret;
+
+}
+
+return -ETIMEDOUT;
+}
+
+static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
+{
+int ret = 0;
+u8 encoding = DP_SET_ANSI_8B10B;
+struct drm_dp_link link_info = {0};
+
+ctrl->link->phy_params.p_level = 0;
+ctrl->link->phy_params.v_level = 0;
+
+dp_ctrl_config_ctrl(ctrl);
+
+ret = drm_dp_link_probe(ctrl->aux->drm_aux, &link_info);
+if (ret < 0) {
+DRM_ERROR("failed to retrieve link capabilities. ret=%d\n", ret);
+dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+return ret;
+}
+
+drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
+drm_dp_dpcd_write(ctrl->aux->drm_aux,

DP_MAIN_LINK_CHANNEL_CODING_SET,
+&encoding, 1);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +27 -0
+
+ret = dp_ctrl_link_train_1(ctrl);
+if (ret) {
+DRM_ERROR("link training #1 failed. ret=%d\n", ret);
+goto end;
+}
+
+/* print success info as this is a result of user initiated action */
+DRM_DEBUG_DP("link training #1 successful\n");
+
+ret = dp_ctrl_link_training_2(ctrl);
+if (ret) {
+DRM_ERROR("link training #2 failed. ret=%d\n", ret);
+goto end;
+}
+
+/* print success info as this is a result of user initiated action */
+DRM_DEBUG_DP("link training #2 successful\n");
+
+end:
+dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
+
+dp_ctrl_clear_training_pattern(ctrl);
+return ret;
+}
+
+static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool

train)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +39 -0
+{
+bool mainlink_ready = false;
+int ret = 0;
+
+dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+
+ret = dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, false);
+if (ret)
+return ret;
+
+if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
+return ret;
+
+if (train) {
+/*
+ * As part of previous calls, DP controller state might have
+ * transitioned to PUSH_IDLE. In order to start transmitting a link
+ * training pattern, we have to first do a DP software reset.
+ */
+dp_catalog_ctrl_reset(ctrl->catalog);
+
+ret = dp_ctrl_link_train(ctrl);
+if (ret)
+return ret;
+}
+
+/*
+ * Set up transfer unit values and set controller state to send
+ * video.
+ */
+dp_ctrl_setup_tr_unit(ctrl);
+dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
+
+ret = dp_ctrl_wait4video_ready(ctrl);
+if (ret)
+return ret;
+
+mainlink_ready = dp_catalog_ctrl_mainlink_ready(ctrl->catalog);
+DRM_DEBUG_DP("mainlink %s\n", mainlink_ready ? "READY" : "NOT

READY");

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +23 -0
+return ret;
+}
+
+static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
+   char *name, u32 rate)
+{
+u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk;
+struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config;
+
+while (num && strcmp(cfg->clk_name, name)) {
+num--;
+cfg++;
+}
+
+DRM_DEBUG_DP("setting rate=%d on clk=%s\n", rate, name);
+
+if (num)
+cfg->rate = rate;
+else
+DRM_ERROR("%s clock could not be set with rate %d\n", name, rate);
+}
+
+static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private

*ctrl)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +7 -0
+{
+int ret = 0;
+
+dp_power_set_link_clk_parent(ctrl->power);
+dp_power_set_pixel_clk_parent(ctrl->power);
+
+dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",

ctrl->link->link_params.rate);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +2 -0
+
+dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk",

ctrl->dp_ctrl.pixel_rate);

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +67 -0
+
+ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true);
+if (ret)
+DRM_ERROR("Unabled to start link clocks. ret=%d\n", ret);
+
+return ret;
+}
+
+int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)
+{
+struct dp_ctrl_private *ctrl;
+
+if (!dp_ctrl) {
+DRM_ERROR("Invalid input data\n");
+return -EINVAL;
+}
+
+ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+ctrl->dp_ctrl.orientation = flip;
+
+dp_catalog_ctrl_usb_reset(ctrl->catalog, flip);
+dp_catalog_ctrl_phy_reset(ctrl->catalog);
+dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
+
+return 0;
+}
+
+/**
+ * dp_ctrl_host_deinit() - Uninitialize DP controller
+ * @ctrl: Display Port Driver data
+ *
+ * Perform required steps to uninitialize DP controller
+ * and its resources.
+ */
+void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
+{
+struct dp_ctrl_private *ctrl;
+
+if (!dp_ctrl) {
+DRM_ERROR("Invalid input data\n");
+return;
+}
+
+ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
+
+DRM_DEBUG_DP("Host deinitialized successfully\n");
+}
+
+static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
+{
+u8 *dpcd = ctrl->panel->dpcd;
+
+/*
+ * For better interop experience, used a fixed NVID=0x8000
+ * whenever connected to a VGA dongle downstream.
+ */
+if (drm_dp_is_branch(dpcd))
+return (drm_dp_has_quirk(&ctrl->panel->desc,
+DP_DPCD_QUIRK_CONSTANT_N));
+
+return false;
+}
+
+static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private 

*ctrl)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +59 -0
+{
+int ret = 0;
+
+dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
+dp_catalog_ctrl_phy_lane_cfg(ctrl->catalog,
+ctrl->dp_ctrl.orientation, ctrl->link->link_params.num_lanes);
+/*
+ * Disable and re-enable the mainlink clock since the
+ * link clock might have been adjusted as part of the
+ * link maintenance.
+ */
+ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
+if (ret) {
+DRM_ERROR("Failed to disable clocks. ret=%d\n", ret);
+return ret;
+}
+/* hw recommended delay before re-enabling clocks */
+msleep(20);
+
+ret = dp_ctrl_enable_mainlink_clocks(ctrl);
+if (ret) {
+DRM_ERROR("Failed to enable mainlink clks. ret=%d\n", ret);
+return ret;
+}
+
+dp_ctrl_configure_source_params(ctrl);
+dp_catalog_ctrl_config_msa(ctrl->catalog,
+ctrl->link->link_params.rate,
+ctrl->dp_ctrl.pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
+reinit_completion(&ctrl->idle_comp);
+
+return ret;
+}
+
+static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
+{
+int ret = 0;
+int tries, max_tries = 10;
+
+dp_ctrl_push_idle(&ctrl->dp_ctrl);
+dp_catalog_ctrl_reset(ctrl->catalog);
+
+ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
+
+for (tries = 0; tries < max_tries; tries++) {
+ret = dp_ctrl_reinitialize_mainlink(ctrl);
+if (ret) {
+DRM_ERROR("Failed to reinitialize mainlink. ret=%d\n", ret);
+break;
+}
+
+ret = dp_ctrl_setup_main_link(ctrl, true);
+if (ret == -EAGAIN) /* try with lower link rate */
+dp_ctrl_link_rate_down_shift(ctrl);
+}
+return ret;
+}
+
+static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private

*ctrl)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +29 -0
+{
+int ret = 0;
+
+if (!ctrl->link->phy_params.phy_test_pattern_sel) {
+DRM_DEBUG_DP("no test pattern selected by sink\n");
+return ret;
+}
+
+dp_ctrl_push_idle(&ctrl->dp_ctrl);
+/*
+ * The global reset will need DP link related clocks to be
+ * running. Add the global reset just before disabling the
+ * link clocks and core clocks.
+ */
+dp_catalog_ctrl_reset(ctrl->catalog);
+ret = dp_ctrl_off(&ctrl->dp_ctrl);
+if (ret) {
+DRM_ERROR("failed to disable DP controller\n");
+return ret;
+}
+
+ret = dp_ctrl_on(&ctrl->dp_ctrl);
+if (ret)
+DRM_ERROR("failed to enable DP controller\n");
+
+return ret;
+}
+
+static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private

*ctrl)

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +123 -0
+{
+bool success = false;
+u32 pattern_sent = 0x0;
+u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
+
+DRM_DEBUG_DP("request: 0x%x\n", pattern_requested);
+
+if (dp_catalog_ctrl_update_vx_px(ctrl->catalog,
+ctrl->link->phy_params.v_level,
+ctrl->link->phy_params.p_level)) {
+DRM_ERROR("Failed to set v/p levels\n");
+return false;
+}
+dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
+dp_link_send_test_response(ctrl->link);
+
+pattern_sent = dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
+
+switch (pattern_sent) {
+case MR_LINK_TRAINING1:
+success = pattern_requested ==
+DP_LINK_QUAL_PATTERN_D10_2;
+break;
+case MR_LINK_SYMBOL_ERM:
+success = (pattern_requested ==
+DP_LINK_QUAL_PATTERN_ERROR_RATE)
+|| (pattern_requested ==
+DP_LINK_QUAL_PATTERN_HBR2_EYE);
+break;
+case MR_LINK_PRBS7:
+success = pattern_requested == DP_LINK_QUAL_PATTERN_PRBS7;
+break;
+case MR_LINK_CUSTOM80:
+success = pattern_requested ==
+DP_LINK_QUAL_PATTERN_80BIT_CUSTOM;
+break;
+default:
+success = false;
+}
+
+DRM_DEBUG_DP("%s: test->0x%x\n", success ? "success" : "failed",
+pattern_requested);
+return success;
+}
+
+void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
+{
+struct dp_ctrl_private *ctrl;
+u32 sink_request = 0x0;
+
+if (!dp_ctrl) {
+DRM_ERROR("invalid input\n");
+return;
+}
+
+ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+sink_request = ctrl->link->sink_request;
+
+if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
+DRM_DEBUG_DP("PHY_TEST_PATTERN request\n");
+if (dp_ctrl_process_phy_test_request(ctrl)) {
+DRM_ERROR("process phy_test_req failed\n");
+return;
+}
+}
+
+if (sink_request & DP_LINK_STATUS_UPDATED)
+if (dp_ctrl_link_maintenance(ctrl)) {
+DRM_ERROR("link_maintenance failed: STATUS_UPDATED\n");
+return;
+}
+
+
+if (sink_request & DP_TEST_LINK_TRAINING) {
+dp_link_send_test_response(ctrl->link);
+if (dp_ctrl_link_maintenance(ctrl)) {
+DRM_ERROR("link_maintenance failed: TEST_LINK_TRAINING\n");
+return;
+}
+}
+}
+
+int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
+{
+int rc = 0;
+struct dp_ctrl_private *ctrl;
+u32 rate = 0;
+u32 link_train_max_retries = 10;
+u32 const phy_cts_pixel_clk_khz = 148500;
+
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

!atomic_read(&ctrl->dp_ctrl.aborted)) {

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +64 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

struct dp_panel *panel,
+struct dp_aux *aux, struct dp_power *power, struct dp_catalog *catalog,

drivers/gpu/drm/msm/dp/dp_ctrl.c new file +52 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_ctrl.h new file +3 -0
new file mode 100644
index 0000000..99ab4b2

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_ctrl.h new file +25 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

struct dp_panel *panel,
+struct dp_aux *aux, struct dp_power *power, struct dp_catalog *catalog,

drivers/gpu/drm/msm/dp/dp_ctrl.h new file +4 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_display.c new file +3 -0
new file mode 100644
index 0000000..a893542

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_display.c new file +129 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*master,

drivers/gpu/drm/msm/dp/dp_display.c new file +35 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dp)

drivers/gpu/drm/msm/dp/dp_display.c new file +17 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dp,

drivers/gpu/drm/msm/dp/dp_display.c new file +182 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dp)

drivers/gpu/drm/msm/dp/dp_display.c new file +70 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dp)

drivers/gpu/drm/msm/dp/dp_display.c new file +392 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dev,

drivers/gpu/drm/msm/dp/dp_display.c new file +33 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*encoder)

drivers/gpu/drm/msm/dp/dp_display.c new file +39 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*encoder)

drivers/gpu/drm/msm/dp/dp_display.c new file +23 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*encoder,

drivers/gpu/drm/msm/dp/dp_display.c new file +25 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_display.h new file +3 -0
new file mode 100644
index 0000000..c916408

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_display.h new file +18 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

mode_pclk_khz);

drivers/gpu/drm/msm/dp/dp_display.h new file +7 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_drm.c new file +3 -0
new file mode 100644
index 0000000..a72b0bb

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_drm.c new file +19 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

connected
+ * @connector: Pointer to drm connector structure
+ * @force: Force detect setting from drm framework
+ * Returns: Connector 'is connected' status
+ */
+static enum drm_connector_status dp_connector_detect(struct drm_connector *conn,

drivers/gpu/drm/msm/dp/dp_drm.c new file +15 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

drm_mode_probed_add()
+ * @connector: Pointer to drm connector structure
+ * Returns: Number of modes added
+ */

drivers/gpu/drm/msm/dp/dp_drm.c new file +55 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

is valid
+ * @connector: Pointer to drm connector structure
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,

drivers/gpu/drm/msm/dp/dp_drm.c new file +27 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

drm_atomic_helper_connector_duplicate_state, +.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,

drivers/gpu/drm/msm/dp/dp_drm.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

dp_connector_helper_funcs = {
+.get_modes = dp_connector_get_modes,
+.mode_valid = dp_connector_mode_valid,

drivers/gpu/drm/msm/dp/dp_drm.c new file +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dp_display)

drivers/gpu/drm/msm/dp/dp_drm.c new file +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

sizeof(*dp_connector),

drivers/gpu/drm/msm/dp/dp_drm.c new file +9 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&dp_connector_funcs,

drivers/gpu/drm/msm/dp/dp_drm.c new file +8 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

the host.
+ */

drivers/gpu/drm/msm/dp/dp_drm.c new file +6 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_drm.h new file +3 -0
new file mode 100644
index 0000000..cf472c5

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_drm.h new file +13 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*dp_display);

drivers/gpu/drm/msm/dp/dp_drm.h new file +3 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_extcon.c new file +3 -0
new file mode 100644
index 0000000..0fb34ef

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_extcon.c new file +36 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

dp_usbpd);

drivers/gpu/drm/msm/dp/dp_extcon.c new file +86 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

dp_usbpd);

drivers/gpu/drm/msm/dp/dp_extcon.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

extcon_priv->extcon,

drivers/gpu/drm/msm/dp/dp_extcon.c new file +10 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

create_singlethread_workqueue("drm_dp_extcon");

drivers/gpu/drm/msm/dp/dp_extcon.c new file +20 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

dp_usbpd);

drivers/gpu/drm/msm/dp/dp_extcon.c new file +2 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

extcon_priv->extcon,

drivers/gpu/drm/msm/dp/dp_extcon.c new file +10 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*cb)

drivers/gpu/drm/msm/dp/dp_extcon.c new file +45 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_extcon.h new file +3 -0
new file mode 100644
index 0000000..c6c3051

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_extcon.h new file +73 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*cb);

drivers/gpu/drm/msm/dp/dp_extcon.h new file +7 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_link.c new file +3 -0
new file mode 100644
index 0000000..9f5b7bc8

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +42 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

addr)

drivers/gpu/drm/msm/dp/dp_link.c new file +26 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*link)

drivers/gpu/drm/msm/dp/dp_link.c new file +65 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*link)

drivers/gpu/drm/msm/dp/dp_link.c new file +37 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&data);

drivers/gpu/drm/msm/dp/dp_link.c new file +33 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

from DPCD
+ * @link: Display Port Driver data
+ *
+ * Returns 0 if it successfully parses the audio link pattern parameters.
+ */
+static int dp_link_parse_audio_pattern_params(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +118 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

from DPCD
+ * @link: Display Port Driver data
+ *
+ * Returns 0 if it successfully parses the video link pattern and the link
+ * bit depth requested by the sink and, and if the values parsed are valid.
+ */
+static int dp_link_parse_video_pattern_params(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +20 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*/

drivers/gpu/drm/msm/dp/dp_link.c new file +8 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

DP_TEST_DYNAMIC_RANGE_CEA);

drivers/gpu/drm/msm/dp/dp_link.c new file +79 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

DP_TEST_REFRESH_RATE_NUMERATOR,
+&link->dp_link.test_video.test_rr_n);

drivers/gpu/drm/msm/dp/dp_link.c new file +2 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

(DP_TEST_REFRESH_RATE_NUMERATOR)\n");

drivers/gpu/drm/msm/dp/dp_link.c new file +37 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

parameters from
+ * DPCD
+ * @link: Display Port Driver data
+ *
+ * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane
+ * count (Byte 0x220), and if these values parse are valid.
+ */
+static int dp_link_parse_link_training_params(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +19 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&bp);

drivers/gpu/drm/msm/dp/dp_link.c new file +21 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

being
+ * requested.
+ */
+static int dp_link_parse_phy_test_params(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&data);

drivers/gpu/drm/msm/dp/dp_link.c new file +24 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

link request
+ * @link: link requested by the sink
+ *
+ * Returns true if the requested link is a permitted audio/video link.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +15 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

0x201),
+ * and what type of link automation is being requested (Byte 0x218).
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +68 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

send
+ * a DP_TEST_NAK.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +18 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Content
+ * Protection enabled.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +26 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*link)

drivers/gpu/drm/msm/dp/dp_link.c new file +15 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

requests
+ * @link: Display Port link data
+ *
+ * This function will handle new link training requests that are initiated by
+ * the sink. In particular, it will update the requested lane count and link
+ * link rate, and then trigger the link retraining procedure.
+ *
+ * The function will return 0 if a link training request has been processed,
+ * otherwise it will return -EINVAL.
+ */
+static int dp_link_process_link_training_request(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +56 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

"exit");

drivers/gpu/drm/msm/dp/dp_link.c new file +20 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

checksum);

drivers/gpu/drm/msm/dp/dp_link.c new file +39 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

requests
+ * @link: Display Port Driver data
+ *
+ * This function will handle new phy link pattern requests that are initiated
+ * by the sink. The function will return 0 if a phy link pattern has been
+ * processed, otherwise it will return -EINVAL.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

{

drivers/gpu/drm/msm/dp/dp_link.c new file +29 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

int r)

drivers/gpu/drm/msm/dp/dp_link.c new file +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

updates
+ * @link: Display Port link module data
+ *
+ * This function will check for changes in the link status, e.g. clock
+ * recovery done on all lanes, and trigger link training if there is a
+ * failure/error on the link.
+ *
+ * The function will return 0 if the a link status update has been processed,
+ * otherwise it will return -EINVAL.
+ */
+static int dp_link_process_link_status_update(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +2 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

DP_LANE_ALIGN_STATUS_UPDATED) &

drivers/gpu/drm/msm/dp/dp_link.c new file +18 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

status changes
+ * @link: Display Port Driver data
+ *
+ * This function will handle downstream port updates that are initiated by
+ * the sink. If the downstream port status has changed, the EDID is read via
+ * AUX.
+ *
+ * The function will return 0 if a downstream port update has been
+ * processed, otherwise it will return -EINVAL.
+ */
+static int dp_link_process_ds_port_status_change(struct dp_link_private *link)

drivers/gpu/drm/msm/dp/dp_link.c new file +2 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&

drivers/gpu/drm/msm/dp/dp_link.c new file +14 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*link)

drivers/gpu/drm/msm/dp/dp_link.c new file +7 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*link)

drivers/gpu/drm/msm/dp/dp_link.c new file +20 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

to
HIGH
+ * (including cases when there are back to back HPD IRQ HIGH) indicating
+ * the start of a new link training request or sink status update.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +114 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

within
+ * the allowable range.
+ */

drivers/gpu/drm/msm/dp/dp_link.c new file +97 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_link.h new file +3 -0
new file mode 100644
index 0000000..607904b

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_link.h new file +110 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

checksum);

drivers/gpu/drm/msm/dp/dp_link.h new file +18 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_panel.c new file +3 -0
new file mode 100644
index 0000000..a3150f4

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_panel.c new file +95 -1

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

test_info->test_hsync_width;

drivers/gpu/drm/msm/dp/dp_panel.c new file +7 -1

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

test_info->test_vsync_width;

drivers/gpu/drm/msm/dp/dp_panel.c new file +208 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&panel->dp_panel.dp_mode.drm_mode);

drivers/gpu/drm/msm/dp/dp_panel.c new file +86 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

dp_panel->dp_mode.bpp, 30));

drivers/gpu/drm/msm/dp/dp_panel.c new file +50 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_panel.h new file +3 -0
new file mode 100644
index 0000000..68c5650

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_panel.h new file +52 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

mode_max_bpp,

drivers/gpu/drm/msm/dp/dp_panel.h new file +36 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_parser.c new file +3 -0
new file mode 100644
index 0000000..3fa2a1f

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_parser.c new file +283 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

"qcom,usbplug-cc-gpio", 0);

drivers/gpu/drm/msm/dp/dp_parser.c new file +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

0);

drivers/gpu/drm/msm/dp/dp_parser.c new file +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

"qcom,aux-sel-gpio", 0);

drivers/gpu/drm/msm/dp/dp_parser.c new file +9 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

const char *clk_name)

drivers/gpu/drm/msm/dp/dp_parser.c new file +135 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

phy) */

drivers/gpu/drm/msm/dp/dp_parser.c new file +27 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

disabled\n");

drivers/gpu/drm/msm/dp/dp_parser.c new file +26 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_parser.h new file +3 -0
new file mode 100644
index 0000000..b606b40

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_parser.h new file +175 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

PHY
+ * @usbplug_cc_gpio: GPIO to route DP/USB lanes when using combo PHY
+ * @combo_phy_en: Boolean to check whether combo PHY is used
+ * @disp_data: controller's display related data
+ * @parse: function to be called by client to parse device tree.
+ */

drivers/gpu/drm/msm/dp/dp_parser.h new file +38 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_power.c new file +3 -0
new file mode 100644
index 0000000..3fa4c9b

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_power.c new file +21 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*power)

drivers/gpu/drm/msm/dp/dp_power.c new file +71 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

active)

drivers/gpu/drm/msm/dp/dp_power.c new file +200 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

flip)

drivers/gpu/drm/msm/dp/dp_power.c new file +14 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

flip)

drivers/gpu/drm/msm/dp/dp_power.c new file +248 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_power.h new file +3 -0
new file mode 100644
index 0000000..40d7e73

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_power.h new file +23 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

pm_type,

drivers/gpu/drm/msm/dp/dp_power.h new file +8 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

data
+ *
+ * @parser: instance of parser module
+ * return: pointer to allocated power module data
+ *
+ * This API will configure the DisplayPort's power module and provides
+ * methods to be called by the client to configure the power related
+ * modueles.
+ */

drivers/gpu/drm/msm/dp/dp_power.h new file +9 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/dp/dp_reg.h new file +3 -0
new file mode 100644
index 0000000..5468f7b

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

reserved.
+ */

drivers/gpu/drm/msm/dp/dp_reg.h new file +484 -0

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/msm_drv.c +2 -0
index c84f0a8..e5e93e3 100644

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/msm/msm_drv.h +9 -0
index 71547e7..8b068ec 100644

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*encoder);
+void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder,

drivers/gpu/drm/msm/msm_drv.h +18 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

drm_encoder *encoder)

drivers/gpu/drm/msm/msm_drv.h +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

drm_encoder *encoder)

drivers/gpu/drm/msm/msm_drv.h +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

drm_encoder *encoder,

drivers/gpu/drm/msm/msm_drv.h +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Part of the diff is not shown here. View the raw message.