diff options
author | Dave Airlie <airlied@redhat.com> | 2016-04-05 19:57:33 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-04-05 19:57:33 -0400 |
commit | d00b39c17573ece6f5fb1385314877d29f540db8 (patch) | |
tree | 859eda0522e4a5bbfd727c07ec210686cb799b08 | |
parent | 85bd5ac371c844f66918dda8c83145a26a55f9f2 (diff) | |
parent | 7b4b7a8db439dca4342a0424b3d99d878a4e5a12 (diff) |
Merge branch 'drm-next-analogix-dp-v2' of github.com:yakir-Yang/linux into drm-next
This pull request want to land the analogix_dp driver into drm/bridge directory,
which reused the Exynos DP code, and add Rockchip DP support. And those
patches have been:
* 'drm-next-analogix-dp-v2' of github.com:yakir-Yang/linux:
drm: bridge: analogix/dp: Fix the possible dead lock in bridge disable time
drm: bridge: analogix/dp: add panel prepare/unprepare in suspend/resume time
drm: bridge: analogix/dp: add edid modes parse in get_modes method
drm: bridge: analogix/dp: move hpd detect to connector detect function
drm: bridge: analogix/dp: try force hpd after plug in lookup failed
drm: bridge: analogix/dp: add max link rate and lane count limit for RK3288
drm: bridge: analogix/dp: add some rk3288 special registers setting
dt-bindings: add document for rockchip variant of analogix_dp
drm: rockchip: dp: add rockchip platform dp driver
ARM: dts: exynos/dp: remove some properties that deprecated by analogix_dp driver
dt-bindings: add document for analogix display port driver
drm: bridge: analogix/dp: dynamic parse sync_pol & interlace & dynamic_range
drm: bridge: analogix/dp: remove duplicate configuration of link rate and link count
drm: bridge: analogix/dp: fix some obvious code style
drm: bridge: analogix/dp: rename register constants
drm/exynos: dp: rename implementation specific driver part
drm: bridge: analogix/dp: split exynos dp driver to bridge directory
28 files changed, 4106 insertions, 3258 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt new file mode 100644 index 000000000000..4f2ba8c13d92 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt | |||
@@ -0,0 +1,52 @@ | |||
1 | Analogix Display Port bridge bindings | ||
2 | |||
3 | Required properties for dp-controller: | ||
4 | -compatible: | ||
5 | platform specific such as: | ||
6 | * "samsung,exynos5-dp" | ||
7 | * "rockchip,rk3288-dp" | ||
8 | -reg: | ||
9 | physical base address of the controller and length | ||
10 | of memory mapped region. | ||
11 | -interrupts: | ||
12 | interrupt combiner values. | ||
13 | -clocks: | ||
14 | from common clock binding: handle to dp clock. | ||
15 | -clock-names: | ||
16 | from common clock binding: Shall be "dp". | ||
17 | -interrupt-parent: | ||
18 | phandle to Interrupt combiner node. | ||
19 | -phys: | ||
20 | from general PHY binding: the phandle for the PHY device. | ||
21 | -phy-names: | ||
22 | from general PHY binding: Should be "dp". | ||
23 | |||
24 | Optional properties for dp-controller: | ||
25 | -force-hpd: | ||
26 | Indicate driver need force hpd when hpd detect failed, this | ||
27 | is used for some eDP screen which don't have hpd signal. | ||
28 | -hpd-gpios: | ||
29 | Hotplug detect GPIO. | ||
30 | Indicates which GPIO should be used for hotplug detection | ||
31 | -port@[X]: SoC specific port nodes with endpoint definitions as defined | ||
32 | in Documentation/devicetree/bindings/media/video-interfaces.txt, | ||
33 | please refer to the SoC specific binding document: | ||
34 | * Documentation/devicetree/bindings/display/exynos/exynos_dp.txt | ||
35 | * Documentation/devicetree/bindings/video/analogix_dp-rockchip.txt | ||
36 | |||
37 | [1]: Documentation/devicetree/bindings/media/video-interfaces.txt | ||
38 | ------------------------------------------------------------------------------- | ||
39 | |||
40 | Example: | ||
41 | |||
42 | dp-controller { | ||
43 | compatible = "samsung,exynos5-dp"; | ||
44 | reg = <0x145b0000 0x10000>; | ||
45 | interrupts = <10 3>; | ||
46 | interrupt-parent = <&combiner>; | ||
47 | clocks = <&clock 342>; | ||
48 | clock-names = "dp"; | ||
49 | |||
50 | phys = <&dp_phy>; | ||
51 | phy-names = "dp"; | ||
52 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt index fe4a7a2dea9c..ade5d8eebf85 100644 --- a/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt +++ b/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt | |||
@@ -1,20 +1,3 @@ | |||
1 | Device-Tree bindings for Samsung Exynos Embedded DisplayPort Transmitter(eDP) | ||
2 | |||
3 | DisplayPort is industry standard to accommodate the growing board adoption | ||
4 | of digital display technology within the PC and CE industries. | ||
5 | It consolidates the internal and external connection methods to reduce device | ||
6 | complexity and cost. It also supports necessary features for important cross | ||
7 | industry applications and provides performance scalability to enable the next | ||
8 | generation of displays that feature higher color depths, refresh rates, and | ||
9 | display resolutions. | ||
10 | |||
11 | eDP (embedded display port) device is compliant with Embedded DisplayPort | ||
12 | standard as follows, | ||
13 | - DisplayPort standard 1.1a for Exynos5250 and Exynos5260. | ||
14 | - DisplayPort standard 1.3 for Exynos5422s and Exynos5800. | ||
15 | |||
16 | eDP resides between FIMD and panel or FIMD and bridge such as LVDS. | ||
17 | |||
18 | The Exynos display port interface should be configured based on | 1 | The Exynos display port interface should be configured based on |
19 | the type of panel connected to it. | 2 | the type of panel connected to it. |
20 | 3 | ||
@@ -48,26 +31,6 @@ Required properties for dp-controller: | |||
48 | from general PHY binding: the phandle for the PHY device. | 31 | from general PHY binding: the phandle for the PHY device. |
49 | -phy-names: | 32 | -phy-names: |
50 | from general PHY binding: Should be "dp". | 33 | from general PHY binding: Should be "dp". |
51 | -samsung,color-space: | ||
52 | input video data format. | ||
53 | COLOR_RGB = 0, COLOR_YCBCR422 = 1, COLOR_YCBCR444 = 2 | ||
54 | -samsung,dynamic-range: | ||
55 | dynamic range for input video data. | ||
56 | VESA = 0, CEA = 1 | ||
57 | -samsung,ycbcr-coeff: | ||
58 | YCbCr co-efficients for input video. | ||
59 | COLOR_YCBCR601 = 0, COLOR_YCBCR709 = 1 | ||
60 | -samsung,color-depth: | ||
61 | number of bits per colour component. | ||
62 | COLOR_6 = 0, COLOR_8 = 1, COLOR_10 = 2, COLOR_12 = 3 | ||
63 | -samsung,link-rate: | ||
64 | link rate supported by the panel. | ||
65 | LINK_RATE_1_62GBPS = 0x6, LINK_RATE_2_70GBPS = 0x0A | ||
66 | -samsung,lane-count: | ||
67 | number of lanes supported by the panel. | ||
68 | LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4 | ||
69 | - display-timings: timings for the connected panel as described by | ||
70 | Documentation/devicetree/bindings/display/display-timing.txt | ||
71 | 34 | ||
72 | Optional properties for dp-controller: | 35 | Optional properties for dp-controller: |
73 | -interlaced: | 36 | -interlaced: |
@@ -83,17 +46,31 @@ Optional properties for dp-controller: | |||
83 | Hotplug detect GPIO. | 46 | Hotplug detect GPIO. |
84 | Indicates which GPIO should be used for hotplug | 47 | Indicates which GPIO should be used for hotplug |
85 | detection | 48 | detection |
86 | Video interfaces: | 49 | -video interfaces: Device node can contain video interface port |
87 | Device node can contain video interface port nodes according to [1]. | 50 | nodes according to [1]. |
88 | The following are properties specific to those nodes: | 51 | - display-timings: timings for the connected panel as described by |
89 | 52 | Documentation/devicetree/bindings/display/panel/display-timing.txt | |
90 | endpoint node connected to bridge or panel node: | 53 | |
91 | - remote-endpoint: specifies the endpoint in panel or bridge node. | 54 | For the below properties, please refer to Analogix DP binding document: |
92 | This node is required in all kinds of exynos dp | 55 | * Documentation/devicetree/bindings/display/bridge/analogix_dp.txt |
93 | to represent the connection between dp and bridge | 56 | -phys (required) |
94 | or dp and panel. | 57 | -phy-names (required) |
95 | 58 | -hpd-gpios (optional) | |
96 | [1]: Documentation/devicetree/bindings/media/video-interfaces.txt | 59 | force-hpd (optional) |
60 | |||
61 | Deprecated properties for DisplayPort: | ||
62 | -interlaced: deprecated prop that can parsed from drm_display_mode. | ||
63 | -vsync-active-high: deprecated prop that can parsed from drm_display_mode. | ||
64 | -hsync-active-high: deprecated prop that can parsed from drm_display_mode. | ||
65 | -samsung,ycbcr-coeff: deprecated prop that can parsed from drm_display_mode. | ||
66 | -samsung,dynamic-range: deprecated prop that can parsed from drm_display_mode. | ||
67 | -samsung,color-space: deprecated prop that can parsed from drm_display_info. | ||
68 | -samsung,color-depth: deprecated prop that can parsed from drm_display_info. | ||
69 | -samsung,link-rate: deprecated prop that can reading from monitor by dpcd method. | ||
70 | -samsung,lane-count: deprecated prop that can reading from monitor by dpcd method. | ||
71 | -samsung,hpd-gpio: deprecated name for hpd-gpios. | ||
72 | |||
73 | ------------------------------------------------------------------------------- | ||
97 | 74 | ||
98 | Example: | 75 | Example: |
99 | 76 | ||
@@ -112,13 +89,6 @@ SOC specific portion: | |||
112 | 89 | ||
113 | Board Specific portion: | 90 | Board Specific portion: |
114 | dp-controller { | 91 | dp-controller { |
115 | samsung,color-space = <0>; | ||
116 | samsung,dynamic-range = <0>; | ||
117 | samsung,ycbcr-coeff = <0>; | ||
118 | samsung,color-depth = <1>; | ||
119 | samsung,link-rate = <0x0a>; | ||
120 | samsung,lane-count = <4>; | ||
121 | |||
122 | display-timings { | 92 | display-timings { |
123 | native-mode = <&lcd_timing>; | 93 | native-mode = <&lcd_timing>; |
124 | lcd_timing: 1366x768 { | 94 | lcd_timing: 1366x768 { |
@@ -135,18 +105,9 @@ Board Specific portion: | |||
135 | }; | 105 | }; |
136 | 106 | ||
137 | ports { | 107 | ports { |
138 | port { | 108 | port@0 { |
139 | dp_out: endpoint { | 109 | dp_out: endpoint { |
140 | remote-endpoint = <&dp_in>; | 110 | remote-endpoint = <&bridge_in>; |
141 | }; | ||
142 | }; | ||
143 | }; | ||
144 | |||
145 | panel { | ||
146 | ... | ||
147 | port { | ||
148 | dp_in: endpoint { | ||
149 | remote-endpoint = <&dp_out>; | ||
150 | }; | 111 | }; |
151 | }; | 112 | }; |
152 | }; | 113 | }; |
diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt new file mode 100644 index 000000000000..e832ff98fd61 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt | |||
@@ -0,0 +1,92 @@ | |||
1 | Rockchip RK3288 specific extensions to the Analogix Display Port | ||
2 | ================================ | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: "rockchip,rk3288-edp"; | ||
6 | |||
7 | - reg: physical base address of the controller and length | ||
8 | |||
9 | - clocks: from common clock binding: handle to dp clock. | ||
10 | of memory mapped region. | ||
11 | |||
12 | - clock-names: from common clock binding: | ||
13 | Required elements: "dp" "pclk" | ||
14 | |||
15 | - resets: Must contain an entry for each entry in reset-names. | ||
16 | See ../reset/reset.txt for details. | ||
17 | |||
18 | - pinctrl-names: Names corresponding to the chip hotplug pinctrl states. | ||
19 | - pinctrl-0: pin-control mode. should be <&edp_hpd> | ||
20 | |||
21 | - reset-names: Must include the name "dp" | ||
22 | |||
23 | - rockchip,grf: this soc should set GRF regs, so need get grf here. | ||
24 | |||
25 | - ports: there are 2 port nodes with endpoint definitions as defined in | ||
26 | Documentation/devicetree/bindings/media/video-interfaces.txt. | ||
27 | Port 0: contained 2 endpoints, connecting to the output of vop. | ||
28 | Port 1: contained 1 endpoint, connecting to the input of panel. | ||
29 | |||
30 | For the below properties, please refer to Analogix DP binding document: | ||
31 | * Documentation/devicetree/bindings/drm/bridge/analogix_dp.txt | ||
32 | - phys (required) | ||
33 | - phy-names (required) | ||
34 | - hpd-gpios (optional) | ||
35 | - force-hpd (optional) | ||
36 | ------------------------------------------------------------------------------- | ||
37 | |||
38 | Example: | ||
39 | dp-controller: dp@ff970000 { | ||
40 | compatible = "rockchip,rk3288-dp"; | ||
41 | reg = <0xff970000 0x4000>; | ||
42 | interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; | ||
43 | clocks = <&cru SCLK_EDP>, <&cru PCLK_EDP_CTRL>; | ||
44 | clock-names = "dp", "pclk"; | ||
45 | phys = <&dp_phy>; | ||
46 | phy-names = "dp"; | ||
47 | |||
48 | rockchip,grf = <&grf>; | ||
49 | resets = <&cru 111>; | ||
50 | reset-names = "dp"; | ||
51 | |||
52 | pinctrl-names = "default"; | ||
53 | pinctrl-0 = <&edp_hpd>; | ||
54 | |||
55 | status = "disabled"; | ||
56 | |||
57 | ports { | ||
58 | #address-cells = <1>; | ||
59 | #size-cells = <0>; | ||
60 | edp_in: port@0 { | ||
61 | reg = <0>; | ||
62 | #address-cells = <1>; | ||
63 | #size-cells = <0>; | ||
64 | edp_in_vopb: endpoint@0 { | ||
65 | reg = <0>; | ||
66 | remote-endpoint = <&vopb_out_edp>; | ||
67 | }; | ||
68 | edp_in_vopl: endpoint@1 { | ||
69 | reg = <1>; | ||
70 | remote-endpoint = <&vopl_out_edp>; | ||
71 | }; | ||
72 | }; | ||
73 | |||
74 | edp_out: port@1 { | ||
75 | reg = <1>; | ||
76 | #address-cells = <1>; | ||
77 | #size-cells = <0>; | ||
78 | edp_out_panel: endpoint { | ||
79 | reg = <0>; | ||
80 | remote-endpoint = <&panel_in_edp> | ||
81 | }; | ||
82 | }; | ||
83 | }; | ||
84 | }; | ||
85 | |||
86 | pinctrl { | ||
87 | edp { | ||
88 | edp_hpd: edp-hpd { | ||
89 | rockchip,pins = <7 11 RK_FUNC_2 &pcfg_pull_none>; | ||
90 | }; | ||
91 | }; | ||
92 | }; | ||
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index 8b2acc74aa76..85d819217d17 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts | |||
@@ -124,8 +124,6 @@ | |||
124 | &dp { | 124 | &dp { |
125 | status = "okay"; | 125 | status = "okay"; |
126 | samsung,color-space = <0>; | 126 | samsung,color-space = <0>; |
127 | samsung,dynamic-range = <0>; | ||
128 | samsung,ycbcr-coeff = <0>; | ||
129 | samsung,color-depth = <1>; | 127 | samsung,color-depth = <1>; |
130 | samsung,link-rate = <0x0a>; | 128 | samsung,link-rate = <0x0a>; |
131 | samsung,lane-count = <4>; | 129 | samsung,lane-count = <4>; |
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 0f5dcd418af8..f30c2dbba4f5 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts | |||
@@ -80,8 +80,6 @@ | |||
80 | 80 | ||
81 | &dp { | 81 | &dp { |
82 | samsung,color-space = <0>; | 82 | samsung,color-space = <0>; |
83 | samsung,dynamic-range = <0>; | ||
84 | samsung,ycbcr-coeff = <0>; | ||
85 | samsung,color-depth = <1>; | 83 | samsung,color-depth = <1>; |
86 | samsung,link-rate = <0x0a>; | 84 | samsung,link-rate = <0x0a>; |
87 | samsung,lane-count = <4>; | 85 | samsung,lane-count = <4>; |
diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi index 95210ef6a6b5..746808f401e5 100644 --- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi +++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi | |||
@@ -236,12 +236,10 @@ | |||
236 | pinctrl-names = "default"; | 236 | pinctrl-names = "default"; |
237 | pinctrl-0 = <&dp_hpd>; | 237 | pinctrl-0 = <&dp_hpd>; |
238 | samsung,color-space = <0>; | 238 | samsung,color-space = <0>; |
239 | samsung,dynamic-range = <0>; | ||
240 | samsung,ycbcr-coeff = <0>; | ||
241 | samsung,color-depth = <1>; | 239 | samsung,color-depth = <1>; |
242 | samsung,link-rate = <0x0a>; | 240 | samsung,link-rate = <0x0a>; |
243 | samsung,lane-count = <2>; | 241 | samsung,lane-count = <2>; |
244 | samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>; | 242 | hpd-gpios = <&gpx0 7 GPIO_ACTIVE_HIGH>; |
245 | 243 | ||
246 | ports { | 244 | ports { |
247 | port@0 { | 245 | port@0 { |
diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts index 0f500cb1eb2d..c607bed575d9 100644 --- a/arch/arm/boot/dts/exynos5250-spring.dts +++ b/arch/arm/boot/dts/exynos5250-spring.dts | |||
@@ -74,12 +74,10 @@ | |||
74 | pinctrl-names = "default"; | 74 | pinctrl-names = "default"; |
75 | pinctrl-0 = <&dp_hpd_gpio>; | 75 | pinctrl-0 = <&dp_hpd_gpio>; |
76 | samsung,color-space = <0>; | 76 | samsung,color-space = <0>; |
77 | samsung,dynamic-range = <0>; | ||
78 | samsung,ycbcr-coeff = <0>; | ||
79 | samsung,color-depth = <1>; | 77 | samsung,color-depth = <1>; |
80 | samsung,link-rate = <0x0a>; | 78 | samsung,link-rate = <0x0a>; |
81 | samsung,lane-count = <1>; | 79 | samsung,lane-count = <1>; |
82 | samsung,hpd-gpio = <&gpc3 0 GPIO_ACTIVE_HIGH>; | 80 | hpd-gpios = <&gpc3 0 GPIO_ACTIVE_HIGH>; |
83 | }; | 81 | }; |
84 | 82 | ||
85 | &ehci { | 83 | &ehci { |
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 3981ddb25036..7ddb6a066b28 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts | |||
@@ -157,12 +157,10 @@ | |||
157 | pinctrl-names = "default"; | 157 | pinctrl-names = "default"; |
158 | pinctrl-0 = <&dp_hpd_gpio>; | 158 | pinctrl-0 = <&dp_hpd_gpio>; |
159 | samsung,color-space = <0>; | 159 | samsung,color-space = <0>; |
160 | samsung,dynamic-range = <0>; | ||
161 | samsung,ycbcr-coeff = <0>; | ||
162 | samsung,color-depth = <1>; | 160 | samsung,color-depth = <1>; |
163 | samsung,link-rate = <0x06>; | 161 | samsung,link-rate = <0x06>; |
164 | samsung,lane-count = <2>; | 162 | samsung,lane-count = <2>; |
165 | samsung,hpd-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; | 163 | hpd-gpios = <&gpx2 6 GPIO_ACTIVE_HIGH>; |
166 | 164 | ||
167 | ports { | 165 | ports { |
168 | port@0 { | 166 | port@0 { |
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index 0785fedf441e..288817daa16c 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts | |||
@@ -102,8 +102,6 @@ | |||
102 | pinctrl-names = "default"; | 102 | pinctrl-names = "default"; |
103 | pinctrl-0 = <&dp_hpd>; | 103 | pinctrl-0 = <&dp_hpd>; |
104 | samsung,color-space = <0>; | 104 | samsung,color-space = <0>; |
105 | samsung,dynamic-range = <0>; | ||
106 | samsung,ycbcr-coeff = <0>; | ||
107 | samsung,color-depth = <1>; | 105 | samsung,color-depth = <1>; |
108 | samsung,link-rate = <0x0a>; | 106 | samsung,link-rate = <0x0a>; |
109 | samsung,lane-count = <4>; | 107 | samsung,lane-count = <4>; |
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index 6e9edc1610c4..6ba9aec15485 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts | |||
@@ -157,8 +157,6 @@ | |||
157 | pinctrl-names = "default"; | 157 | pinctrl-names = "default"; |
158 | pinctrl-0 = <&dp_hpd_gpio>; | 158 | pinctrl-0 = <&dp_hpd_gpio>; |
159 | samsung,color-space = <0>; | 159 | samsung,color-space = <0>; |
160 | samsung,dynamic-range = <0>; | ||
161 | samsung,ycbcr-coeff = <0>; | ||
162 | samsung,color-depth = <1>; | 160 | samsung,color-depth = <1>; |
163 | samsung,link-rate = <0x0a>; | 161 | samsung,link-rate = <0x0a>; |
164 | samsung,lane-count = <2>; | 162 | samsung,lane-count = <2>; |
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 27e2022de89d..efd94e00c3e5 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig | |||
@@ -40,4 +40,6 @@ config DRM_PARADE_PS8622 | |||
40 | ---help--- | 40 | ---help--- |
41 | Parade eDP-LVDS bridge chip driver. | 41 | Parade eDP-LVDS bridge chip driver. |
42 | 42 | ||
43 | source "drivers/gpu/drm/bridge/analogix/Kconfig" | ||
44 | |||
43 | endmenu | 45 | endmenu |
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index f13c33d67c03..ff821f4b5833 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile | |||
@@ -4,3 +4,4 @@ obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o | |||
4 | obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o | 4 | obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o |
5 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o | 5 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o |
6 | obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o | 6 | obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o |
7 | obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ | ||
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig new file mode 100644 index 000000000000..80f286fa3a69 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/Kconfig | |||
@@ -0,0 +1,3 @@ | |||
1 | config DRM_ANALOGIX_DP | ||
2 | tristate | ||
3 | depends on DRM | ||
diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile new file mode 100644 index 000000000000..cd4010ba6890 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o | ||
2 | obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o | ||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c new file mode 100644 index 000000000000..7699597070a1 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | |||
@@ -0,0 +1,1430 @@ | |||
1 | /* | ||
2 | * Analogix DP (Display Port) core interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_gpio.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/component.h> | ||
23 | #include <linux/phy/phy.h> | ||
24 | |||
25 | #include <drm/drmP.h> | ||
26 | #include <drm/drm_atomic_helper.h> | ||
27 | #include <drm/drm_crtc.h> | ||
28 | #include <drm/drm_crtc_helper.h> | ||
29 | #include <drm/drm_panel.h> | ||
30 | |||
31 | #include <drm/bridge/analogix_dp.h> | ||
32 | |||
33 | #include "analogix_dp_core.h" | ||
34 | |||
35 | #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) | ||
36 | |||
37 | struct bridge_init { | ||
38 | struct i2c_client *client; | ||
39 | struct device_node *node; | ||
40 | }; | ||
41 | |||
42 | static void analogix_dp_init_dp(struct analogix_dp_device *dp) | ||
43 | { | ||
44 | analogix_dp_reset(dp); | ||
45 | |||
46 | analogix_dp_swreset(dp); | ||
47 | |||
48 | analogix_dp_init_analog_param(dp); | ||
49 | analogix_dp_init_interrupt(dp); | ||
50 | |||
51 | /* SW defined function Normal operation */ | ||
52 | analogix_dp_enable_sw_function(dp); | ||
53 | |||
54 | analogix_dp_config_interrupt(dp); | ||
55 | analogix_dp_init_analog_func(dp); | ||
56 | |||
57 | analogix_dp_init_hpd(dp); | ||
58 | analogix_dp_init_aux(dp); | ||
59 | } | ||
60 | |||
61 | static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) | ||
62 | { | ||
63 | int timeout_loop = 0; | ||
64 | |||
65 | while (timeout_loop < DP_TIMEOUT_LOOP_COUNT) { | ||
66 | if (analogix_dp_get_plug_in_status(dp) == 0) | ||
67 | return 0; | ||
68 | |||
69 | timeout_loop++; | ||
70 | usleep_range(10, 11); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Some edp screen do not have hpd signal, so we can't just | ||
75 | * return failed when hpd plug in detect failed, DT property | ||
76 | * "force-hpd" would indicate whether driver need this. | ||
77 | */ | ||
78 | if (!dp->force_hpd) | ||
79 | return -ETIMEDOUT; | ||
80 | |||
81 | /* | ||
82 | * The eDP TRM indicate that if HPD_STATUS(RO) is 0, AUX CH | ||
83 | * will not work, so we need to give a force hpd action to | ||
84 | * set HPD_STATUS manually. | ||
85 | */ | ||
86 | dev_dbg(dp->dev, "failed to get hpd plug status, try to force hpd\n"); | ||
87 | |||
88 | analogix_dp_force_hpd(dp); | ||
89 | |||
90 | if (analogix_dp_get_plug_in_status(dp) != 0) { | ||
91 | dev_err(dp->dev, "failed to get hpd plug in status\n"); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | dev_dbg(dp->dev, "success to get plug in status after force hpd\n"); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) | ||
101 | { | ||
102 | int i; | ||
103 | unsigned char sum = 0; | ||
104 | |||
105 | for (i = 0; i < EDID_BLOCK_LENGTH; i++) | ||
106 | sum = sum + edid_data[i]; | ||
107 | |||
108 | return sum; | ||
109 | } | ||
110 | |||
111 | static int analogix_dp_read_edid(struct analogix_dp_device *dp) | ||
112 | { | ||
113 | unsigned char *edid = dp->edid; | ||
114 | unsigned int extend_block = 0; | ||
115 | unsigned char sum; | ||
116 | unsigned char test_vector; | ||
117 | int retval; | ||
118 | |||
119 | /* | ||
120 | * EDID device address is 0x50. | ||
121 | * However, if necessary, you must have set upper address | ||
122 | * into E-EDID in I2C device, 0x30. | ||
123 | */ | ||
124 | |||
125 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ | ||
126 | retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | ||
127 | EDID_EXTENSION_FLAG, | ||
128 | &extend_block); | ||
129 | if (retval) | ||
130 | return retval; | ||
131 | |||
132 | if (extend_block > 0) { | ||
133 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); | ||
134 | |||
135 | /* Read EDID data */ | ||
136 | retval = analogix_dp_read_bytes_from_i2c(dp, | ||
137 | I2C_EDID_DEVICE_ADDR, | ||
138 | EDID_HEADER_PATTERN, | ||
139 | EDID_BLOCK_LENGTH, | ||
140 | &edid[EDID_HEADER_PATTERN]); | ||
141 | if (retval != 0) { | ||
142 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
143 | return -EIO; | ||
144 | } | ||
145 | sum = analogix_dp_calc_edid_check_sum(edid); | ||
146 | if (sum != 0) { | ||
147 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
148 | return -EIO; | ||
149 | } | ||
150 | |||
151 | /* Read additional EDID data */ | ||
152 | retval = analogix_dp_read_bytes_from_i2c(dp, | ||
153 | I2C_EDID_DEVICE_ADDR, | ||
154 | EDID_BLOCK_LENGTH, | ||
155 | EDID_BLOCK_LENGTH, | ||
156 | &edid[EDID_BLOCK_LENGTH]); | ||
157 | if (retval != 0) { | ||
158 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
159 | return -EIO; | ||
160 | } | ||
161 | sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); | ||
162 | if (sum != 0) { | ||
163 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
164 | return -EIO; | ||
165 | } | ||
166 | |||
167 | analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, | ||
168 | &test_vector); | ||
169 | if (test_vector & DP_TEST_LINK_EDID_READ) { | ||
170 | analogix_dp_write_byte_to_dpcd(dp, | ||
171 | DP_TEST_EDID_CHECKSUM, | ||
172 | edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); | ||
173 | analogix_dp_write_byte_to_dpcd(dp, | ||
174 | DP_TEST_RESPONSE, | ||
175 | DP_TEST_EDID_CHECKSUM_WRITE); | ||
176 | } | ||
177 | } else { | ||
178 | dev_info(dp->dev, "EDID data does not include any extensions.\n"); | ||
179 | |||
180 | /* Read EDID data */ | ||
181 | retval = analogix_dp_read_bytes_from_i2c(dp, | ||
182 | I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, | ||
183 | EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); | ||
184 | if (retval != 0) { | ||
185 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
186 | return -EIO; | ||
187 | } | ||
188 | sum = analogix_dp_calc_edid_check_sum(edid); | ||
189 | if (sum != 0) { | ||
190 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
191 | return -EIO; | ||
192 | } | ||
193 | |||
194 | analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, | ||
195 | &test_vector); | ||
196 | if (test_vector & DP_TEST_LINK_EDID_READ) { | ||
197 | analogix_dp_write_byte_to_dpcd(dp, | ||
198 | DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); | ||
199 | analogix_dp_write_byte_to_dpcd(dp, | ||
200 | DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | dev_dbg(dp->dev, "EDID Read success!\n"); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int analogix_dp_handle_edid(struct analogix_dp_device *dp) | ||
209 | { | ||
210 | u8 buf[12]; | ||
211 | int i; | ||
212 | int retval; | ||
213 | |||
214 | /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | ||
215 | retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); | ||
216 | if (retval) | ||
217 | return retval; | ||
218 | |||
219 | /* Read EDID */ | ||
220 | for (i = 0; i < 3; i++) { | ||
221 | retval = analogix_dp_read_edid(dp); | ||
222 | if (!retval) | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | return retval; | ||
227 | } | ||
228 | |||
229 | static void | ||
230 | analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, | ||
231 | bool enable) | ||
232 | { | ||
233 | u8 data; | ||
234 | |||
235 | analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); | ||
236 | |||
237 | if (enable) | ||
238 | analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, | ||
239 | DP_LANE_COUNT_ENHANCED_FRAME_EN | | ||
240 | DPCD_LANE_COUNT_SET(data)); | ||
241 | else | ||
242 | analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, | ||
243 | DPCD_LANE_COUNT_SET(data)); | ||
244 | } | ||
245 | |||
246 | static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) | ||
247 | { | ||
248 | u8 data; | ||
249 | int retval; | ||
250 | |||
251 | analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); | ||
252 | retval = DPCD_ENHANCED_FRAME_CAP(data); | ||
253 | |||
254 | return retval; | ||
255 | } | ||
256 | |||
257 | static void analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp) | ||
258 | { | ||
259 | u8 data; | ||
260 | |||
261 | data = analogix_dp_is_enhanced_mode_available(dp); | ||
262 | analogix_dp_enable_rx_to_enhanced_mode(dp, data); | ||
263 | analogix_dp_enable_enhanced_mode(dp, data); | ||
264 | } | ||
265 | |||
266 | static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) | ||
267 | { | ||
268 | analogix_dp_set_training_pattern(dp, DP_NONE); | ||
269 | |||
270 | analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET, | ||
271 | DP_TRAINING_PATTERN_DISABLE); | ||
272 | } | ||
273 | |||
274 | static void | ||
275 | analogix_dp_set_lane_lane_pre_emphasis(struct analogix_dp_device *dp, | ||
276 | int pre_emphasis, int lane) | ||
277 | { | ||
278 | switch (lane) { | ||
279 | case 0: | ||
280 | analogix_dp_set_lane0_pre_emphasis(dp, pre_emphasis); | ||
281 | break; | ||
282 | case 1: | ||
283 | analogix_dp_set_lane1_pre_emphasis(dp, pre_emphasis); | ||
284 | break; | ||
285 | |||
286 | case 2: | ||
287 | analogix_dp_set_lane2_pre_emphasis(dp, pre_emphasis); | ||
288 | break; | ||
289 | |||
290 | case 3: | ||
291 | analogix_dp_set_lane3_pre_emphasis(dp, pre_emphasis); | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static int analogix_dp_link_start(struct analogix_dp_device *dp) | ||
297 | { | ||
298 | u8 buf[4]; | ||
299 | int lane, lane_count, pll_tries, retval; | ||
300 | |||
301 | lane_count = dp->link_train.lane_count; | ||
302 | |||
303 | dp->link_train.lt_state = CLOCK_RECOVERY; | ||
304 | dp->link_train.eq_loop = 0; | ||
305 | |||
306 | for (lane = 0; lane < lane_count; lane++) | ||
307 | dp->link_train.cr_loop[lane] = 0; | ||
308 | |||
309 | /* Set link rate and count as you want to establish*/ | ||
310 | analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); | ||
311 | analogix_dp_set_lane_count(dp, dp->link_train.lane_count); | ||
312 | |||
313 | /* Setup RX configuration */ | ||
314 | buf[0] = dp->link_train.link_rate; | ||
315 | buf[1] = dp->link_train.lane_count; | ||
316 | retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); | ||
317 | if (retval) | ||
318 | return retval; | ||
319 | |||
320 | /* Set TX pre-emphasis to minimum */ | ||
321 | for (lane = 0; lane < lane_count; lane++) | ||
322 | analogix_dp_set_lane_lane_pre_emphasis(dp, | ||
323 | PRE_EMPHASIS_LEVEL_0, lane); | ||
324 | |||
325 | /* Wait for PLL lock */ | ||
326 | pll_tries = 0; | ||
327 | while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
328 | if (pll_tries == DP_TIMEOUT_LOOP_COUNT) { | ||
329 | dev_err(dp->dev, "Wait for PLL lock timed out\n"); | ||
330 | return -ETIMEDOUT; | ||
331 | } | ||
332 | |||
333 | pll_tries++; | ||
334 | usleep_range(90, 120); | ||
335 | } | ||
336 | |||
337 | /* Set training pattern 1 */ | ||
338 | analogix_dp_set_training_pattern(dp, TRAINING_PTN1); | ||
339 | |||
340 | /* Set RX training pattern */ | ||
341 | retval = analogix_dp_write_byte_to_dpcd(dp, | ||
342 | DP_TRAINING_PATTERN_SET, | ||
343 | DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); | ||
344 | if (retval) | ||
345 | return retval; | ||
346 | |||
347 | for (lane = 0; lane < lane_count; lane++) | ||
348 | buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | | ||
349 | DP_TRAIN_VOLTAGE_SWING_LEVEL_0; | ||
350 | |||
351 | retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, | ||
352 | lane_count, buf); | ||
353 | |||
354 | return retval; | ||
355 | } | ||
356 | |||
357 | static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) | ||
358 | { | ||
359 | int shift = (lane & 1) * 4; | ||
360 | u8 link_value = link_status[lane >> 1]; | ||
361 | |||
362 | return (link_value >> shift) & 0xf; | ||
363 | } | ||
364 | |||
365 | static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count) | ||
366 | { | ||
367 | int lane; | ||
368 | u8 lane_status; | ||
369 | |||
370 | for (lane = 0; lane < lane_count; lane++) { | ||
371 | lane_status = analogix_dp_get_lane_status(link_status, lane); | ||
372 | if ((lane_status & DP_LANE_CR_DONE) == 0) | ||
373 | return -EINVAL; | ||
374 | } | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align, | ||
379 | int lane_count) | ||
380 | { | ||
381 | int lane; | ||
382 | u8 lane_status; | ||
383 | |||
384 | if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) | ||
385 | return -EINVAL; | ||
386 | |||
387 | for (lane = 0; lane < lane_count; lane++) { | ||
388 | lane_status = analogix_dp_get_lane_status(link_status, lane); | ||
389 | lane_status &= DP_CHANNEL_EQ_BITS; | ||
390 | if (lane_status != DP_CHANNEL_EQ_BITS) | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static unsigned char | ||
398 | analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane) | ||
399 | { | ||
400 | int shift = (lane & 1) * 4; | ||
401 | u8 link_value = adjust_request[lane >> 1]; | ||
402 | |||
403 | return (link_value >> shift) & 0x3; | ||
404 | } | ||
405 | |||
406 | static unsigned char analogix_dp_get_adjust_request_pre_emphasis( | ||
407 | u8 adjust_request[2], | ||
408 | int lane) | ||
409 | { | ||
410 | int shift = (lane & 1) * 4; | ||
411 | u8 link_value = adjust_request[lane >> 1]; | ||
412 | |||
413 | return ((link_value >> shift) & 0xc) >> 2; | ||
414 | } | ||
415 | |||
416 | static void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp, | ||
417 | u8 training_lane_set, int lane) | ||
418 | { | ||
419 | switch (lane) { | ||
420 | case 0: | ||
421 | analogix_dp_set_lane0_link_training(dp, training_lane_set); | ||
422 | break; | ||
423 | case 1: | ||
424 | analogix_dp_set_lane1_link_training(dp, training_lane_set); | ||
425 | break; | ||
426 | |||
427 | case 2: | ||
428 | analogix_dp_set_lane2_link_training(dp, training_lane_set); | ||
429 | break; | ||
430 | |||
431 | case 3: | ||
432 | analogix_dp_set_lane3_link_training(dp, training_lane_set); | ||
433 | break; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | static unsigned int | ||
438 | analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, | ||
439 | int lane) | ||
440 | { | ||
441 | u32 reg; | ||
442 | |||
443 | switch (lane) { | ||
444 | case 0: | ||
445 | reg = analogix_dp_get_lane0_link_training(dp); | ||
446 | break; | ||
447 | case 1: | ||
448 | reg = analogix_dp_get_lane1_link_training(dp); | ||
449 | break; | ||
450 | case 2: | ||
451 | reg = analogix_dp_get_lane2_link_training(dp); | ||
452 | break; | ||
453 | case 3: | ||
454 | reg = analogix_dp_get_lane3_link_training(dp); | ||
455 | break; | ||
456 | default: | ||
457 | WARN_ON(1); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | return reg; | ||
462 | } | ||
463 | |||
464 | static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) | ||
465 | { | ||
466 | analogix_dp_training_pattern_dis(dp); | ||
467 | analogix_dp_set_enhanced_mode(dp); | ||
468 | |||
469 | dp->link_train.lt_state = FAILED; | ||
470 | } | ||
471 | |||
472 | static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp, | ||
473 | u8 adjust_request[2]) | ||
474 | { | ||
475 | int lane, lane_count; | ||
476 | u8 voltage_swing, pre_emphasis, training_lane; | ||
477 | |||
478 | lane_count = dp->link_train.lane_count; | ||
479 | for (lane = 0; lane < lane_count; lane++) { | ||
480 | voltage_swing = analogix_dp_get_adjust_request_voltage( | ||
481 | adjust_request, lane); | ||
482 | pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( | ||
483 | adjust_request, lane); | ||
484 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
485 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
486 | |||
487 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
488 | training_lane |= DP_TRAIN_MAX_SWING_REACHED; | ||
489 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
490 | training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; | ||
491 | |||
492 | dp->link_train.training_lane[lane] = training_lane; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) | ||
497 | { | ||
498 | int lane, lane_count, retval; | ||
499 | u8 voltage_swing, pre_emphasis, training_lane; | ||
500 | u8 link_status[2], adjust_request[2]; | ||
501 | |||
502 | usleep_range(100, 101); | ||
503 | |||
504 | lane_count = dp->link_train.lane_count; | ||
505 | |||
506 | retval = analogix_dp_read_bytes_from_dpcd(dp, | ||
507 | DP_LANE0_1_STATUS, 2, link_status); | ||
508 | if (retval) | ||
509 | return retval; | ||
510 | |||
511 | retval = analogix_dp_read_bytes_from_dpcd(dp, | ||
512 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | ||
513 | if (retval) | ||
514 | return retval; | ||
515 | |||
516 | if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { | ||
517 | /* set training pattern 2 for EQ */ | ||
518 | analogix_dp_set_training_pattern(dp, TRAINING_PTN2); | ||
519 | |||
520 | retval = analogix_dp_write_byte_to_dpcd(dp, | ||
521 | DP_TRAINING_PATTERN_SET, | ||
522 | DP_LINK_SCRAMBLING_DISABLE | | ||
523 | DP_TRAINING_PATTERN_2); | ||
524 | if (retval) | ||
525 | return retval; | ||
526 | |||
527 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); | ||
528 | dp->link_train.lt_state = EQUALIZER_TRAINING; | ||
529 | } else { | ||
530 | for (lane = 0; lane < lane_count; lane++) { | ||
531 | training_lane = analogix_dp_get_lane_link_training( | ||
532 | dp, lane); | ||
533 | voltage_swing = analogix_dp_get_adjust_request_voltage( | ||
534 | adjust_request, lane); | ||
535 | pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( | ||
536 | adjust_request, lane); | ||
537 | |||
538 | if (DPCD_VOLTAGE_SWING_GET(training_lane) == | ||
539 | voltage_swing && | ||
540 | DPCD_PRE_EMPHASIS_GET(training_lane) == | ||
541 | pre_emphasis) | ||
542 | dp->link_train.cr_loop[lane]++; | ||
543 | |||
544 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || | ||
545 | voltage_swing == VOLTAGE_LEVEL_3 || | ||
546 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { | ||
547 | dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", | ||
548 | dp->link_train.cr_loop[lane], | ||
549 | voltage_swing, pre_emphasis); | ||
550 | analogix_dp_reduce_link_rate(dp); | ||
551 | return -EIO; | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | analogix_dp_get_adjust_training_lane(dp, adjust_request); | ||
557 | |||
558 | for (lane = 0; lane < lane_count; lane++) | ||
559 | analogix_dp_set_lane_link_training(dp, | ||
560 | dp->link_train.training_lane[lane], lane); | ||
561 | |||
562 | retval = analogix_dp_write_bytes_to_dpcd(dp, | ||
563 | DP_TRAINING_LANE0_SET, lane_count, | ||
564 | dp->link_train.training_lane); | ||
565 | if (retval) | ||
566 | return retval; | ||
567 | |||
568 | return retval; | ||
569 | } | ||
570 | |||
571 | static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | ||
572 | { | ||
573 | int lane, lane_count, retval; | ||
574 | u32 reg; | ||
575 | u8 link_align, link_status[2], adjust_request[2]; | ||
576 | |||
577 | usleep_range(400, 401); | ||
578 | |||
579 | lane_count = dp->link_train.lane_count; | ||
580 | |||
581 | retval = analogix_dp_read_bytes_from_dpcd(dp, | ||
582 | DP_LANE0_1_STATUS, 2, link_status); | ||
583 | if (retval) | ||
584 | return retval; | ||
585 | |||
586 | if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { | ||
587 | analogix_dp_reduce_link_rate(dp); | ||
588 | return -EIO; | ||
589 | } | ||
590 | |||
591 | retval = analogix_dp_read_bytes_from_dpcd(dp, | ||
592 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | ||
593 | if (retval) | ||
594 | return retval; | ||
595 | |||
596 | retval = analogix_dp_read_byte_from_dpcd(dp, | ||
597 | DP_LANE_ALIGN_STATUS_UPDATED, &link_align); | ||
598 | if (retval) | ||
599 | return retval; | ||
600 | |||
601 | analogix_dp_get_adjust_training_lane(dp, adjust_request); | ||
602 | |||
603 | if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { | ||
604 | /* traing pattern Set to Normal */ | ||
605 | analogix_dp_training_pattern_dis(dp); | ||
606 | |||
607 | dev_info(dp->dev, "Link Training success!\n"); | ||
608 | |||
609 | analogix_dp_get_link_bandwidth(dp, ®); | ||
610 | dp->link_train.link_rate = reg; | ||
611 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", | ||
612 | dp->link_train.link_rate); | ||
613 | |||
614 | analogix_dp_get_lane_count(dp, ®); | ||
615 | dp->link_train.lane_count = reg; | ||
616 | dev_dbg(dp->dev, "final lane count = %.2x\n", | ||
617 | dp->link_train.lane_count); | ||
618 | |||
619 | /* set enhanced mode if available */ | ||
620 | analogix_dp_set_enhanced_mode(dp); | ||
621 | dp->link_train.lt_state = FINISHED; | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | /* not all locked */ | ||
627 | dp->link_train.eq_loop++; | ||
628 | |||
629 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { | ||
630 | dev_err(dp->dev, "EQ Max loop\n"); | ||
631 | analogix_dp_reduce_link_rate(dp); | ||
632 | return -EIO; | ||
633 | } | ||
634 | |||
635 | for (lane = 0; lane < lane_count; lane++) | ||
636 | analogix_dp_set_lane_link_training(dp, | ||
637 | dp->link_train.training_lane[lane], lane); | ||
638 | |||
639 | retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, | ||
640 | lane_count, dp->link_train.training_lane); | ||
641 | |||
642 | return retval; | ||
643 | } | ||
644 | |||
645 | static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, | ||
646 | u8 *bandwidth) | ||
647 | { | ||
648 | u8 data; | ||
649 | |||
650 | /* | ||
651 | * For DP rev.1.1, Maximum link rate of Main Link lanes | ||
652 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps | ||
653 | * For DP rev.1.2, Maximum link rate of Main Link lanes | ||
654 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps | ||
655 | */ | ||
656 | analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); | ||
657 | *bandwidth = data; | ||
658 | } | ||
659 | |||
660 | static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, | ||
661 | u8 *lane_count) | ||
662 | { | ||
663 | u8 data; | ||
664 | |||
665 | /* | ||
666 | * For DP rev.1.1, Maximum number of Main Link lanes | ||
667 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes | ||
668 | */ | ||
669 | analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); | ||
670 | *lane_count = DPCD_MAX_LANE_COUNT(data); | ||
671 | } | ||
672 | |||
673 | static void analogix_dp_init_training(struct analogix_dp_device *dp, | ||
674 | enum link_lane_count_type max_lane, | ||
675 | int max_rate) | ||
676 | { | ||
677 | /* | ||
678 | * MACRO_RST must be applied after the PLL_LOCK to avoid | ||
679 | * the DP inter pair skew issue for at least 10 us | ||
680 | */ | ||
681 | analogix_dp_reset_macro(dp); | ||
682 | |||
683 | /* Initialize by reading RX's DPCD */ | ||
684 | analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); | ||
685 | analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); | ||
686 | |||
687 | if ((dp->link_train.link_rate != DP_LINK_BW_1_62) && | ||
688 | (dp->link_train.link_rate != DP_LINK_BW_2_7) && | ||
689 | (dp->link_train.link_rate != DP_LINK_BW_5_4)) { | ||
690 | dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n", | ||
691 | dp->link_train.link_rate); | ||
692 | dp->link_train.link_rate = DP_LINK_BW_1_62; | ||
693 | } | ||
694 | |||
695 | if (dp->link_train.lane_count == 0) { | ||
696 | dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n", | ||
697 | dp->link_train.lane_count); | ||
698 | dp->link_train.lane_count = (u8)LANE_COUNT1; | ||
699 | } | ||
700 | |||
701 | /* Setup TX lane count & rate */ | ||
702 | if (dp->link_train.lane_count > max_lane) | ||
703 | dp->link_train.lane_count = max_lane; | ||
704 | if (dp->link_train.link_rate > max_rate) | ||
705 | dp->link_train.link_rate = max_rate; | ||
706 | |||
707 | /* All DP analog module power up */ | ||
708 | analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
709 | } | ||
710 | |||
711 | static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) | ||
712 | { | ||
713 | int retval = 0, training_finished = 0; | ||
714 | |||
715 | dp->link_train.lt_state = START; | ||
716 | |||
717 | /* Process here */ | ||
718 | while (!retval && !training_finished) { | ||
719 | switch (dp->link_train.lt_state) { | ||
720 | case START: | ||
721 | retval = analogix_dp_link_start(dp); | ||
722 | if (retval) | ||
723 | dev_err(dp->dev, "LT link start failed!\n"); | ||
724 | break; | ||
725 | case CLOCK_RECOVERY: | ||
726 | retval = analogix_dp_process_clock_recovery(dp); | ||
727 | if (retval) | ||
728 | dev_err(dp->dev, "LT CR failed!\n"); | ||
729 | break; | ||
730 | case EQUALIZER_TRAINING: | ||
731 | retval = analogix_dp_process_equalizer_training(dp); | ||
732 | if (retval) | ||
733 | dev_err(dp->dev, "LT EQ failed!\n"); | ||
734 | break; | ||
735 | case FINISHED: | ||
736 | training_finished = 1; | ||
737 | break; | ||
738 | case FAILED: | ||
739 | return -EREMOTEIO; | ||
740 | } | ||
741 | } | ||
742 | if (retval) | ||
743 | dev_err(dp->dev, "eDP link training failed (%d)\n", retval); | ||
744 | |||
745 | return retval; | ||
746 | } | ||
747 | |||
748 | static int analogix_dp_set_link_train(struct analogix_dp_device *dp, | ||
749 | u32 count, u32 bwtype) | ||
750 | { | ||
751 | int i; | ||
752 | int retval; | ||
753 | |||
754 | for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) { | ||
755 | analogix_dp_init_training(dp, count, bwtype); | ||
756 | retval = analogix_dp_sw_link_training(dp); | ||
757 | if (retval == 0) | ||
758 | break; | ||
759 | |||
760 | usleep_range(100, 110); | ||
761 | } | ||
762 | |||
763 | return retval; | ||
764 | } | ||
765 | |||
766 | static int analogix_dp_config_video(struct analogix_dp_device *dp) | ||
767 | { | ||
768 | int retval = 0; | ||
769 | int timeout_loop = 0; | ||
770 | int done_count = 0; | ||
771 | |||
772 | analogix_dp_config_video_slave_mode(dp); | ||
773 | |||
774 | analogix_dp_set_video_color_format(dp); | ||
775 | |||
776 | if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
777 | dev_err(dp->dev, "PLL is not locked yet.\n"); | ||
778 | return -EINVAL; | ||
779 | } | ||
780 | |||
781 | for (;;) { | ||
782 | timeout_loop++; | ||
783 | if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0) | ||
784 | break; | ||
785 | if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { | ||
786 | dev_err(dp->dev, "Timeout of video streamclk ok\n"); | ||
787 | return -ETIMEDOUT; | ||
788 | } | ||
789 | |||
790 | usleep_range(1, 2); | ||
791 | } | ||
792 | |||
793 | /* Set to use the register calculated M/N video */ | ||
794 | analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); | ||
795 | |||
796 | /* For video bist, Video timing must be generated by register */ | ||
797 | analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); | ||
798 | |||
799 | /* Disable video mute */ | ||
800 | analogix_dp_enable_video_mute(dp, 0); | ||
801 | |||
802 | /* Configure video slave mode */ | ||
803 | analogix_dp_enable_video_master(dp, 0); | ||
804 | |||
805 | timeout_loop = 0; | ||
806 | |||
807 | for (;;) { | ||
808 | timeout_loop++; | ||
809 | if (analogix_dp_is_video_stream_on(dp) == 0) { | ||
810 | done_count++; | ||
811 | if (done_count > 10) | ||
812 | break; | ||
813 | } else if (done_count) { | ||
814 | done_count = 0; | ||
815 | } | ||
816 | if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { | ||
817 | dev_err(dp->dev, "Timeout of video streamclk ok\n"); | ||
818 | return -ETIMEDOUT; | ||
819 | } | ||
820 | |||
821 | usleep_range(1000, 1001); | ||
822 | } | ||
823 | |||
824 | if (retval != 0) | ||
825 | dev_err(dp->dev, "Video stream is not detected!\n"); | ||
826 | |||
827 | return retval; | ||
828 | } | ||
829 | |||
830 | static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, | ||
831 | bool enable) | ||
832 | { | ||
833 | u8 data; | ||
834 | |||
835 | if (enable) { | ||
836 | analogix_dp_enable_scrambling(dp); | ||
837 | |||
838 | analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, | ||
839 | &data); | ||
840 | analogix_dp_write_byte_to_dpcd(dp, | ||
841 | DP_TRAINING_PATTERN_SET, | ||
842 | (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); | ||
843 | } else { | ||
844 | analogix_dp_disable_scrambling(dp); | ||
845 | |||
846 | analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, | ||
847 | &data); | ||
848 | analogix_dp_write_byte_to_dpcd(dp, | ||
849 | DP_TRAINING_PATTERN_SET, | ||
850 | (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); | ||
851 | } | ||
852 | } | ||
853 | |||
854 | static irqreturn_t analogix_dp_hardirq(int irq, void *arg) | ||
855 | { | ||
856 | struct analogix_dp_device *dp = arg; | ||
857 | irqreturn_t ret = IRQ_NONE; | ||
858 | enum dp_irq_type irq_type; | ||
859 | |||
860 | irq_type = analogix_dp_get_irq_type(dp); | ||
861 | if (irq_type != DP_IRQ_TYPE_UNKNOWN) { | ||
862 | analogix_dp_mute_hpd_interrupt(dp); | ||
863 | ret = IRQ_WAKE_THREAD; | ||
864 | } | ||
865 | |||
866 | return ret; | ||
867 | } | ||
868 | |||
869 | static irqreturn_t analogix_dp_irq_thread(int irq, void *arg) | ||
870 | { | ||
871 | struct analogix_dp_device *dp = arg; | ||
872 | enum dp_irq_type irq_type; | ||
873 | |||
874 | irq_type = analogix_dp_get_irq_type(dp); | ||
875 | if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN || | ||
876 | irq_type & DP_IRQ_TYPE_HP_CABLE_OUT) { | ||
877 | dev_dbg(dp->dev, "Detected cable status changed!\n"); | ||
878 | if (dp->drm_dev) | ||
879 | drm_helper_hpd_irq_event(dp->drm_dev); | ||
880 | } | ||
881 | |||
882 | if (irq_type != DP_IRQ_TYPE_UNKNOWN) { | ||
883 | analogix_dp_clear_hotplug_interrupts(dp); | ||
884 | analogix_dp_unmute_hpd_interrupt(dp); | ||
885 | } | ||
886 | |||
887 | return IRQ_HANDLED; | ||
888 | } | ||
889 | |||
890 | static void analogix_dp_commit(struct analogix_dp_device *dp) | ||
891 | { | ||
892 | int ret; | ||
893 | |||
894 | /* Keep the panel disabled while we configure video */ | ||
895 | if (dp->plat_data->panel) { | ||
896 | if (drm_panel_disable(dp->plat_data->panel)) | ||
897 | DRM_ERROR("failed to disable the panel\n"); | ||
898 | } | ||
899 | |||
900 | ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, | ||
901 | dp->video_info.max_link_rate); | ||
902 | if (ret) { | ||
903 | dev_err(dp->dev, "unable to do link train\n"); | ||
904 | return; | ||
905 | } | ||
906 | |||
907 | analogix_dp_enable_scramble(dp, 1); | ||
908 | analogix_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
909 | analogix_dp_enable_enhanced_mode(dp, 1); | ||
910 | |||
911 | analogix_dp_init_video(dp); | ||
912 | ret = analogix_dp_config_video(dp); | ||
913 | if (ret) | ||
914 | dev_err(dp->dev, "unable to config video\n"); | ||
915 | |||
916 | /* Safe to enable the panel now */ | ||
917 | if (dp->plat_data->panel) { | ||
918 | if (drm_panel_enable(dp->plat_data->panel)) | ||
919 | DRM_ERROR("failed to enable the panel\n"); | ||
920 | } | ||
921 | |||
922 | /* Enable video */ | ||
923 | analogix_dp_start_video(dp); | ||
924 | } | ||
925 | |||
926 | int analogix_dp_get_modes(struct drm_connector *connector) | ||
927 | { | ||
928 | struct analogix_dp_device *dp = to_dp(connector); | ||
929 | struct edid *edid = (struct edid *)dp->edid; | ||
930 | int num_modes = 0; | ||
931 | |||
932 | if (analogix_dp_handle_edid(dp) == 0) { | ||
933 | drm_mode_connector_update_edid_property(&dp->connector, edid); | ||
934 | num_modes += drm_add_edid_modes(&dp->connector, edid); | ||
935 | } | ||
936 | |||
937 | if (dp->plat_data->panel) | ||
938 | num_modes += drm_panel_get_modes(dp->plat_data->panel); | ||
939 | |||
940 | if (dp->plat_data->get_modes) | ||
941 | num_modes += dp->plat_data->get_modes(dp->plat_data); | ||
942 | |||
943 | return num_modes; | ||
944 | } | ||
945 | |||
946 | static struct drm_encoder * | ||
947 | analogix_dp_best_encoder(struct drm_connector *connector) | ||
948 | { | ||
949 | struct analogix_dp_device *dp = to_dp(connector); | ||
950 | |||
951 | return dp->encoder; | ||
952 | } | ||
953 | |||
954 | static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = { | ||
955 | .get_modes = analogix_dp_get_modes, | ||
956 | .best_encoder = analogix_dp_best_encoder, | ||
957 | }; | ||
958 | |||
959 | enum drm_connector_status | ||
960 | analogix_dp_detect(struct drm_connector *connector, bool force) | ||
961 | { | ||
962 | struct analogix_dp_device *dp = to_dp(connector); | ||
963 | |||
964 | if (analogix_dp_detect_hpd(dp)) | ||
965 | return connector_status_disconnected; | ||
966 | |||
967 | return connector_status_connected; | ||
968 | } | ||
969 | |||
970 | static void analogix_dp_connector_destroy(struct drm_connector *connector) | ||
971 | { | ||
972 | drm_connector_unregister(connector); | ||
973 | drm_connector_cleanup(connector); | ||
974 | |||
975 | } | ||
976 | |||
977 | static const struct drm_connector_funcs analogix_dp_connector_funcs = { | ||
978 | .dpms = drm_atomic_helper_connector_dpms, | ||
979 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
980 | .detect = analogix_dp_detect, | ||
981 | .destroy = analogix_dp_connector_destroy, | ||
982 | .reset = drm_atomic_helper_connector_reset, | ||
983 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
984 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
985 | }; | ||
986 | |||
987 | static int analogix_dp_bridge_attach(struct drm_bridge *bridge) | ||
988 | { | ||
989 | struct analogix_dp_device *dp = bridge->driver_private; | ||
990 | struct drm_encoder *encoder = dp->encoder; | ||
991 | struct drm_connector *connector = &dp->connector; | ||
992 | int ret; | ||
993 | |||
994 | if (!bridge->encoder) { | ||
995 | DRM_ERROR("Parent encoder object not found"); | ||
996 | return -ENODEV; | ||
997 | } | ||
998 | |||
999 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
1000 | |||
1001 | ret = drm_connector_init(dp->drm_dev, connector, | ||
1002 | &analogix_dp_connector_funcs, | ||
1003 | DRM_MODE_CONNECTOR_eDP); | ||
1004 | if (ret) { | ||
1005 | DRM_ERROR("Failed to initialize connector with drm\n"); | ||
1006 | return ret; | ||
1007 | } | ||
1008 | |||
1009 | drm_connector_helper_add(connector, | ||
1010 | &analogix_dp_connector_helper_funcs); | ||
1011 | drm_mode_connector_attach_encoder(connector, encoder); | ||
1012 | |||
1013 | /* | ||
1014 | * NOTE: the connector registration is implemented in analogix | ||
1015 | * platform driver, that to say connector would be exist after | ||
1016 | * plat_data->attch return, that's why we record the connector | ||
1017 | * point after plat attached. | ||
1018 | */ | ||
1019 | if (dp->plat_data->attach) { | ||
1020 | ret = dp->plat_data->attach(dp->plat_data, bridge, connector); | ||
1021 | if (ret) { | ||
1022 | DRM_ERROR("Failed at platform attch func\n"); | ||
1023 | return ret; | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | if (dp->plat_data->panel) { | ||
1028 | ret = drm_panel_attach(dp->plat_data->panel, &dp->connector); | ||
1029 | if (ret) { | ||
1030 | DRM_ERROR("Failed to attach panel\n"); | ||
1031 | return ret; | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | static void analogix_dp_bridge_enable(struct drm_bridge *bridge) | ||
1039 | { | ||
1040 | struct analogix_dp_device *dp = bridge->driver_private; | ||
1041 | |||
1042 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) | ||
1043 | return; | ||
1044 | |||
1045 | pm_runtime_get_sync(dp->dev); | ||
1046 | |||
1047 | if (dp->plat_data->power_on) | ||
1048 | dp->plat_data->power_on(dp->plat_data); | ||
1049 | |||
1050 | phy_power_on(dp->phy); | ||
1051 | analogix_dp_init_dp(dp); | ||
1052 | enable_irq(dp->irq); | ||
1053 | analogix_dp_commit(dp); | ||
1054 | |||
1055 | dp->dpms_mode = DRM_MODE_DPMS_ON; | ||
1056 | } | ||
1057 | |||
1058 | static void analogix_dp_bridge_disable(struct drm_bridge *bridge) | ||
1059 | { | ||
1060 | struct analogix_dp_device *dp = bridge->driver_private; | ||
1061 | |||
1062 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) | ||
1063 | return; | ||
1064 | |||
1065 | if (dp->plat_data->panel) { | ||
1066 | if (drm_panel_disable(dp->plat_data->panel)) { | ||
1067 | DRM_ERROR("failed to disable the panel\n"); | ||
1068 | return; | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | disable_irq(dp->irq); | ||
1073 | phy_power_off(dp->phy); | ||
1074 | |||
1075 | if (dp->plat_data->power_off) | ||
1076 | dp->plat_data->power_off(dp->plat_data); | ||
1077 | |||
1078 | pm_runtime_put_sync(dp->dev); | ||
1079 | |||
1080 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | ||
1081 | } | ||
1082 | |||
1083 | static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, | ||
1084 | struct drm_display_mode *orig_mode, | ||
1085 | struct drm_display_mode *mode) | ||
1086 | { | ||
1087 | struct analogix_dp_device *dp = bridge->driver_private; | ||
1088 | struct drm_display_info *display_info = &dp->connector.display_info; | ||
1089 | struct video_info *video = &dp->video_info; | ||
1090 | struct device_node *dp_node = dp->dev->of_node; | ||
1091 | int vic; | ||
1092 | |||
1093 | /* Input video interlaces & hsync pol & vsync pol */ | ||
1094 | video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); | ||
1095 | video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); | ||
1096 | video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); | ||
1097 | |||
1098 | /* Input video dynamic_range & colorimetry */ | ||
1099 | vic = drm_match_cea_mode(mode); | ||
1100 | if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) || | ||
1101 | (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) { | ||
1102 | video->dynamic_range = CEA; | ||
1103 | video->ycbcr_coeff = COLOR_YCBCR601; | ||
1104 | } else if (vic) { | ||
1105 | video->dynamic_range = CEA; | ||
1106 | video->ycbcr_coeff = COLOR_YCBCR709; | ||
1107 | } else { | ||
1108 | video->dynamic_range = VESA; | ||
1109 | video->ycbcr_coeff = COLOR_YCBCR709; | ||
1110 | } | ||
1111 | |||
1112 | /* Input vide bpc and color_formats */ | ||
1113 | switch (display_info->bpc) { | ||
1114 | case 12: | ||
1115 | video->color_depth = COLOR_12; | ||
1116 | break; | ||
1117 | case 10: | ||
1118 | video->color_depth = COLOR_10; | ||
1119 | break; | ||
1120 | case 8: | ||
1121 | video->color_depth = COLOR_8; | ||
1122 | break; | ||
1123 | case 6: | ||
1124 | video->color_depth = COLOR_6; | ||
1125 | break; | ||
1126 | default: | ||
1127 | video->color_depth = COLOR_8; | ||
1128 | break; | ||
1129 | } | ||
1130 | if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||
1131 | video->color_space = COLOR_YCBCR444; | ||
1132 | else if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | ||
1133 | video->color_space = COLOR_YCBCR422; | ||
1134 | else if (display_info->color_formats & DRM_COLOR_FORMAT_RGB444) | ||
1135 | video->color_space = COLOR_RGB; | ||
1136 | else | ||
1137 | video->color_space = COLOR_RGB; | ||
1138 | |||
1139 | /* | ||
1140 | * NOTE: those property parsing code is used for providing backward | ||
1141 | * compatibility for samsung platform. | ||
1142 | * Due to we used the "of_property_read_u32" interfaces, when this | ||
1143 | * property isn't present, the "video_info" can keep the original | ||
1144 | * values and wouldn't be modified. | ||
1145 | */ | ||
1146 | of_property_read_u32(dp_node, "samsung,color-space", | ||
1147 | &video->color_space); | ||
1148 | of_property_read_u32(dp_node, "samsung,dynamic-range", | ||
1149 | &video->dynamic_range); | ||
1150 | of_property_read_u32(dp_node, "samsung,ycbcr-coeff", | ||
1151 | &video->ycbcr_coeff); | ||
1152 | of_property_read_u32(dp_node, "samsung,color-depth", | ||
1153 | &video->color_depth); | ||
1154 | if (of_property_read_bool(dp_node, "hsync-active-high")) | ||
1155 | video->h_sync_polarity = true; | ||
1156 | if (of_property_read_bool(dp_node, "vsync-active-high")) | ||
1157 | video->v_sync_polarity = true; | ||
1158 | if (of_property_read_bool(dp_node, "interlaced")) | ||
1159 | video->interlaced = true; | ||
1160 | } | ||
1161 | |||
1162 | static void analogix_dp_bridge_nop(struct drm_bridge *bridge) | ||
1163 | { | ||
1164 | /* do nothing */ | ||
1165 | } | ||
1166 | |||
1167 | static const struct drm_bridge_funcs analogix_dp_bridge_funcs = { | ||
1168 | .enable = analogix_dp_bridge_enable, | ||
1169 | .disable = analogix_dp_bridge_disable, | ||
1170 | .pre_enable = analogix_dp_bridge_nop, | ||
1171 | .post_disable = analogix_dp_bridge_nop, | ||
1172 | .mode_set = analogix_dp_bridge_mode_set, | ||
1173 | .attach = analogix_dp_bridge_attach, | ||
1174 | }; | ||
1175 | |||
1176 | static int analogix_dp_create_bridge(struct drm_device *drm_dev, | ||
1177 | struct analogix_dp_device *dp) | ||
1178 | { | ||
1179 | struct drm_bridge *bridge; | ||
1180 | int ret; | ||
1181 | |||
1182 | bridge = devm_kzalloc(drm_dev->dev, sizeof(*bridge), GFP_KERNEL); | ||
1183 | if (!bridge) { | ||
1184 | DRM_ERROR("failed to allocate for drm bridge\n"); | ||
1185 | return -ENOMEM; | ||
1186 | } | ||
1187 | |||
1188 | dp->bridge = bridge; | ||
1189 | |||
1190 | dp->encoder->bridge = bridge; | ||
1191 | bridge->driver_private = dp; | ||
1192 | bridge->encoder = dp->encoder; | ||
1193 | bridge->funcs = &analogix_dp_bridge_funcs; | ||
1194 | |||
1195 | ret = drm_bridge_attach(drm_dev, bridge); | ||
1196 | if (ret) { | ||
1197 | DRM_ERROR("failed to attach drm bridge\n"); | ||
1198 | return -EINVAL; | ||
1199 | } | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) | ||
1205 | { | ||
1206 | struct device_node *dp_node = dp->dev->of_node; | ||
1207 | struct video_info *video_info = &dp->video_info; | ||
1208 | |||
1209 | switch (dp->plat_data->dev_type) { | ||
1210 | case RK3288_DP: | ||
1211 | /* | ||
1212 | * Like Rk3288 DisplayPort TRM indicate that "Main link | ||
1213 | * containing 4 physical lanes of 2.7/1.62 Gbps/lane". | ||
1214 | */ | ||
1215 | video_info->max_link_rate = 0x0A; | ||
1216 | video_info->max_lane_count = 0x04; | ||
1217 | break; | ||
1218 | case EXYNOS_DP: | ||
1219 | /* | ||
1220 | * NOTE: those property parseing code is used for | ||
1221 | * providing backward compatibility for samsung platform. | ||
1222 | */ | ||
1223 | of_property_read_u32(dp_node, "samsung,link-rate", | ||
1224 | &video_info->max_link_rate); | ||
1225 | of_property_read_u32(dp_node, "samsung,lane-count", | ||
1226 | &video_info->max_lane_count); | ||
1227 | break; | ||
1228 | } | ||
1229 | |||
1230 | return 0; | ||
1231 | } | ||
1232 | |||
1233 | int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, | ||
1234 | struct analogix_dp_plat_data *plat_data) | ||
1235 | { | ||
1236 | struct platform_device *pdev = to_platform_device(dev); | ||
1237 | struct analogix_dp_device *dp; | ||
1238 | struct resource *res; | ||
1239 | unsigned int irq_flags; | ||
1240 | int ret; | ||
1241 | |||
1242 | if (!plat_data) { | ||
1243 | dev_err(dev, "Invalided input plat_data\n"); | ||
1244 | return -EINVAL; | ||
1245 | } | ||
1246 | |||
1247 | dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL); | ||
1248 | if (!dp) | ||
1249 | return -ENOMEM; | ||
1250 | |||
1251 | dev_set_drvdata(dev, dp); | ||
1252 | |||
1253 | dp->dev = &pdev->dev; | ||
1254 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | ||
1255 | |||
1256 | /* | ||
1257 | * platform dp driver need containor_of the plat_data to get | ||
1258 | * the driver private data, so we need to store the point of | ||
1259 | * plat_data, not the context of plat_data. | ||
1260 | */ | ||
1261 | dp->plat_data = plat_data; | ||
1262 | |||
1263 | ret = analogix_dp_dt_parse_pdata(dp); | ||
1264 | if (ret) | ||
1265 | return ret; | ||
1266 | |||
1267 | dp->phy = devm_phy_get(dp->dev, "dp"); | ||
1268 | if (IS_ERR(dp->phy)) { | ||
1269 | dev_err(dp->dev, "no DP phy configured\n"); | ||
1270 | ret = PTR_ERR(dp->phy); | ||
1271 | if (ret) { | ||
1272 | /* | ||
1273 | * phy itself is not enabled, so we can move forward | ||
1274 | * assigning NULL to phy pointer. | ||
1275 | */ | ||
1276 | if (ret == -ENOSYS || ret == -ENODEV) | ||
1277 | dp->phy = NULL; | ||
1278 | else | ||
1279 | return ret; | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | dp->clock = devm_clk_get(&pdev->dev, "dp"); | ||
1284 | if (IS_ERR(dp->clock)) { | ||
1285 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
1286 | return PTR_ERR(dp->clock); | ||
1287 | } | ||
1288 | |||
1289 | clk_prepare_enable(dp->clock); | ||
1290 | |||
1291 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1292 | |||
1293 | dp->reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
1294 | if (IS_ERR(dp->reg_base)) | ||
1295 | return PTR_ERR(dp->reg_base); | ||
1296 | |||
1297 | dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd"); | ||
1298 | |||
1299 | dp->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0); | ||
1300 | if (!gpio_is_valid(dp->hpd_gpio)) | ||
1301 | dp->hpd_gpio = of_get_named_gpio(dev->of_node, | ||
1302 | "samsung,hpd-gpio", 0); | ||
1303 | |||
1304 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
1305 | /* | ||
1306 | * Set up the hotplug GPIO from the device tree as an interrupt. | ||
1307 | * Simply specifying a different interrupt in the device tree | ||
1308 | * doesn't work since we handle hotplug rather differently when | ||
1309 | * using a GPIO. We also need the actual GPIO specifier so | ||
1310 | * that we can get the current state of the GPIO. | ||
1311 | */ | ||
1312 | ret = devm_gpio_request_one(&pdev->dev, dp->hpd_gpio, GPIOF_IN, | ||
1313 | "hpd_gpio"); | ||
1314 | if (ret) { | ||
1315 | dev_err(&pdev->dev, "failed to get hpd gpio\n"); | ||
1316 | return ret; | ||
1317 | } | ||
1318 | dp->irq = gpio_to_irq(dp->hpd_gpio); | ||
1319 | irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | ||
1320 | } else { | ||
1321 | dp->hpd_gpio = -ENODEV; | ||
1322 | dp->irq = platform_get_irq(pdev, 0); | ||
1323 | irq_flags = 0; | ||
1324 | } | ||
1325 | |||
1326 | if (dp->irq == -ENXIO) { | ||
1327 | dev_err(&pdev->dev, "failed to get irq\n"); | ||
1328 | return -ENODEV; | ||
1329 | } | ||
1330 | |||
1331 | pm_runtime_enable(dev); | ||
1332 | |||
1333 | phy_power_on(dp->phy); | ||
1334 | |||
1335 | if (dp->plat_data->panel) { | ||
1336 | if (drm_panel_prepare(dp->plat_data->panel)) { | ||
1337 | DRM_ERROR("failed to setup the panel\n"); | ||
1338 | return -EBUSY; | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | analogix_dp_init_dp(dp); | ||
1343 | |||
1344 | ret = devm_request_threaded_irq(&pdev->dev, dp->irq, | ||
1345 | analogix_dp_hardirq, | ||
1346 | analogix_dp_irq_thread, | ||
1347 | irq_flags, "analogix-dp", dp); | ||
1348 | if (ret) { | ||
1349 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
1350 | goto err_disable_pm_runtime; | ||
1351 | } | ||
1352 | disable_irq(dp->irq); | ||
1353 | |||
1354 | dp->drm_dev = drm_dev; | ||
1355 | dp->encoder = dp->plat_data->encoder; | ||
1356 | |||
1357 | ret = analogix_dp_create_bridge(drm_dev, dp); | ||
1358 | if (ret) { | ||
1359 | DRM_ERROR("failed to create bridge (%d)\n", ret); | ||
1360 | drm_encoder_cleanup(dp->encoder); | ||
1361 | goto err_disable_pm_runtime; | ||
1362 | } | ||
1363 | |||
1364 | return 0; | ||
1365 | |||
1366 | err_disable_pm_runtime: | ||
1367 | pm_runtime_disable(dev); | ||
1368 | |||
1369 | return ret; | ||
1370 | } | ||
1371 | EXPORT_SYMBOL_GPL(analogix_dp_bind); | ||
1372 | |||
1373 | void analogix_dp_unbind(struct device *dev, struct device *master, | ||
1374 | void *data) | ||
1375 | { | ||
1376 | struct analogix_dp_device *dp = dev_get_drvdata(dev); | ||
1377 | |||
1378 | analogix_dp_bridge_disable(dp->bridge); | ||
1379 | |||
1380 | if (dp->plat_data->panel) { | ||
1381 | if (drm_panel_unprepare(dp->plat_data->panel)) | ||
1382 | DRM_ERROR("failed to turnoff the panel\n"); | ||
1383 | } | ||
1384 | |||
1385 | pm_runtime_disable(dev); | ||
1386 | } | ||
1387 | EXPORT_SYMBOL_GPL(analogix_dp_unbind); | ||
1388 | |||
1389 | #ifdef CONFIG_PM | ||
1390 | int analogix_dp_suspend(struct device *dev) | ||
1391 | { | ||
1392 | struct analogix_dp_device *dp = dev_get_drvdata(dev); | ||
1393 | |||
1394 | clk_disable_unprepare(dp->clock); | ||
1395 | |||
1396 | if (dp->plat_data->panel) { | ||
1397 | if (drm_panel_unprepare(dp->plat_data->panel)) | ||
1398 | DRM_ERROR("failed to turnoff the panel\n"); | ||
1399 | } | ||
1400 | |||
1401 | return 0; | ||
1402 | } | ||
1403 | EXPORT_SYMBOL_GPL(analogix_dp_suspend); | ||
1404 | |||
1405 | int analogix_dp_resume(struct device *dev) | ||
1406 | { | ||
1407 | struct analogix_dp_device *dp = dev_get_drvdata(dev); | ||
1408 | int ret; | ||
1409 | |||
1410 | ret = clk_prepare_enable(dp->clock); | ||
1411 | if (ret < 0) { | ||
1412 | DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret); | ||
1413 | return ret; | ||
1414 | } | ||
1415 | |||
1416 | if (dp->plat_data->panel) { | ||
1417 | if (drm_panel_prepare(dp->plat_data->panel)) { | ||
1418 | DRM_ERROR("failed to setup the panel\n"); | ||
1419 | return -EBUSY; | ||
1420 | } | ||
1421 | } | ||
1422 | |||
1423 | return 0; | ||
1424 | } | ||
1425 | EXPORT_SYMBOL_GPL(analogix_dp_resume); | ||
1426 | #endif | ||
1427 | |||
1428 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | ||
1429 | MODULE_DESCRIPTION("Analogix DP Core Driver"); | ||
1430 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h new file mode 100644 index 000000000000..f09275d40f70 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Header file for Analogix DP (Display Port) core interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _ANALOGIX_DP_CORE_H | ||
14 | #define _ANALOGIX_DP_CORE_H | ||
15 | |||
16 | #include <drm/drm_crtc.h> | ||
17 | #include <drm/drm_dp_helper.h> | ||
18 | |||
19 | #define DP_TIMEOUT_LOOP_COUNT 100 | ||
20 | #define MAX_CR_LOOP 5 | ||
21 | #define MAX_EQ_LOOP 5 | ||
22 | |||
23 | /* I2C EDID Chip ID, Slave Address */ | ||
24 | #define I2C_EDID_DEVICE_ADDR 0x50 | ||
25 | #define I2C_E_EDID_DEVICE_ADDR 0x30 | ||
26 | |||
27 | #define EDID_BLOCK_LENGTH 0x80 | ||
28 | #define EDID_HEADER_PATTERN 0x00 | ||
29 | #define EDID_EXTENSION_FLAG 0x7e | ||
30 | #define EDID_CHECKSUM 0x7f | ||
31 | |||
32 | /* DP_MAX_LANE_COUNT */ | ||
33 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) | ||
34 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) | ||
35 | |||
36 | /* DP_LANE_COUNT_SET */ | ||
37 | #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) | ||
38 | |||
39 | /* DP_TRAINING_LANE0_SET */ | ||
40 | #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) | ||
41 | #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) | ||
42 | #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) | ||
43 | #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) | ||
44 | |||
45 | enum link_lane_count_type { | ||
46 | LANE_COUNT1 = 1, | ||
47 | LANE_COUNT2 = 2, | ||
48 | LANE_COUNT4 = 4 | ||
49 | }; | ||
50 | |||
51 | enum link_training_state { | ||
52 | START, | ||
53 | CLOCK_RECOVERY, | ||
54 | EQUALIZER_TRAINING, | ||
55 | FINISHED, | ||
56 | FAILED | ||
57 | }; | ||
58 | |||
59 | enum voltage_swing_level { | ||
60 | VOLTAGE_LEVEL_0, | ||
61 | VOLTAGE_LEVEL_1, | ||
62 | VOLTAGE_LEVEL_2, | ||
63 | VOLTAGE_LEVEL_3, | ||
64 | }; | ||
65 | |||
66 | enum pre_emphasis_level { | ||
67 | PRE_EMPHASIS_LEVEL_0, | ||
68 | PRE_EMPHASIS_LEVEL_1, | ||
69 | PRE_EMPHASIS_LEVEL_2, | ||
70 | PRE_EMPHASIS_LEVEL_3, | ||
71 | }; | ||
72 | |||
73 | enum pattern_set { | ||
74 | PRBS7, | ||
75 | D10_2, | ||
76 | TRAINING_PTN1, | ||
77 | TRAINING_PTN2, | ||
78 | DP_NONE | ||
79 | }; | ||
80 | |||
81 | enum color_space { | ||
82 | COLOR_RGB, | ||
83 | COLOR_YCBCR422, | ||
84 | COLOR_YCBCR444 | ||
85 | }; | ||
86 | |||
87 | enum color_depth { | ||
88 | COLOR_6, | ||
89 | COLOR_8, | ||
90 | COLOR_10, | ||
91 | COLOR_12 | ||
92 | }; | ||
93 | |||
94 | enum color_coefficient { | ||
95 | COLOR_YCBCR601, | ||
96 | COLOR_YCBCR709 | ||
97 | }; | ||
98 | |||
99 | enum dynamic_range { | ||
100 | VESA, | ||
101 | CEA | ||
102 | }; | ||
103 | |||
104 | enum pll_status { | ||
105 | PLL_UNLOCKED, | ||
106 | PLL_LOCKED | ||
107 | }; | ||
108 | |||
109 | enum clock_recovery_m_value_type { | ||
110 | CALCULATED_M, | ||
111 | REGISTER_M | ||
112 | }; | ||
113 | |||
114 | enum video_timing_recognition_type { | ||
115 | VIDEO_TIMING_FROM_CAPTURE, | ||
116 | VIDEO_TIMING_FROM_REGISTER | ||
117 | }; | ||
118 | |||
119 | enum analog_power_block { | ||
120 | AUX_BLOCK, | ||
121 | CH0_BLOCK, | ||
122 | CH1_BLOCK, | ||
123 | CH2_BLOCK, | ||
124 | CH3_BLOCK, | ||
125 | ANALOG_TOTAL, | ||
126 | POWER_ALL | ||
127 | }; | ||
128 | |||
129 | enum dp_irq_type { | ||
130 | DP_IRQ_TYPE_HP_CABLE_IN, | ||
131 | DP_IRQ_TYPE_HP_CABLE_OUT, | ||
132 | DP_IRQ_TYPE_HP_CHANGE, | ||
133 | DP_IRQ_TYPE_UNKNOWN, | ||
134 | }; | ||
135 | |||
136 | struct video_info { | ||
137 | char *name; | ||
138 | |||
139 | bool h_sync_polarity; | ||
140 | bool v_sync_polarity; | ||
141 | bool interlaced; | ||
142 | |||
143 | enum color_space color_space; | ||
144 | enum dynamic_range dynamic_range; | ||
145 | enum color_coefficient ycbcr_coeff; | ||
146 | enum color_depth color_depth; | ||
147 | |||
148 | int max_link_rate; | ||
149 | enum link_lane_count_type max_lane_count; | ||
150 | }; | ||
151 | |||
152 | struct link_train { | ||
153 | int eq_loop; | ||
154 | int cr_loop[4]; | ||
155 | |||
156 | u8 link_rate; | ||
157 | u8 lane_count; | ||
158 | u8 training_lane[4]; | ||
159 | |||
160 | enum link_training_state lt_state; | ||
161 | }; | ||
162 | |||
163 | struct analogix_dp_device { | ||
164 | struct drm_encoder *encoder; | ||
165 | struct device *dev; | ||
166 | struct drm_device *drm_dev; | ||
167 | struct drm_connector connector; | ||
168 | struct drm_bridge *bridge; | ||
169 | struct clk *clock; | ||
170 | unsigned int irq; | ||
171 | void __iomem *reg_base; | ||
172 | |||
173 | struct video_info video_info; | ||
174 | struct link_train link_train; | ||
175 | struct phy *phy; | ||
176 | int dpms_mode; | ||
177 | int hpd_gpio; | ||
178 | bool force_hpd; | ||
179 | unsigned char edid[EDID_BLOCK_LENGTH * 2]; | ||
180 | |||
181 | struct analogix_dp_plat_data *plat_data; | ||
182 | }; | ||
183 | |||
184 | /* analogix_dp_reg.c */ | ||
185 | void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable); | ||
186 | void analogix_dp_stop_video(struct analogix_dp_device *dp); | ||
187 | void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable); | ||
188 | void analogix_dp_init_analog_param(struct analogix_dp_device *dp); | ||
189 | void analogix_dp_init_interrupt(struct analogix_dp_device *dp); | ||
190 | void analogix_dp_reset(struct analogix_dp_device *dp); | ||
191 | void analogix_dp_swreset(struct analogix_dp_device *dp); | ||
192 | void analogix_dp_config_interrupt(struct analogix_dp_device *dp); | ||
193 | void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp); | ||
194 | void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp); | ||
195 | enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp); | ||
196 | void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable); | ||
197 | void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, | ||
198 | enum analog_power_block block, | ||
199 | bool enable); | ||
200 | void analogix_dp_init_analog_func(struct analogix_dp_device *dp); | ||
201 | void analogix_dp_init_hpd(struct analogix_dp_device *dp); | ||
202 | void analogix_dp_force_hpd(struct analogix_dp_device *dp); | ||
203 | enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp); | ||
204 | void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp); | ||
205 | void analogix_dp_reset_aux(struct analogix_dp_device *dp); | ||
206 | void analogix_dp_init_aux(struct analogix_dp_device *dp); | ||
207 | int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp); | ||
208 | void analogix_dp_enable_sw_function(struct analogix_dp_device *dp); | ||
209 | int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp); | ||
210 | int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, | ||
211 | unsigned int reg_addr, | ||
212 | unsigned char data); | ||
213 | int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, | ||
214 | unsigned int reg_addr, | ||
215 | unsigned char *data); | ||
216 | int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, | ||
217 | unsigned int reg_addr, | ||
218 | unsigned int count, | ||
219 | unsigned char data[]); | ||
220 | int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, | ||
221 | unsigned int reg_addr, | ||
222 | unsigned int count, | ||
223 | unsigned char data[]); | ||
224 | int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, | ||
225 | unsigned int device_addr, | ||
226 | unsigned int reg_addr); | ||
227 | int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, | ||
228 | unsigned int device_addr, | ||
229 | unsigned int reg_addr, | ||
230 | unsigned int *data); | ||
231 | int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, | ||
232 | unsigned int device_addr, | ||
233 | unsigned int reg_addr, | ||
234 | unsigned int count, | ||
235 | unsigned char edid[]); | ||
236 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype); | ||
237 | void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype); | ||
238 | void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count); | ||
239 | void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count); | ||
240 | void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp, | ||
241 | bool enable); | ||
242 | void analogix_dp_set_training_pattern(struct analogix_dp_device *dp, | ||
243 | enum pattern_set pattern); | ||
244 | void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp, | ||
245 | u32 level); | ||
246 | void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp, | ||
247 | u32 level); | ||
248 | void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp, | ||
249 | u32 level); | ||
250 | void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp, | ||
251 | u32 level); | ||
252 | void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp, | ||
253 | u32 training_lane); | ||
254 | void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp, | ||
255 | u32 training_lane); | ||
256 | void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp, | ||
257 | u32 training_lane); | ||
258 | void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, | ||
259 | u32 training_lane); | ||
260 | u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp); | ||
261 | u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp); | ||
262 | u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp); | ||
263 | u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp); | ||
264 | void analogix_dp_reset_macro(struct analogix_dp_device *dp); | ||
265 | void analogix_dp_init_video(struct analogix_dp_device *dp); | ||
266 | |||
267 | void analogix_dp_set_video_color_format(struct analogix_dp_device *dp); | ||
268 | int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp); | ||
269 | void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp, | ||
270 | enum clock_recovery_m_value_type type, | ||
271 | u32 m_value, | ||
272 | u32 n_value); | ||
273 | void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type); | ||
274 | void analogix_dp_enable_video_master(struct analogix_dp_device *dp, | ||
275 | bool enable); | ||
276 | void analogix_dp_start_video(struct analogix_dp_device *dp); | ||
277 | int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp); | ||
278 | void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); | ||
279 | void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); | ||
280 | void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); | ||
281 | #endif /* _ANALOGIX_DP_CORE_H */ | ||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c new file mode 100644 index 000000000000..49205ef02be3 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | |||
@@ -0,0 +1,1320 @@ | |||
1 | /* | ||
2 | * Analogix DP (Display port) core register interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/gpio.h> | ||
17 | |||
18 | #include <drm/bridge/analogix_dp.h> | ||
19 | |||
20 | #include "analogix_dp_core.h" | ||
21 | #include "analogix_dp_reg.h" | ||
22 | |||
23 | #define COMMON_INT_MASK_1 0 | ||
24 | #define COMMON_INT_MASK_2 0 | ||
25 | #define COMMON_INT_MASK_3 0 | ||
26 | #define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) | ||
27 | #define INT_STA_MASK INT_HPD | ||
28 | |||
29 | void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable) | ||
30 | { | ||
31 | u32 reg; | ||
32 | |||
33 | if (enable) { | ||
34 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
35 | reg |= HDCP_VIDEO_MUTE; | ||
36 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
37 | } else { | ||
38 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
39 | reg &= ~HDCP_VIDEO_MUTE; | ||
40 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | void analogix_dp_stop_video(struct analogix_dp_device *dp) | ||
45 | { | ||
46 | u32 reg; | ||
47 | |||
48 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
49 | reg &= ~VIDEO_EN; | ||
50 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
51 | } | ||
52 | |||
53 | void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable) | ||
54 | { | ||
55 | u32 reg; | ||
56 | |||
57 | if (enable) | ||
58 | reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | | ||
59 | LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; | ||
60 | else | ||
61 | reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | | ||
62 | LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; | ||
63 | |||
64 | writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP); | ||
65 | } | ||
66 | |||
67 | void analogix_dp_init_analog_param(struct analogix_dp_device *dp) | ||
68 | { | ||
69 | u32 reg; | ||
70 | |||
71 | reg = TX_TERMINAL_CTRL_50_OHM; | ||
72 | writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_1); | ||
73 | |||
74 | reg = SEL_24M | TX_DVDD_BIT_1_0625V; | ||
75 | writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2); | ||
76 | |||
77 | if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) { | ||
78 | writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1); | ||
79 | writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2); | ||
80 | writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3); | ||
81 | writel(0x58, dp->reg_base + ANALOGIX_DP_PLL_REG_4); | ||
82 | writel(0x22, dp->reg_base + ANALOGIX_DP_PLL_REG_5); | ||
83 | } | ||
84 | |||
85 | reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; | ||
86 | writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_3); | ||
87 | |||
88 | reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | | ||
89 | TX_CUR1_2X | TX_CUR_16_MA; | ||
90 | writel(reg, dp->reg_base + ANALOGIX_DP_PLL_FILTER_CTL_1); | ||
91 | |||
92 | reg = CH3_AMP_400_MV | CH2_AMP_400_MV | | ||
93 | CH1_AMP_400_MV | CH0_AMP_400_MV; | ||
94 | writel(reg, dp->reg_base + ANALOGIX_DP_TX_AMP_TUNING_CTL); | ||
95 | } | ||
96 | |||
97 | void analogix_dp_init_interrupt(struct analogix_dp_device *dp) | ||
98 | { | ||
99 | /* Set interrupt pin assertion polarity as high */ | ||
100 | writel(INT_POL1 | INT_POL0, dp->reg_base + ANALOGIX_DP_INT_CTL); | ||
101 | |||
102 | /* Clear pending regisers */ | ||
103 | writel(0xff, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); | ||
104 | writel(0x4f, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_2); | ||
105 | writel(0xe0, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_3); | ||
106 | writel(0xe7, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); | ||
107 | writel(0x63, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
108 | |||
109 | /* 0:mask,1: unmask */ | ||
110 | writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1); | ||
111 | writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2); | ||
112 | writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3); | ||
113 | writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); | ||
114 | writel(0x00, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); | ||
115 | } | ||
116 | |||
117 | void analogix_dp_reset(struct analogix_dp_device *dp) | ||
118 | { | ||
119 | u32 reg; | ||
120 | |||
121 | analogix_dp_stop_video(dp); | ||
122 | analogix_dp_enable_video_mute(dp, 0); | ||
123 | |||
124 | reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | | ||
125 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | | ||
126 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; | ||
127 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1); | ||
128 | |||
129 | reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | | ||
130 | SERDES_FIFO_FUNC_EN_N | | ||
131 | LS_CLK_DOMAIN_FUNC_EN_N; | ||
132 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
133 | |||
134 | usleep_range(20, 30); | ||
135 | |||
136 | analogix_dp_lane_swap(dp, 0); | ||
137 | |||
138 | writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1); | ||
139 | writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2); | ||
140 | writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
141 | writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
142 | |||
143 | writel(0x0, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); | ||
144 | writel(0x0, dp->reg_base + ANALOGIX_DP_HDCP_CTL); | ||
145 | |||
146 | writel(0x5e, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_L); | ||
147 | writel(0x1a, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_H); | ||
148 | |||
149 | writel(0x10, dp->reg_base + ANALOGIX_DP_LINK_DEBUG_CTL); | ||
150 | |||
151 | writel(0x0, dp->reg_base + ANALOGIX_DP_PHY_TEST); | ||
152 | |||
153 | writel(0x0, dp->reg_base + ANALOGIX_DP_VIDEO_FIFO_THRD); | ||
154 | writel(0x20, dp->reg_base + ANALOGIX_DP_AUDIO_MARGIN); | ||
155 | |||
156 | writel(0x4, dp->reg_base + ANALOGIX_DP_M_VID_GEN_FILTER_TH); | ||
157 | writel(0x2, dp->reg_base + ANALOGIX_DP_M_AUD_GEN_FILTER_TH); | ||
158 | |||
159 | writel(0x00000101, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); | ||
160 | } | ||
161 | |||
162 | void analogix_dp_swreset(struct analogix_dp_device *dp) | ||
163 | { | ||
164 | writel(RESET_DP_TX, dp->reg_base + ANALOGIX_DP_TX_SW_RESET); | ||
165 | } | ||
166 | |||
167 | void analogix_dp_config_interrupt(struct analogix_dp_device *dp) | ||
168 | { | ||
169 | u32 reg; | ||
170 | |||
171 | /* 0: mask, 1: unmask */ | ||
172 | reg = COMMON_INT_MASK_1; | ||
173 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1); | ||
174 | |||
175 | reg = COMMON_INT_MASK_2; | ||
176 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2); | ||
177 | |||
178 | reg = COMMON_INT_MASK_3; | ||
179 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3); | ||
180 | |||
181 | reg = COMMON_INT_MASK_4; | ||
182 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); | ||
183 | |||
184 | reg = INT_STA_MASK; | ||
185 | writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); | ||
186 | } | ||
187 | |||
188 | void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp) | ||
189 | { | ||
190 | u32 reg; | ||
191 | |||
192 | /* 0: mask, 1: unmask */ | ||
193 | reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); | ||
194 | reg &= ~COMMON_INT_MASK_4; | ||
195 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); | ||
196 | |||
197 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA_MASK); | ||
198 | reg &= ~INT_STA_MASK; | ||
199 | writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); | ||
200 | } | ||
201 | |||
202 | void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp) | ||
203 | { | ||
204 | u32 reg; | ||
205 | |||
206 | /* 0: mask, 1: unmask */ | ||
207 | reg = COMMON_INT_MASK_4; | ||
208 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); | ||
209 | |||
210 | reg = INT_STA_MASK; | ||
211 | writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); | ||
212 | } | ||
213 | |||
214 | enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp) | ||
215 | { | ||
216 | u32 reg; | ||
217 | |||
218 | reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL); | ||
219 | if (reg & PLL_LOCK) | ||
220 | return PLL_LOCKED; | ||
221 | else | ||
222 | return PLL_UNLOCKED; | ||
223 | } | ||
224 | |||
225 | void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable) | ||
226 | { | ||
227 | u32 reg; | ||
228 | |||
229 | if (enable) { | ||
230 | reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL); | ||
231 | reg |= DP_PLL_PD; | ||
232 | writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL); | ||
233 | } else { | ||
234 | reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL); | ||
235 | reg &= ~DP_PLL_PD; | ||
236 | writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, | ||
241 | enum analog_power_block block, | ||
242 | bool enable) | ||
243 | { | ||
244 | u32 reg; | ||
245 | u32 phy_pd_addr = ANALOGIX_DP_PHY_PD; | ||
246 | |||
247 | if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) | ||
248 | phy_pd_addr = ANALOGIX_DP_PD; | ||
249 | |||
250 | switch (block) { | ||
251 | case AUX_BLOCK: | ||
252 | if (enable) { | ||
253 | reg = readl(dp->reg_base + phy_pd_addr); | ||
254 | reg |= AUX_PD; | ||
255 | writel(reg, dp->reg_base + phy_pd_addr); | ||
256 | } else { | ||
257 | reg = readl(dp->reg_base + phy_pd_addr); | ||
258 | reg &= ~AUX_PD; | ||
259 | writel(reg, dp->reg_base + phy_pd_addr); | ||
260 | } | ||
261 | break; | ||
262 | case CH0_BLOCK: | ||
263 | if (enable) { | ||
264 | reg = readl(dp->reg_base + phy_pd_addr); | ||
265 | reg |= CH0_PD; | ||
266 | writel(reg, dp->reg_base + phy_pd_addr); | ||
267 | } else { | ||
268 | reg = readl(dp->reg_base + phy_pd_addr); | ||
269 | reg &= ~CH0_PD; | ||
270 | writel(reg, dp->reg_base + phy_pd_addr); | ||
271 | } | ||
272 | break; | ||
273 | case CH1_BLOCK: | ||
274 | if (enable) { | ||
275 | reg = readl(dp->reg_base + phy_pd_addr); | ||
276 | reg |= CH1_PD; | ||
277 | writel(reg, dp->reg_base + phy_pd_addr); | ||
278 | } else { | ||
279 | reg = readl(dp->reg_base + phy_pd_addr); | ||
280 | reg &= ~CH1_PD; | ||
281 | writel(reg, dp->reg_base + phy_pd_addr); | ||
282 | } | ||
283 | break; | ||
284 | case CH2_BLOCK: | ||
285 | if (enable) { | ||
286 | reg = readl(dp->reg_base + phy_pd_addr); | ||
287 | reg |= CH2_PD; | ||
288 | writel(reg, dp->reg_base + phy_pd_addr); | ||
289 | } else { | ||
290 | reg = readl(dp->reg_base + phy_pd_addr); | ||
291 | reg &= ~CH2_PD; | ||
292 | writel(reg, dp->reg_base + phy_pd_addr); | ||
293 | } | ||
294 | break; | ||
295 | case CH3_BLOCK: | ||
296 | if (enable) { | ||
297 | reg = readl(dp->reg_base + phy_pd_addr); | ||
298 | reg |= CH3_PD; | ||
299 | writel(reg, dp->reg_base + phy_pd_addr); | ||
300 | } else { | ||
301 | reg = readl(dp->reg_base + phy_pd_addr); | ||
302 | reg &= ~CH3_PD; | ||
303 | writel(reg, dp->reg_base + phy_pd_addr); | ||
304 | } | ||
305 | break; | ||
306 | case ANALOG_TOTAL: | ||
307 | if (enable) { | ||
308 | reg = readl(dp->reg_base + phy_pd_addr); | ||
309 | reg |= DP_PHY_PD; | ||
310 | writel(reg, dp->reg_base + phy_pd_addr); | ||
311 | } else { | ||
312 | reg = readl(dp->reg_base + phy_pd_addr); | ||
313 | reg &= ~DP_PHY_PD; | ||
314 | writel(reg, dp->reg_base + phy_pd_addr); | ||
315 | } | ||
316 | break; | ||
317 | case POWER_ALL: | ||
318 | if (enable) { | ||
319 | reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | | ||
320 | CH1_PD | CH0_PD; | ||
321 | writel(reg, dp->reg_base + phy_pd_addr); | ||
322 | } else { | ||
323 | writel(0x00, dp->reg_base + phy_pd_addr); | ||
324 | } | ||
325 | break; | ||
326 | default: | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | void analogix_dp_init_analog_func(struct analogix_dp_device *dp) | ||
332 | { | ||
333 | u32 reg; | ||
334 | int timeout_loop = 0; | ||
335 | |||
336 | analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
337 | |||
338 | reg = PLL_LOCK_CHG; | ||
339 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); | ||
340 | |||
341 | reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL); | ||
342 | reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); | ||
343 | writel(reg, dp->reg_base + ANALOGIX_DP_DEBUG_CTL); | ||
344 | |||
345 | /* Power up PLL */ | ||
346 | if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
347 | analogix_dp_set_pll_power_down(dp, 0); | ||
348 | |||
349 | while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
350 | timeout_loop++; | ||
351 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
352 | dev_err(dp->dev, "failed to get pll lock status\n"); | ||
353 | return; | ||
354 | } | ||
355 | usleep_range(10, 20); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | /* Enable Serdes FIFO function and Link symbol clock domain module */ | ||
360 | reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
361 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | ||
362 | | AUX_FUNC_EN_N); | ||
363 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
364 | } | ||
365 | |||
366 | void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp) | ||
367 | { | ||
368 | u32 reg; | ||
369 | |||
370 | if (gpio_is_valid(dp->hpd_gpio)) | ||
371 | return; | ||
372 | |||
373 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; | ||
374 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); | ||
375 | |||
376 | reg = INT_HPD; | ||
377 | writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
378 | } | ||
379 | |||
380 | void analogix_dp_init_hpd(struct analogix_dp_device *dp) | ||
381 | { | ||
382 | u32 reg; | ||
383 | |||
384 | if (gpio_is_valid(dp->hpd_gpio)) | ||
385 | return; | ||
386 | |||
387 | analogix_dp_clear_hotplug_interrupts(dp); | ||
388 | |||
389 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
390 | reg &= ~(F_HPD | HPD_CTRL); | ||
391 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
392 | } | ||
393 | |||
394 | void analogix_dp_force_hpd(struct analogix_dp_device *dp) | ||
395 | { | ||
396 | u32 reg; | ||
397 | |||
398 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
399 | reg = (F_HPD | HPD_CTRL); | ||
400 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
401 | } | ||
402 | |||
403 | enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp) | ||
404 | { | ||
405 | u32 reg; | ||
406 | |||
407 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
408 | reg = gpio_get_value(dp->hpd_gpio); | ||
409 | if (reg) | ||
410 | return DP_IRQ_TYPE_HP_CABLE_IN; | ||
411 | else | ||
412 | return DP_IRQ_TYPE_HP_CABLE_OUT; | ||
413 | } else { | ||
414 | /* Parse hotplug interrupt status register */ | ||
415 | reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); | ||
416 | |||
417 | if (reg & PLUG) | ||
418 | return DP_IRQ_TYPE_HP_CABLE_IN; | ||
419 | |||
420 | if (reg & HPD_LOST) | ||
421 | return DP_IRQ_TYPE_HP_CABLE_OUT; | ||
422 | |||
423 | if (reg & HOTPLUG_CHG) | ||
424 | return DP_IRQ_TYPE_HP_CHANGE; | ||
425 | |||
426 | return DP_IRQ_TYPE_UNKNOWN; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | void analogix_dp_reset_aux(struct analogix_dp_device *dp) | ||
431 | { | ||
432 | u32 reg; | ||
433 | |||
434 | /* Disable AUX channel module */ | ||
435 | reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
436 | reg |= AUX_FUNC_EN_N; | ||
437 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
438 | } | ||
439 | |||
440 | void analogix_dp_init_aux(struct analogix_dp_device *dp) | ||
441 | { | ||
442 | u32 reg; | ||
443 | |||
444 | /* Clear inerrupts related to AUX channel */ | ||
445 | reg = RPLY_RECEIV | AUX_ERR; | ||
446 | writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
447 | |||
448 | analogix_dp_reset_aux(dp); | ||
449 | |||
450 | /* Disable AUX transaction H/W retry */ | ||
451 | if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) | ||
452 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) | | ||
453 | AUX_HW_RETRY_COUNT_SEL(3) | | ||
454 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | ||
455 | else | ||
456 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | | ||
457 | AUX_HW_RETRY_COUNT_SEL(0) | | ||
458 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | ||
459 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL); | ||
460 | |||
461 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ | ||
462 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); | ||
463 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_DEFER_CTL); | ||
464 | |||
465 | /* Enable AUX channel module */ | ||
466 | reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
467 | reg &= ~AUX_FUNC_EN_N; | ||
468 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); | ||
469 | } | ||
470 | |||
471 | int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp) | ||
472 | { | ||
473 | u32 reg; | ||
474 | |||
475 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
476 | if (gpio_get_value(dp->hpd_gpio)) | ||
477 | return 0; | ||
478 | } else { | ||
479 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
480 | if (reg & HPD_STATUS) | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | void analogix_dp_enable_sw_function(struct analogix_dp_device *dp) | ||
488 | { | ||
489 | u32 reg; | ||
490 | |||
491 | reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1); | ||
492 | reg &= ~SW_FUNC_EN_N; | ||
493 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1); | ||
494 | } | ||
495 | |||
496 | int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) | ||
497 | { | ||
498 | int reg; | ||
499 | int retval = 0; | ||
500 | int timeout_loop = 0; | ||
501 | |||
502 | /* Enable AUX CH operation */ | ||
503 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
504 | reg |= AUX_EN; | ||
505 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
506 | |||
507 | /* Is AUX CH command reply received? */ | ||
508 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); | ||
509 | while (!(reg & RPLY_RECEIV)) { | ||
510 | timeout_loop++; | ||
511 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
512 | dev_err(dp->dev, "AUX CH command reply failed!\n"); | ||
513 | return -ETIMEDOUT; | ||
514 | } | ||
515 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); | ||
516 | usleep_range(10, 11); | ||
517 | } | ||
518 | |||
519 | /* Clear interrupt source for AUX CH command reply */ | ||
520 | writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
521 | |||
522 | /* Clear interrupt source for AUX CH access error */ | ||
523 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); | ||
524 | if (reg & AUX_ERR) { | ||
525 | writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
526 | return -EREMOTEIO; | ||
527 | } | ||
528 | |||
529 | /* Check AUX CH error access status */ | ||
530 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA); | ||
531 | if ((reg & AUX_STATUS_MASK) != 0) { | ||
532 | dev_err(dp->dev, "AUX CH error happens: %d\n\n", | ||
533 | reg & AUX_STATUS_MASK); | ||
534 | return -EREMOTEIO; | ||
535 | } | ||
536 | |||
537 | return retval; | ||
538 | } | ||
539 | |||
540 | int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, | ||
541 | unsigned int reg_addr, | ||
542 | unsigned char data) | ||
543 | { | ||
544 | u32 reg; | ||
545 | int i; | ||
546 | int retval; | ||
547 | |||
548 | for (i = 0; i < 3; i++) { | ||
549 | /* Clear AUX CH data buffer */ | ||
550 | reg = BUF_CLR; | ||
551 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
552 | |||
553 | /* Select DPCD device address */ | ||
554 | reg = AUX_ADDR_7_0(reg_addr); | ||
555 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
556 | reg = AUX_ADDR_15_8(reg_addr); | ||
557 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
558 | reg = AUX_ADDR_19_16(reg_addr); | ||
559 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
560 | |||
561 | /* Write data buffer */ | ||
562 | reg = (unsigned int)data; | ||
563 | writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
564 | |||
565 | /* | ||
566 | * Set DisplayPort transaction and write 1 byte | ||
567 | * If bit 3 is 1, DisplayPort transaction. | ||
568 | * If Bit 3 is 0, I2C transaction. | ||
569 | */ | ||
570 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
571 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
572 | |||
573 | /* Start AUX transaction */ | ||
574 | retval = analogix_dp_start_aux_transaction(dp); | ||
575 | if (retval == 0) | ||
576 | break; | ||
577 | |||
578 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
579 | } | ||
580 | |||
581 | return retval; | ||
582 | } | ||
583 | |||
584 | int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, | ||
585 | unsigned int reg_addr, | ||
586 | unsigned char *data) | ||
587 | { | ||
588 | u32 reg; | ||
589 | int i; | ||
590 | int retval; | ||
591 | |||
592 | for (i = 0; i < 3; i++) { | ||
593 | /* Clear AUX CH data buffer */ | ||
594 | reg = BUF_CLR; | ||
595 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
596 | |||
597 | /* Select DPCD device address */ | ||
598 | reg = AUX_ADDR_7_0(reg_addr); | ||
599 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
600 | reg = AUX_ADDR_15_8(reg_addr); | ||
601 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
602 | reg = AUX_ADDR_19_16(reg_addr); | ||
603 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
604 | |||
605 | /* | ||
606 | * Set DisplayPort transaction and read 1 byte | ||
607 | * If bit 3 is 1, DisplayPort transaction. | ||
608 | * If Bit 3 is 0, I2C transaction. | ||
609 | */ | ||
610 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
611 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
612 | |||
613 | /* Start AUX transaction */ | ||
614 | retval = analogix_dp_start_aux_transaction(dp); | ||
615 | if (retval == 0) | ||
616 | break; | ||
617 | |||
618 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
619 | } | ||
620 | |||
621 | /* Read data buffer */ | ||
622 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
623 | *data = (unsigned char)(reg & 0xff); | ||
624 | |||
625 | return retval; | ||
626 | } | ||
627 | |||
628 | int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, | ||
629 | unsigned int reg_addr, | ||
630 | unsigned int count, | ||
631 | unsigned char data[]) | ||
632 | { | ||
633 | u32 reg; | ||
634 | unsigned int start_offset; | ||
635 | unsigned int cur_data_count; | ||
636 | unsigned int cur_data_idx; | ||
637 | int i; | ||
638 | int retval = 0; | ||
639 | |||
640 | /* Clear AUX CH data buffer */ | ||
641 | reg = BUF_CLR; | ||
642 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
643 | |||
644 | start_offset = 0; | ||
645 | while (start_offset < count) { | ||
646 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
647 | if ((count - start_offset) > 16) | ||
648 | cur_data_count = 16; | ||
649 | else | ||
650 | cur_data_count = count - start_offset; | ||
651 | |||
652 | for (i = 0; i < 3; i++) { | ||
653 | /* Select DPCD device address */ | ||
654 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
655 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
656 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
657 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
658 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
659 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
660 | |||
661 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
662 | cur_data_idx++) { | ||
663 | reg = data[start_offset + cur_data_idx]; | ||
664 | writel(reg, dp->reg_base + | ||
665 | ANALOGIX_DP_BUF_DATA_0 + | ||
666 | 4 * cur_data_idx); | ||
667 | } | ||
668 | |||
669 | /* | ||
670 | * Set DisplayPort transaction and write | ||
671 | * If bit 3 is 1, DisplayPort transaction. | ||
672 | * If Bit 3 is 0, I2C transaction. | ||
673 | */ | ||
674 | reg = AUX_LENGTH(cur_data_count) | | ||
675 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
676 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
677 | |||
678 | /* Start AUX transaction */ | ||
679 | retval = analogix_dp_start_aux_transaction(dp); | ||
680 | if (retval == 0) | ||
681 | break; | ||
682 | |||
683 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
684 | __func__); | ||
685 | } | ||
686 | |||
687 | start_offset += cur_data_count; | ||
688 | } | ||
689 | |||
690 | return retval; | ||
691 | } | ||
692 | |||
693 | int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, | ||
694 | unsigned int reg_addr, | ||
695 | unsigned int count, | ||
696 | unsigned char data[]) | ||
697 | { | ||
698 | u32 reg; | ||
699 | unsigned int start_offset; | ||
700 | unsigned int cur_data_count; | ||
701 | unsigned int cur_data_idx; | ||
702 | int i; | ||
703 | int retval = 0; | ||
704 | |||
705 | /* Clear AUX CH data buffer */ | ||
706 | reg = BUF_CLR; | ||
707 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
708 | |||
709 | start_offset = 0; | ||
710 | while (start_offset < count) { | ||
711 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
712 | if ((count - start_offset) > 16) | ||
713 | cur_data_count = 16; | ||
714 | else | ||
715 | cur_data_count = count - start_offset; | ||
716 | |||
717 | /* AUX CH Request Transaction process */ | ||
718 | for (i = 0; i < 3; i++) { | ||
719 | /* Select DPCD device address */ | ||
720 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
721 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
722 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
723 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
724 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
725 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
726 | |||
727 | /* | ||
728 | * Set DisplayPort transaction and read | ||
729 | * If bit 3 is 1, DisplayPort transaction. | ||
730 | * If Bit 3 is 0, I2C transaction. | ||
731 | */ | ||
732 | reg = AUX_LENGTH(cur_data_count) | | ||
733 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
734 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
735 | |||
736 | /* Start AUX transaction */ | ||
737 | retval = analogix_dp_start_aux_transaction(dp); | ||
738 | if (retval == 0) | ||
739 | break; | ||
740 | |||
741 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
742 | __func__); | ||
743 | } | ||
744 | |||
745 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
746 | cur_data_idx++) { | ||
747 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 | ||
748 | + 4 * cur_data_idx); | ||
749 | data[start_offset + cur_data_idx] = | ||
750 | (unsigned char)reg; | ||
751 | } | ||
752 | |||
753 | start_offset += cur_data_count; | ||
754 | } | ||
755 | |||
756 | return retval; | ||
757 | } | ||
758 | |||
759 | int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, | ||
760 | unsigned int device_addr, | ||
761 | unsigned int reg_addr) | ||
762 | { | ||
763 | u32 reg; | ||
764 | int retval; | ||
765 | |||
766 | /* Set EDID device address */ | ||
767 | reg = device_addr; | ||
768 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
769 | writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
770 | writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
771 | |||
772 | /* Set offset from base address of EDID device */ | ||
773 | writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
774 | |||
775 | /* | ||
776 | * Set I2C transaction and write address | ||
777 | * If bit 3 is 1, DisplayPort transaction. | ||
778 | * If Bit 3 is 0, I2C transaction. | ||
779 | */ | ||
780 | reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | | ||
781 | AUX_TX_COMM_WRITE; | ||
782 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
783 | |||
784 | /* Start AUX transaction */ | ||
785 | retval = analogix_dp_start_aux_transaction(dp); | ||
786 | if (retval != 0) | ||
787 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
788 | |||
789 | return retval; | ||
790 | } | ||
791 | |||
792 | int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, | ||
793 | unsigned int device_addr, | ||
794 | unsigned int reg_addr, | ||
795 | unsigned int *data) | ||
796 | { | ||
797 | u32 reg; | ||
798 | int i; | ||
799 | int retval; | ||
800 | |||
801 | for (i = 0; i < 3; i++) { | ||
802 | /* Clear AUX CH data buffer */ | ||
803 | reg = BUF_CLR; | ||
804 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
805 | |||
806 | /* Select EDID device */ | ||
807 | retval = analogix_dp_select_i2c_device(dp, device_addr, | ||
808 | reg_addr); | ||
809 | if (retval != 0) | ||
810 | continue; | ||
811 | |||
812 | /* | ||
813 | * Set I2C transaction and read data | ||
814 | * If bit 3 is 1, DisplayPort transaction. | ||
815 | * If Bit 3 is 0, I2C transaction. | ||
816 | */ | ||
817 | reg = AUX_TX_COMM_I2C_TRANSACTION | | ||
818 | AUX_TX_COMM_READ; | ||
819 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
820 | |||
821 | /* Start AUX transaction */ | ||
822 | retval = analogix_dp_start_aux_transaction(dp); | ||
823 | if (retval == 0) | ||
824 | break; | ||
825 | |||
826 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
827 | } | ||
828 | |||
829 | /* Read data */ | ||
830 | if (retval == 0) | ||
831 | *data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
832 | |||
833 | return retval; | ||
834 | } | ||
835 | |||
836 | int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, | ||
837 | unsigned int device_addr, | ||
838 | unsigned int reg_addr, | ||
839 | unsigned int count, | ||
840 | unsigned char edid[]) | ||
841 | { | ||
842 | u32 reg; | ||
843 | unsigned int i, j; | ||
844 | unsigned int cur_data_idx; | ||
845 | unsigned int defer = 0; | ||
846 | int retval = 0; | ||
847 | |||
848 | for (i = 0; i < count; i += 16) { | ||
849 | for (j = 0; j < 3; j++) { | ||
850 | /* Clear AUX CH data buffer */ | ||
851 | reg = BUF_CLR; | ||
852 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
853 | |||
854 | /* Set normal AUX CH command */ | ||
855 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
856 | reg &= ~ADDR_ONLY; | ||
857 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
858 | |||
859 | /* | ||
860 | * If Rx sends defer, Tx sends only reads | ||
861 | * request without sending address | ||
862 | */ | ||
863 | if (!defer) | ||
864 | retval = analogix_dp_select_i2c_device(dp, | ||
865 | device_addr, reg_addr + i); | ||
866 | else | ||
867 | defer = 0; | ||
868 | |||
869 | if (retval == 0) { | ||
870 | /* | ||
871 | * Set I2C transaction and write data | ||
872 | * If bit 3 is 1, DisplayPort transaction. | ||
873 | * If Bit 3 is 0, I2C transaction. | ||
874 | */ | ||
875 | reg = AUX_LENGTH(16) | | ||
876 | AUX_TX_COMM_I2C_TRANSACTION | | ||
877 | AUX_TX_COMM_READ; | ||
878 | writel(reg, dp->reg_base + | ||
879 | ANALOGIX_DP_AUX_CH_CTL_1); | ||
880 | |||
881 | /* Start AUX transaction */ | ||
882 | retval = analogix_dp_start_aux_transaction(dp); | ||
883 | if (retval == 0) | ||
884 | break; | ||
885 | |||
886 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
887 | __func__); | ||
888 | } | ||
889 | /* Check if Rx sends defer */ | ||
890 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); | ||
891 | if (reg == AUX_RX_COMM_AUX_DEFER || | ||
892 | reg == AUX_RX_COMM_I2C_DEFER) { | ||
893 | dev_err(dp->dev, "Defer: %d\n\n", reg); | ||
894 | defer = 1; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { | ||
899 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 | ||
900 | + 4 * cur_data_idx); | ||
901 | edid[i + cur_data_idx] = (unsigned char)reg; | ||
902 | } | ||
903 | } | ||
904 | |||
905 | return retval; | ||
906 | } | ||
907 | |||
908 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) | ||
909 | { | ||
910 | u32 reg; | ||
911 | |||
912 | reg = bwtype; | ||
913 | if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62)) | ||
914 | writel(reg, dp->reg_base + ANALOGIX_DP_LINK_BW_SET); | ||
915 | } | ||
916 | |||
917 | void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype) | ||
918 | { | ||
919 | u32 reg; | ||
920 | |||
921 | reg = readl(dp->reg_base + ANALOGIX_DP_LINK_BW_SET); | ||
922 | *bwtype = reg; | ||
923 | } | ||
924 | |||
925 | void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count) | ||
926 | { | ||
927 | u32 reg; | ||
928 | |||
929 | reg = count; | ||
930 | writel(reg, dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET); | ||
931 | } | ||
932 | |||
933 | void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count) | ||
934 | { | ||
935 | u32 reg; | ||
936 | |||
937 | reg = readl(dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET); | ||
938 | *count = reg; | ||
939 | } | ||
940 | |||
941 | void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp, | ||
942 | bool enable) | ||
943 | { | ||
944 | u32 reg; | ||
945 | |||
946 | if (enable) { | ||
947 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
948 | reg |= ENHANCED; | ||
949 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
950 | } else { | ||
951 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
952 | reg &= ~ENHANCED; | ||
953 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
954 | } | ||
955 | } | ||
956 | |||
957 | void analogix_dp_set_training_pattern(struct analogix_dp_device *dp, | ||
958 | enum pattern_set pattern) | ||
959 | { | ||
960 | u32 reg; | ||
961 | |||
962 | switch (pattern) { | ||
963 | case PRBS7: | ||
964 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; | ||
965 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
966 | break; | ||
967 | case D10_2: | ||
968 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; | ||
969 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
970 | break; | ||
971 | case TRAINING_PTN1: | ||
972 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; | ||
973 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
974 | break; | ||
975 | case TRAINING_PTN2: | ||
976 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; | ||
977 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
978 | break; | ||
979 | case DP_NONE: | ||
980 | reg = SCRAMBLING_ENABLE | | ||
981 | LINK_QUAL_PATTERN_SET_DISABLE | | ||
982 | SW_TRAINING_PATTERN_SET_NORMAL; | ||
983 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
984 | break; | ||
985 | default: | ||
986 | break; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp, | ||
991 | u32 level) | ||
992 | { | ||
993 | u32 reg; | ||
994 | |||
995 | reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); | ||
996 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
997 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
998 | writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); | ||
999 | } | ||
1000 | |||
1001 | void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp, | ||
1002 | u32 level) | ||
1003 | { | ||
1004 | u32 reg; | ||
1005 | |||
1006 | reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); | ||
1007 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
1008 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
1009 | writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); | ||
1010 | } | ||
1011 | |||
1012 | void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp, | ||
1013 | u32 level) | ||
1014 | { | ||
1015 | u32 reg; | ||
1016 | |||
1017 | reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); | ||
1018 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
1019 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
1020 | writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); | ||
1021 | } | ||
1022 | |||
1023 | void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp, | ||
1024 | u32 level) | ||
1025 | { | ||
1026 | u32 reg; | ||
1027 | |||
1028 | reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); | ||
1029 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
1030 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
1031 | writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); | ||
1032 | } | ||
1033 | |||
1034 | void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp, | ||
1035 | u32 training_lane) | ||
1036 | { | ||
1037 | u32 reg; | ||
1038 | |||
1039 | reg = training_lane; | ||
1040 | writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); | ||
1041 | } | ||
1042 | |||
1043 | void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp, | ||
1044 | u32 training_lane) | ||
1045 | { | ||
1046 | u32 reg; | ||
1047 | |||
1048 | reg = training_lane; | ||
1049 | writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); | ||
1050 | } | ||
1051 | |||
1052 | void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp, | ||
1053 | u32 training_lane) | ||
1054 | { | ||
1055 | u32 reg; | ||
1056 | |||
1057 | reg = training_lane; | ||
1058 | writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); | ||
1059 | } | ||
1060 | |||
1061 | void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, | ||
1062 | u32 training_lane) | ||
1063 | { | ||
1064 | u32 reg; | ||
1065 | |||
1066 | reg = training_lane; | ||
1067 | writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); | ||
1068 | } | ||
1069 | |||
1070 | u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp) | ||
1071 | { | ||
1072 | u32 reg; | ||
1073 | |||
1074 | reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); | ||
1075 | return reg; | ||
1076 | } | ||
1077 | |||
1078 | u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp) | ||
1079 | { | ||
1080 | u32 reg; | ||
1081 | |||
1082 | reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); | ||
1083 | return reg; | ||
1084 | } | ||
1085 | |||
1086 | u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp) | ||
1087 | { | ||
1088 | u32 reg; | ||
1089 | |||
1090 | reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); | ||
1091 | return reg; | ||
1092 | } | ||
1093 | |||
1094 | u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp) | ||
1095 | { | ||
1096 | u32 reg; | ||
1097 | |||
1098 | reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); | ||
1099 | return reg; | ||
1100 | } | ||
1101 | |||
1102 | void analogix_dp_reset_macro(struct analogix_dp_device *dp) | ||
1103 | { | ||
1104 | u32 reg; | ||
1105 | |||
1106 | reg = readl(dp->reg_base + ANALOGIX_DP_PHY_TEST); | ||
1107 | reg |= MACRO_RST; | ||
1108 | writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST); | ||
1109 | |||
1110 | /* 10 us is the minimum reset time. */ | ||
1111 | usleep_range(10, 20); | ||
1112 | |||
1113 | reg &= ~MACRO_RST; | ||
1114 | writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST); | ||
1115 | } | ||
1116 | |||
1117 | void analogix_dp_init_video(struct analogix_dp_device *dp) | ||
1118 | { | ||
1119 | u32 reg; | ||
1120 | |||
1121 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; | ||
1122 | writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); | ||
1123 | |||
1124 | reg = 0x0; | ||
1125 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1); | ||
1126 | |||
1127 | reg = CHA_CRI(4) | CHA_CTRL; | ||
1128 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2); | ||
1129 | |||
1130 | reg = 0x0; | ||
1131 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
1132 | |||
1133 | reg = VID_HRES_TH(2) | VID_VRES_TH(0); | ||
1134 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_8); | ||
1135 | } | ||
1136 | |||
1137 | void analogix_dp_set_video_color_format(struct analogix_dp_device *dp) | ||
1138 | { | ||
1139 | u32 reg; | ||
1140 | |||
1141 | /* Configure the input color depth, color space, dynamic range */ | ||
1142 | reg = (dp->video_info.dynamic_range << IN_D_RANGE_SHIFT) | | ||
1143 | (dp->video_info.color_depth << IN_BPC_SHIFT) | | ||
1144 | (dp->video_info.color_space << IN_COLOR_F_SHIFT); | ||
1145 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_2); | ||
1146 | |||
1147 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | ||
1148 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); | ||
1149 | reg &= ~IN_YC_COEFFI_MASK; | ||
1150 | if (dp->video_info.ycbcr_coeff) | ||
1151 | reg |= IN_YC_COEFFI_ITU709; | ||
1152 | else | ||
1153 | reg |= IN_YC_COEFFI_ITU601; | ||
1154 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); | ||
1155 | } | ||
1156 | |||
1157 | int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp) | ||
1158 | { | ||
1159 | u32 reg; | ||
1160 | |||
1161 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1); | ||
1162 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1); | ||
1163 | |||
1164 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1); | ||
1165 | |||
1166 | if (!(reg & DET_STA)) { | ||
1167 | dev_dbg(dp->dev, "Input stream clock not detected.\n"); | ||
1168 | return -EINVAL; | ||
1169 | } | ||
1170 | |||
1171 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2); | ||
1172 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2); | ||
1173 | |||
1174 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2); | ||
1175 | dev_dbg(dp->dev, "wait SYS_CTL_2.\n"); | ||
1176 | |||
1177 | if (reg & CHA_STA) { | ||
1178 | dev_dbg(dp->dev, "Input stream clk is changing\n"); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp, | ||
1186 | enum clock_recovery_m_value_type type, | ||
1187 | u32 m_value, u32 n_value) | ||
1188 | { | ||
1189 | u32 reg; | ||
1190 | |||
1191 | if (type == REGISTER_M) { | ||
1192 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
1193 | reg |= FIX_M_VID; | ||
1194 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
1195 | reg = m_value & 0xff; | ||
1196 | writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_0); | ||
1197 | reg = (m_value >> 8) & 0xff; | ||
1198 | writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_1); | ||
1199 | reg = (m_value >> 16) & 0xff; | ||
1200 | writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_2); | ||
1201 | |||
1202 | reg = n_value & 0xff; | ||
1203 | writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_0); | ||
1204 | reg = (n_value >> 8) & 0xff; | ||
1205 | writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_1); | ||
1206 | reg = (n_value >> 16) & 0xff; | ||
1207 | writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_2); | ||
1208 | } else { | ||
1209 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
1210 | reg &= ~FIX_M_VID; | ||
1211 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); | ||
1212 | |||
1213 | writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_0); | ||
1214 | writel(0x80, dp->reg_base + ANALOGIX_DP_N_VID_1); | ||
1215 | writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_2); | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type) | ||
1220 | { | ||
1221 | u32 reg; | ||
1222 | |||
1223 | if (type == VIDEO_TIMING_FROM_CAPTURE) { | ||
1224 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1225 | reg &= ~FORMAT_SEL; | ||
1226 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1227 | } else { | ||
1228 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1229 | reg |= FORMAT_SEL; | ||
1230 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1231 | } | ||
1232 | } | ||
1233 | |||
1234 | void analogix_dp_enable_video_master(struct analogix_dp_device *dp, bool enable) | ||
1235 | { | ||
1236 | u32 reg; | ||
1237 | |||
1238 | if (enable) { | ||
1239 | reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); | ||
1240 | reg &= ~VIDEO_MODE_MASK; | ||
1241 | reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; | ||
1242 | writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); | ||
1243 | } else { | ||
1244 | reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); | ||
1245 | reg &= ~VIDEO_MODE_MASK; | ||
1246 | reg |= VIDEO_MODE_SLAVE_MODE; | ||
1247 | writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | void analogix_dp_start_video(struct analogix_dp_device *dp) | ||
1252 | { | ||
1253 | u32 reg; | ||
1254 | |||
1255 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
1256 | reg |= VIDEO_EN; | ||
1257 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); | ||
1258 | } | ||
1259 | |||
1260 | int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp) | ||
1261 | { | ||
1262 | u32 reg; | ||
1263 | |||
1264 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
1265 | writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
1266 | |||
1267 | reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); | ||
1268 | if (!(reg & STRM_VALID)) { | ||
1269 | dev_dbg(dp->dev, "Input video stream is not detected.\n"); | ||
1270 | return -EINVAL; | ||
1271 | } | ||
1272 | |||
1273 | return 0; | ||
1274 | } | ||
1275 | |||
1276 | void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp) | ||
1277 | { | ||
1278 | u32 reg; | ||
1279 | |||
1280 | reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1); | ||
1281 | reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N); | ||
1282 | reg |= MASTER_VID_FUNC_EN_N; | ||
1283 | writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1); | ||
1284 | |||
1285 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1286 | reg &= ~INTERACE_SCAN_CFG; | ||
1287 | reg |= (dp->video_info.interlaced << 2); | ||
1288 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1289 | |||
1290 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1291 | reg &= ~VSYNC_POLARITY_CFG; | ||
1292 | reg |= (dp->video_info.v_sync_polarity << 1); | ||
1293 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1294 | |||
1295 | reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1296 | reg &= ~HSYNC_POLARITY_CFG; | ||
1297 | reg |= (dp->video_info.h_sync_polarity << 0); | ||
1298 | writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); | ||
1299 | |||
1300 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; | ||
1301 | writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); | ||
1302 | } | ||
1303 | |||
1304 | void analogix_dp_enable_scrambling(struct analogix_dp_device *dp) | ||
1305 | { | ||
1306 | u32 reg; | ||
1307 | |||
1308 | reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
1309 | reg &= ~SCRAMBLING_DISABLE; | ||
1310 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
1311 | } | ||
1312 | |||
1313 | void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) | ||
1314 | { | ||
1315 | u32 reg; | ||
1316 | |||
1317 | reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
1318 | reg |= SCRAMBLING_DISABLE; | ||
1319 | writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); | ||
1320 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 2e9bd0e0b9f2..337912b0aeab 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Register definition file for Samsung DP driver | 2 | * Register definition file for Analogix DP core driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | 4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. |
5 | * Author: Jingoo Han <jg1.han@samsung.com> | 5 | * Author: Jingoo Han <jg1.han@samsung.com> |
@@ -9,96 +9,104 @@ | |||
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef _EXYNOS_DP_REG_H | 12 | #ifndef _ANALOGIX_DP_REG_H |
13 | #define _EXYNOS_DP_REG_H | 13 | #define _ANALOGIX_DP_REG_H |
14 | 14 | ||
15 | #define EXYNOS_DP_TX_SW_RESET 0x14 | 15 | #define ANALOGIX_DP_TX_SW_RESET 0x14 |
16 | #define EXYNOS_DP_FUNC_EN_1 0x18 | 16 | #define ANALOGIX_DP_FUNC_EN_1 0x18 |
17 | #define EXYNOS_DP_FUNC_EN_2 0x1C | 17 | #define ANALOGIX_DP_FUNC_EN_2 0x1C |
18 | #define EXYNOS_DP_VIDEO_CTL_1 0x20 | 18 | #define ANALOGIX_DP_VIDEO_CTL_1 0x20 |
19 | #define EXYNOS_DP_VIDEO_CTL_2 0x24 | 19 | #define ANALOGIX_DP_VIDEO_CTL_2 0x24 |
20 | #define EXYNOS_DP_VIDEO_CTL_3 0x28 | 20 | #define ANALOGIX_DP_VIDEO_CTL_3 0x28 |
21 | 21 | ||
22 | #define EXYNOS_DP_VIDEO_CTL_8 0x3C | 22 | #define ANALOGIX_DP_VIDEO_CTL_8 0x3C |
23 | #define EXYNOS_DP_VIDEO_CTL_10 0x44 | 23 | #define ANALOGIX_DP_VIDEO_CTL_10 0x44 |
24 | 24 | ||
25 | #define EXYNOS_DP_LANE_MAP 0x35C | 25 | #define ANALOGIX_DP_PLL_REG_1 0xfc |
26 | 26 | #define ANALOGIX_DP_PLL_REG_2 0x9e4 | |
27 | #define EXYNOS_DP_ANALOG_CTL_1 0x370 | 27 | #define ANALOGIX_DP_PLL_REG_3 0x9e8 |
28 | #define EXYNOS_DP_ANALOG_CTL_2 0x374 | 28 | #define ANALOGIX_DP_PLL_REG_4 0x9ec |
29 | #define EXYNOS_DP_ANALOG_CTL_3 0x378 | 29 | #define ANALOGIX_DP_PLL_REG_5 0xa00 |
30 | #define EXYNOS_DP_PLL_FILTER_CTL_1 0x37C | 30 | |
31 | #define EXYNOS_DP_TX_AMP_TUNING_CTL 0x380 | 31 | #define ANALOGIX_DP_PD 0x12c |
32 | 32 | ||
33 | #define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390 | 33 | #define ANALOGIX_DP_LANE_MAP 0x35C |
34 | 34 | ||
35 | #define EXYNOS_DP_COMMON_INT_STA_1 0x3C4 | 35 | #define ANALOGIX_DP_ANALOG_CTL_1 0x370 |
36 | #define EXYNOS_DP_COMMON_INT_STA_2 0x3C8 | 36 | #define ANALOGIX_DP_ANALOG_CTL_2 0x374 |
37 | #define EXYNOS_DP_COMMON_INT_STA_3 0x3CC | 37 | #define ANALOGIX_DP_ANALOG_CTL_3 0x378 |
38 | #define EXYNOS_DP_COMMON_INT_STA_4 0x3D0 | 38 | #define ANALOGIX_DP_PLL_FILTER_CTL_1 0x37C |
39 | #define EXYNOS_DP_INT_STA 0x3DC | 39 | #define ANALOGIX_DP_TX_AMP_TUNING_CTL 0x380 |
40 | #define EXYNOS_DP_COMMON_INT_MASK_1 0x3E0 | 40 | |
41 | #define EXYNOS_DP_COMMON_INT_MASK_2 0x3E4 | 41 | #define ANALOGIX_DP_AUX_HW_RETRY_CTL 0x390 |
42 | #define EXYNOS_DP_COMMON_INT_MASK_3 0x3E8 | 42 | |
43 | #define EXYNOS_DP_COMMON_INT_MASK_4 0x3EC | 43 | #define ANALOGIX_DP_COMMON_INT_STA_1 0x3C4 |
44 | #define EXYNOS_DP_INT_STA_MASK 0x3F8 | 44 | #define ANALOGIX_DP_COMMON_INT_STA_2 0x3C8 |
45 | #define EXYNOS_DP_INT_CTL 0x3FC | 45 | #define ANALOGIX_DP_COMMON_INT_STA_3 0x3CC |
46 | 46 | #define ANALOGIX_DP_COMMON_INT_STA_4 0x3D0 | |
47 | #define EXYNOS_DP_SYS_CTL_1 0x600 | 47 | #define ANALOGIX_DP_INT_STA 0x3DC |
48 | #define EXYNOS_DP_SYS_CTL_2 0x604 | 48 | #define ANALOGIX_DP_COMMON_INT_MASK_1 0x3E0 |
49 | #define EXYNOS_DP_SYS_CTL_3 0x608 | 49 | #define ANALOGIX_DP_COMMON_INT_MASK_2 0x3E4 |
50 | #define EXYNOS_DP_SYS_CTL_4 0x60C | 50 | #define ANALOGIX_DP_COMMON_INT_MASK_3 0x3E8 |
51 | 51 | #define ANALOGIX_DP_COMMON_INT_MASK_4 0x3EC | |
52 | #define EXYNOS_DP_PKT_SEND_CTL 0x640 | 52 | #define ANALOGIX_DP_INT_STA_MASK 0x3F8 |
53 | #define EXYNOS_DP_HDCP_CTL 0x648 | 53 | #define ANALOGIX_DP_INT_CTL 0x3FC |
54 | 54 | ||
55 | #define EXYNOS_DP_LINK_BW_SET 0x680 | 55 | #define ANALOGIX_DP_SYS_CTL_1 0x600 |
56 | #define EXYNOS_DP_LANE_COUNT_SET 0x684 | 56 | #define ANALOGIX_DP_SYS_CTL_2 0x604 |
57 | #define EXYNOS_DP_TRAINING_PTN_SET 0x688 | 57 | #define ANALOGIX_DP_SYS_CTL_3 0x608 |
58 | #define EXYNOS_DP_LN0_LINK_TRAINING_CTL 0x68C | 58 | #define ANALOGIX_DP_SYS_CTL_4 0x60C |
59 | #define EXYNOS_DP_LN1_LINK_TRAINING_CTL 0x690 | 59 | |
60 | #define EXYNOS_DP_LN2_LINK_TRAINING_CTL 0x694 | 60 | #define ANALOGIX_DP_PKT_SEND_CTL 0x640 |
61 | #define EXYNOS_DP_LN3_LINK_TRAINING_CTL 0x698 | 61 | #define ANALOGIX_DP_HDCP_CTL 0x648 |
62 | 62 | ||
63 | #define EXYNOS_DP_DEBUG_CTL 0x6C0 | 63 | #define ANALOGIX_DP_LINK_BW_SET 0x680 |
64 | #define EXYNOS_DP_HPD_DEGLITCH_L 0x6C4 | 64 | #define ANALOGIX_DP_LANE_COUNT_SET 0x684 |
65 | #define EXYNOS_DP_HPD_DEGLITCH_H 0x6C8 | 65 | #define ANALOGIX_DP_TRAINING_PTN_SET 0x688 |
66 | #define EXYNOS_DP_LINK_DEBUG_CTL 0x6E0 | 66 | #define ANALOGIX_DP_LN0_LINK_TRAINING_CTL 0x68C |
67 | 67 | #define ANALOGIX_DP_LN1_LINK_TRAINING_CTL 0x690 | |
68 | #define EXYNOS_DP_M_VID_0 0x700 | 68 | #define ANALOGIX_DP_LN2_LINK_TRAINING_CTL 0x694 |
69 | #define EXYNOS_DP_M_VID_1 0x704 | 69 | #define ANALOGIX_DP_LN3_LINK_TRAINING_CTL 0x698 |
70 | #define EXYNOS_DP_M_VID_2 0x708 | 70 | |
71 | #define EXYNOS_DP_N_VID_0 0x70C | 71 | #define ANALOGIX_DP_DEBUG_CTL 0x6C0 |
72 | #define EXYNOS_DP_N_VID_1 0x710 | 72 | #define ANALOGIX_DP_HPD_DEGLITCH_L 0x6C4 |
73 | #define EXYNOS_DP_N_VID_2 0x714 | 73 | #define ANALOGIX_DP_HPD_DEGLITCH_H 0x6C8 |
74 | 74 | #define ANALOGIX_DP_LINK_DEBUG_CTL 0x6E0 | |
75 | #define EXYNOS_DP_PLL_CTL 0x71C | 75 | |
76 | #define EXYNOS_DP_PHY_PD 0x720 | 76 | #define ANALOGIX_DP_M_VID_0 0x700 |
77 | #define EXYNOS_DP_PHY_TEST 0x724 | 77 | #define ANALOGIX_DP_M_VID_1 0x704 |
78 | 78 | #define ANALOGIX_DP_M_VID_2 0x708 | |
79 | #define EXYNOS_DP_VIDEO_FIFO_THRD 0x730 | 79 | #define ANALOGIX_DP_N_VID_0 0x70C |
80 | #define EXYNOS_DP_AUDIO_MARGIN 0x73C | 80 | #define ANALOGIX_DP_N_VID_1 0x710 |
81 | 81 | #define ANALOGIX_DP_N_VID_2 0x714 | |
82 | #define EXYNOS_DP_M_VID_GEN_FILTER_TH 0x764 | 82 | |
83 | #define EXYNOS_DP_M_AUD_GEN_FILTER_TH 0x778 | 83 | #define ANALOGIX_DP_PLL_CTL 0x71C |
84 | #define EXYNOS_DP_AUX_CH_STA 0x780 | 84 | #define ANALOGIX_DP_PHY_PD 0x720 |
85 | #define EXYNOS_DP_AUX_CH_DEFER_CTL 0x788 | 85 | #define ANALOGIX_DP_PHY_TEST 0x724 |
86 | #define EXYNOS_DP_AUX_RX_COMM 0x78C | 86 | |
87 | #define EXYNOS_DP_BUFFER_DATA_CTL 0x790 | 87 | #define ANALOGIX_DP_VIDEO_FIFO_THRD 0x730 |
88 | #define EXYNOS_DP_AUX_CH_CTL_1 0x794 | 88 | #define ANALOGIX_DP_AUDIO_MARGIN 0x73C |
89 | #define EXYNOS_DP_AUX_ADDR_7_0 0x798 | 89 | |
90 | #define EXYNOS_DP_AUX_ADDR_15_8 0x79C | 90 | #define ANALOGIX_DP_M_VID_GEN_FILTER_TH 0x764 |
91 | #define EXYNOS_DP_AUX_ADDR_19_16 0x7A0 | 91 | #define ANALOGIX_DP_M_AUD_GEN_FILTER_TH 0x778 |
92 | #define EXYNOS_DP_AUX_CH_CTL_2 0x7A4 | 92 | #define ANALOGIX_DP_AUX_CH_STA 0x780 |
93 | 93 | #define ANALOGIX_DP_AUX_CH_DEFER_CTL 0x788 | |
94 | #define EXYNOS_DP_BUF_DATA_0 0x7C0 | 94 | #define ANALOGIX_DP_AUX_RX_COMM 0x78C |
95 | 95 | #define ANALOGIX_DP_BUFFER_DATA_CTL 0x790 | |
96 | #define EXYNOS_DP_SOC_GENERAL_CTL 0x800 | 96 | #define ANALOGIX_DP_AUX_CH_CTL_1 0x794 |
97 | 97 | #define ANALOGIX_DP_AUX_ADDR_7_0 0x798 | |
98 | /* EXYNOS_DP_TX_SW_RESET */ | 98 | #define ANALOGIX_DP_AUX_ADDR_15_8 0x79C |
99 | #define ANALOGIX_DP_AUX_ADDR_19_16 0x7A0 | ||
100 | #define ANALOGIX_DP_AUX_CH_CTL_2 0x7A4 | ||
101 | |||
102 | #define ANALOGIX_DP_BUF_DATA_0 0x7C0 | ||
103 | |||
104 | #define ANALOGIX_DP_SOC_GENERAL_CTL 0x800 | ||
105 | |||
106 | /* ANALOGIX_DP_TX_SW_RESET */ | ||
99 | #define RESET_DP_TX (0x1 << 0) | 107 | #define RESET_DP_TX (0x1 << 0) |
100 | 108 | ||
101 | /* EXYNOS_DP_FUNC_EN_1 */ | 109 | /* ANALOGIX_DP_FUNC_EN_1 */ |
102 | #define MASTER_VID_FUNC_EN_N (0x1 << 7) | 110 | #define MASTER_VID_FUNC_EN_N (0x1 << 7) |
103 | #define SLAVE_VID_FUNC_EN_N (0x1 << 5) | 111 | #define SLAVE_VID_FUNC_EN_N (0x1 << 5) |
104 | #define AUD_FIFO_FUNC_EN_N (0x1 << 4) | 112 | #define AUD_FIFO_FUNC_EN_N (0x1 << 4) |
@@ -107,17 +115,17 @@ | |||
107 | #define CRC_FUNC_EN_N (0x1 << 1) | 115 | #define CRC_FUNC_EN_N (0x1 << 1) |
108 | #define SW_FUNC_EN_N (0x1 << 0) | 116 | #define SW_FUNC_EN_N (0x1 << 0) |
109 | 117 | ||
110 | /* EXYNOS_DP_FUNC_EN_2 */ | 118 | /* ANALOGIX_DP_FUNC_EN_2 */ |
111 | #define SSC_FUNC_EN_N (0x1 << 7) | 119 | #define SSC_FUNC_EN_N (0x1 << 7) |
112 | #define AUX_FUNC_EN_N (0x1 << 2) | 120 | #define AUX_FUNC_EN_N (0x1 << 2) |
113 | #define SERDES_FIFO_FUNC_EN_N (0x1 << 1) | 121 | #define SERDES_FIFO_FUNC_EN_N (0x1 << 1) |
114 | #define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0) | 122 | #define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0) |
115 | 123 | ||
116 | /* EXYNOS_DP_VIDEO_CTL_1 */ | 124 | /* ANALOGIX_DP_VIDEO_CTL_1 */ |
117 | #define VIDEO_EN (0x1 << 7) | 125 | #define VIDEO_EN (0x1 << 7) |
118 | #define HDCP_VIDEO_MUTE (0x1 << 6) | 126 | #define HDCP_VIDEO_MUTE (0x1 << 6) |
119 | 127 | ||
120 | /* EXYNOS_DP_VIDEO_CTL_1 */ | 128 | /* ANALOGIX_DP_VIDEO_CTL_1 */ |
121 | #define IN_D_RANGE_MASK (0x1 << 7) | 129 | #define IN_D_RANGE_MASK (0x1 << 7) |
122 | #define IN_D_RANGE_SHIFT (7) | 130 | #define IN_D_RANGE_SHIFT (7) |
123 | #define IN_D_RANGE_CEA (0x1 << 7) | 131 | #define IN_D_RANGE_CEA (0x1 << 7) |
@@ -134,7 +142,7 @@ | |||
134 | #define IN_COLOR_F_YCBCR422 (0x1 << 0) | 142 | #define IN_COLOR_F_YCBCR422 (0x1 << 0) |
135 | #define IN_COLOR_F_RGB (0x0 << 0) | 143 | #define IN_COLOR_F_RGB (0x0 << 0) |
136 | 144 | ||
137 | /* EXYNOS_DP_VIDEO_CTL_3 */ | 145 | /* ANALOGIX_DP_VIDEO_CTL_3 */ |
138 | #define IN_YC_COEFFI_MASK (0x1 << 7) | 146 | #define IN_YC_COEFFI_MASK (0x1 << 7) |
139 | #define IN_YC_COEFFI_SHIFT (7) | 147 | #define IN_YC_COEFFI_SHIFT (7) |
140 | #define IN_YC_COEFFI_ITU709 (0x1 << 7) | 148 | #define IN_YC_COEFFI_ITU709 (0x1 << 7) |
@@ -144,17 +152,21 @@ | |||
144 | #define VID_CHK_UPDATE_TYPE_1 (0x1 << 4) | 152 | #define VID_CHK_UPDATE_TYPE_1 (0x1 << 4) |
145 | #define VID_CHK_UPDATE_TYPE_0 (0x0 << 4) | 153 | #define VID_CHK_UPDATE_TYPE_0 (0x0 << 4) |
146 | 154 | ||
147 | /* EXYNOS_DP_VIDEO_CTL_8 */ | 155 | /* ANALOGIX_DP_VIDEO_CTL_8 */ |
148 | #define VID_HRES_TH(x) (((x) & 0xf) << 4) | 156 | #define VID_HRES_TH(x) (((x) & 0xf) << 4) |
149 | #define VID_VRES_TH(x) (((x) & 0xf) << 0) | 157 | #define VID_VRES_TH(x) (((x) & 0xf) << 0) |
150 | 158 | ||
151 | /* EXYNOS_DP_VIDEO_CTL_10 */ | 159 | /* ANALOGIX_DP_VIDEO_CTL_10 */ |
152 | #define FORMAT_SEL (0x1 << 4) | 160 | #define FORMAT_SEL (0x1 << 4) |
153 | #define INTERACE_SCAN_CFG (0x1 << 2) | 161 | #define INTERACE_SCAN_CFG (0x1 << 2) |
154 | #define VSYNC_POLARITY_CFG (0x1 << 1) | 162 | #define VSYNC_POLARITY_CFG (0x1 << 1) |
155 | #define HSYNC_POLARITY_CFG (0x1 << 0) | 163 | #define HSYNC_POLARITY_CFG (0x1 << 0) |
156 | 164 | ||
157 | /* EXYNOS_DP_LANE_MAP */ | 165 | /* ANALOGIX_DP_PLL_REG_1 */ |
166 | #define REF_CLK_24M (0x1 << 1) | ||
167 | #define REF_CLK_27M (0x0 << 1) | ||
168 | |||
169 | /* ANALOGIX_DP_LANE_MAP */ | ||
158 | #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) | 170 | #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) |
159 | #define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6) | 171 | #define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6) |
160 | #define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6) | 172 | #define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6) |
@@ -172,30 +184,30 @@ | |||
172 | #define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) | 184 | #define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) |
173 | #define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) | 185 | #define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) |
174 | 186 | ||
175 | /* EXYNOS_DP_ANALOG_CTL_1 */ | 187 | /* ANALOGIX_DP_ANALOG_CTL_1 */ |
176 | #define TX_TERMINAL_CTRL_50_OHM (0x1 << 4) | 188 | #define TX_TERMINAL_CTRL_50_OHM (0x1 << 4) |
177 | 189 | ||
178 | /* EXYNOS_DP_ANALOG_CTL_2 */ | 190 | /* ANALOGIX_DP_ANALOG_CTL_2 */ |
179 | #define SEL_24M (0x1 << 3) | 191 | #define SEL_24M (0x1 << 3) |
180 | #define TX_DVDD_BIT_1_0625V (0x4 << 0) | 192 | #define TX_DVDD_BIT_1_0625V (0x4 << 0) |
181 | 193 | ||
182 | /* EXYNOS_DP_ANALOG_CTL_3 */ | 194 | /* ANALOGIX_DP_ANALOG_CTL_3 */ |
183 | #define DRIVE_DVDD_BIT_1_0625V (0x4 << 5) | 195 | #define DRIVE_DVDD_BIT_1_0625V (0x4 << 5) |
184 | #define VCO_BIT_600_MICRO (0x5 << 0) | 196 | #define VCO_BIT_600_MICRO (0x5 << 0) |
185 | 197 | ||
186 | /* EXYNOS_DP_PLL_FILTER_CTL_1 */ | 198 | /* ANALOGIX_DP_PLL_FILTER_CTL_1 */ |
187 | #define PD_RING_OSC (0x1 << 6) | 199 | #define PD_RING_OSC (0x1 << 6) |
188 | #define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) | 200 | #define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) |
189 | #define TX_CUR1_2X (0x1 << 2) | 201 | #define TX_CUR1_2X (0x1 << 2) |
190 | #define TX_CUR_16_MA (0x3 << 0) | 202 | #define TX_CUR_16_MA (0x3 << 0) |
191 | 203 | ||
192 | /* EXYNOS_DP_TX_AMP_TUNING_CTL */ | 204 | /* ANALOGIX_DP_TX_AMP_TUNING_CTL */ |
193 | #define CH3_AMP_400_MV (0x0 << 24) | 205 | #define CH3_AMP_400_MV (0x0 << 24) |
194 | #define CH2_AMP_400_MV (0x0 << 16) | 206 | #define CH2_AMP_400_MV (0x0 << 16) |
195 | #define CH1_AMP_400_MV (0x0 << 8) | 207 | #define CH1_AMP_400_MV (0x0 << 8) |
196 | #define CH0_AMP_400_MV (0x0 << 0) | 208 | #define CH0_AMP_400_MV (0x0 << 0) |
197 | 209 | ||
198 | /* EXYNOS_DP_AUX_HW_RETRY_CTL */ | 210 | /* ANALOGIX_DP_AUX_HW_RETRY_CTL */ |
199 | #define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) | 211 | #define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) |
200 | #define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) | 212 | #define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) |
201 | #define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3) | 213 | #define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3) |
@@ -204,7 +216,7 @@ | |||
204 | #define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3) | 216 | #define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3) |
205 | #define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0) | 217 | #define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0) |
206 | 218 | ||
207 | /* EXYNOS_DP_COMMON_INT_STA_1 */ | 219 | /* ANALOGIX_DP_COMMON_INT_STA_1 */ |
208 | #define VSYNC_DET (0x1 << 7) | 220 | #define VSYNC_DET (0x1 << 7) |
209 | #define PLL_LOCK_CHG (0x1 << 6) | 221 | #define PLL_LOCK_CHG (0x1 << 6) |
210 | #define SPDIF_ERR (0x1 << 5) | 222 | #define SPDIF_ERR (0x1 << 5) |
@@ -214,19 +226,19 @@ | |||
214 | #define VID_CLK_CHG (0x1 << 1) | 226 | #define VID_CLK_CHG (0x1 << 1) |
215 | #define SW_INT (0x1 << 0) | 227 | #define SW_INT (0x1 << 0) |
216 | 228 | ||
217 | /* EXYNOS_DP_COMMON_INT_STA_2 */ | 229 | /* ANALOGIX_DP_COMMON_INT_STA_2 */ |
218 | #define ENC_EN_CHG (0x1 << 6) | 230 | #define ENC_EN_CHG (0x1 << 6) |
219 | #define HW_BKSV_RDY (0x1 << 3) | 231 | #define HW_BKSV_RDY (0x1 << 3) |
220 | #define HW_SHA_DONE (0x1 << 2) | 232 | #define HW_SHA_DONE (0x1 << 2) |
221 | #define HW_AUTH_STATE_CHG (0x1 << 1) | 233 | #define HW_AUTH_STATE_CHG (0x1 << 1) |
222 | #define HW_AUTH_DONE (0x1 << 0) | 234 | #define HW_AUTH_DONE (0x1 << 0) |
223 | 235 | ||
224 | /* EXYNOS_DP_COMMON_INT_STA_3 */ | 236 | /* ANALOGIX_DP_COMMON_INT_STA_3 */ |
225 | #define AFIFO_UNDER (0x1 << 7) | 237 | #define AFIFO_UNDER (0x1 << 7) |
226 | #define AFIFO_OVER (0x1 << 6) | 238 | #define AFIFO_OVER (0x1 << 6) |
227 | #define R0_CHK_FLAG (0x1 << 5) | 239 | #define R0_CHK_FLAG (0x1 << 5) |
228 | 240 | ||
229 | /* EXYNOS_DP_COMMON_INT_STA_4 */ | 241 | /* ANALOGIX_DP_COMMON_INT_STA_4 */ |
230 | #define PSR_ACTIVE (0x1 << 7) | 242 | #define PSR_ACTIVE (0x1 << 7) |
231 | #define PSR_INACTIVE (0x1 << 6) | 243 | #define PSR_INACTIVE (0x1 << 6) |
232 | #define SPDIF_BI_PHASE_ERR (0x1 << 5) | 244 | #define SPDIF_BI_PHASE_ERR (0x1 << 5) |
@@ -234,29 +246,29 @@ | |||
234 | #define HPD_LOST (0x1 << 1) | 246 | #define HPD_LOST (0x1 << 1) |
235 | #define PLUG (0x1 << 0) | 247 | #define PLUG (0x1 << 0) |
236 | 248 | ||
237 | /* EXYNOS_DP_INT_STA */ | 249 | /* ANALOGIX_DP_INT_STA */ |
238 | #define INT_HPD (0x1 << 6) | 250 | #define INT_HPD (0x1 << 6) |
239 | #define HW_TRAINING_FINISH (0x1 << 5) | 251 | #define HW_TRAINING_FINISH (0x1 << 5) |
240 | #define RPLY_RECEIV (0x1 << 1) | 252 | #define RPLY_RECEIV (0x1 << 1) |
241 | #define AUX_ERR (0x1 << 0) | 253 | #define AUX_ERR (0x1 << 0) |
242 | 254 | ||
243 | /* EXYNOS_DP_INT_CTL */ | 255 | /* ANALOGIX_DP_INT_CTL */ |
244 | #define SOFT_INT_CTRL (0x1 << 2) | 256 | #define SOFT_INT_CTRL (0x1 << 2) |
245 | #define INT_POL1 (0x1 << 1) | 257 | #define INT_POL1 (0x1 << 1) |
246 | #define INT_POL0 (0x1 << 0) | 258 | #define INT_POL0 (0x1 << 0) |
247 | 259 | ||
248 | /* EXYNOS_DP_SYS_CTL_1 */ | 260 | /* ANALOGIX_DP_SYS_CTL_1 */ |
249 | #define DET_STA (0x1 << 2) | 261 | #define DET_STA (0x1 << 2) |
250 | #define FORCE_DET (0x1 << 1) | 262 | #define FORCE_DET (0x1 << 1) |
251 | #define DET_CTRL (0x1 << 0) | 263 | #define DET_CTRL (0x1 << 0) |
252 | 264 | ||
253 | /* EXYNOS_DP_SYS_CTL_2 */ | 265 | /* ANALOGIX_DP_SYS_CTL_2 */ |
254 | #define CHA_CRI(x) (((x) & 0xf) << 4) | 266 | #define CHA_CRI(x) (((x) & 0xf) << 4) |
255 | #define CHA_STA (0x1 << 2) | 267 | #define CHA_STA (0x1 << 2) |
256 | #define FORCE_CHA (0x1 << 1) | 268 | #define FORCE_CHA (0x1 << 1) |
257 | #define CHA_CTRL (0x1 << 0) | 269 | #define CHA_CTRL (0x1 << 0) |
258 | 270 | ||
259 | /* EXYNOS_DP_SYS_CTL_3 */ | 271 | /* ANALOGIX_DP_SYS_CTL_3 */ |
260 | #define HPD_STATUS (0x1 << 6) | 272 | #define HPD_STATUS (0x1 << 6) |
261 | #define F_HPD (0x1 << 5) | 273 | #define F_HPD (0x1 << 5) |
262 | #define HPD_CTRL (0x1 << 4) | 274 | #define HPD_CTRL (0x1 << 4) |
@@ -265,13 +277,13 @@ | |||
265 | #define F_VALID (0x1 << 1) | 277 | #define F_VALID (0x1 << 1) |
266 | #define VALID_CTRL (0x1 << 0) | 278 | #define VALID_CTRL (0x1 << 0) |
267 | 279 | ||
268 | /* EXYNOS_DP_SYS_CTL_4 */ | 280 | /* ANALOGIX_DP_SYS_CTL_4 */ |
269 | #define FIX_M_AUD (0x1 << 4) | 281 | #define FIX_M_AUD (0x1 << 4) |
270 | #define ENHANCED (0x1 << 3) | 282 | #define ENHANCED (0x1 << 3) |
271 | #define FIX_M_VID (0x1 << 2) | 283 | #define FIX_M_VID (0x1 << 2) |
272 | #define M_VID_UPDATE_CTRL (0x3 << 0) | 284 | #define M_VID_UPDATE_CTRL (0x3 << 0) |
273 | 285 | ||
274 | /* EXYNOS_DP_TRAINING_PTN_SET */ | 286 | /* ANALOGIX_DP_TRAINING_PTN_SET */ |
275 | #define SCRAMBLER_TYPE (0x1 << 9) | 287 | #define SCRAMBLER_TYPE (0x1 << 9) |
276 | #define HW_LINK_TRAINING_PATTERN (0x1 << 8) | 288 | #define HW_LINK_TRAINING_PATTERN (0x1 << 8) |
277 | #define SCRAMBLING_DISABLE (0x1 << 5) | 289 | #define SCRAMBLING_DISABLE (0x1 << 5) |
@@ -285,24 +297,24 @@ | |||
285 | #define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0) | 297 | #define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0) |
286 | #define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) | 298 | #define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) |
287 | 299 | ||
288 | /* EXYNOS_DP_LN0_LINK_TRAINING_CTL */ | 300 | /* ANALOGIX_DP_LN0_LINK_TRAINING_CTL */ |
289 | #define PRE_EMPHASIS_SET_MASK (0x3 << 3) | 301 | #define PRE_EMPHASIS_SET_MASK (0x3 << 3) |
290 | #define PRE_EMPHASIS_SET_SHIFT (3) | 302 | #define PRE_EMPHASIS_SET_SHIFT (3) |
291 | 303 | ||
292 | /* EXYNOS_DP_DEBUG_CTL */ | 304 | /* ANALOGIX_DP_DEBUG_CTL */ |
293 | #define PLL_LOCK (0x1 << 4) | 305 | #define PLL_LOCK (0x1 << 4) |
294 | #define F_PLL_LOCK (0x1 << 3) | 306 | #define F_PLL_LOCK (0x1 << 3) |
295 | #define PLL_LOCK_CTRL (0x1 << 2) | 307 | #define PLL_LOCK_CTRL (0x1 << 2) |
296 | #define PN_INV (0x1 << 0) | 308 | #define PN_INV (0x1 << 0) |
297 | 309 | ||
298 | /* EXYNOS_DP_PLL_CTL */ | 310 | /* ANALOGIX_DP_PLL_CTL */ |
299 | #define DP_PLL_PD (0x1 << 7) | 311 | #define DP_PLL_PD (0x1 << 7) |
300 | #define DP_PLL_RESET (0x1 << 6) | 312 | #define DP_PLL_RESET (0x1 << 6) |
301 | #define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4) | 313 | #define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4) |
302 | #define DP_PLL_REF_BIT_1_1250V (0x5 << 0) | 314 | #define DP_PLL_REF_BIT_1_1250V (0x5 << 0) |
303 | #define DP_PLL_REF_BIT_1_2500V (0x7 << 0) | 315 | #define DP_PLL_REF_BIT_1_2500V (0x7 << 0) |
304 | 316 | ||
305 | /* EXYNOS_DP_PHY_PD */ | 317 | /* ANALOGIX_DP_PHY_PD */ |
306 | #define DP_PHY_PD (0x1 << 5) | 318 | #define DP_PHY_PD (0x1 << 5) |
307 | #define AUX_PD (0x1 << 4) | 319 | #define AUX_PD (0x1 << 4) |
308 | #define CH3_PD (0x1 << 3) | 320 | #define CH3_PD (0x1 << 3) |
@@ -310,28 +322,28 @@ | |||
310 | #define CH1_PD (0x1 << 1) | 322 | #define CH1_PD (0x1 << 1) |
311 | #define CH0_PD (0x1 << 0) | 323 | #define CH0_PD (0x1 << 0) |
312 | 324 | ||
313 | /* EXYNOS_DP_PHY_TEST */ | 325 | /* ANALOGIX_DP_PHY_TEST */ |
314 | #define MACRO_RST (0x1 << 5) | 326 | #define MACRO_RST (0x1 << 5) |
315 | #define CH1_TEST (0x1 << 1) | 327 | #define CH1_TEST (0x1 << 1) |
316 | #define CH0_TEST (0x1 << 0) | 328 | #define CH0_TEST (0x1 << 0) |
317 | 329 | ||
318 | /* EXYNOS_DP_AUX_CH_STA */ | 330 | /* ANALOGIX_DP_AUX_CH_STA */ |
319 | #define AUX_BUSY (0x1 << 4) | 331 | #define AUX_BUSY (0x1 << 4) |
320 | #define AUX_STATUS_MASK (0xf << 0) | 332 | #define AUX_STATUS_MASK (0xf << 0) |
321 | 333 | ||
322 | /* EXYNOS_DP_AUX_CH_DEFER_CTL */ | 334 | /* ANALOGIX_DP_AUX_CH_DEFER_CTL */ |
323 | #define DEFER_CTRL_EN (0x1 << 7) | 335 | #define DEFER_CTRL_EN (0x1 << 7) |
324 | #define DEFER_COUNT(x) (((x) & 0x7f) << 0) | 336 | #define DEFER_COUNT(x) (((x) & 0x7f) << 0) |
325 | 337 | ||
326 | /* EXYNOS_DP_AUX_RX_COMM */ | 338 | /* ANALOGIX_DP_AUX_RX_COMM */ |
327 | #define AUX_RX_COMM_I2C_DEFER (0x2 << 2) | 339 | #define AUX_RX_COMM_I2C_DEFER (0x2 << 2) |
328 | #define AUX_RX_COMM_AUX_DEFER (0x2 << 0) | 340 | #define AUX_RX_COMM_AUX_DEFER (0x2 << 0) |
329 | 341 | ||
330 | /* EXYNOS_DP_BUFFER_DATA_CTL */ | 342 | /* ANALOGIX_DP_BUFFER_DATA_CTL */ |
331 | #define BUF_CLR (0x1 << 7) | 343 | #define BUF_CLR (0x1 << 7) |
332 | #define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0) | 344 | #define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0) |
333 | 345 | ||
334 | /* EXYNOS_DP_AUX_CH_CTL_1 */ | 346 | /* ANALOGIX_DP_AUX_CH_CTL_1 */ |
335 | #define AUX_LENGTH(x) (((x - 1) & 0xf) << 4) | 347 | #define AUX_LENGTH(x) (((x - 1) & 0xf) << 4) |
336 | #define AUX_TX_COMM_MASK (0xf << 0) | 348 | #define AUX_TX_COMM_MASK (0xf << 0) |
337 | #define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3) | 349 | #define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3) |
@@ -340,20 +352,20 @@ | |||
340 | #define AUX_TX_COMM_WRITE (0x0 << 0) | 352 | #define AUX_TX_COMM_WRITE (0x0 << 0) |
341 | #define AUX_TX_COMM_READ (0x1 << 0) | 353 | #define AUX_TX_COMM_READ (0x1 << 0) |
342 | 354 | ||
343 | /* EXYNOS_DP_AUX_ADDR_7_0 */ | 355 | /* ANALOGIX_DP_AUX_ADDR_7_0 */ |
344 | #define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff) | 356 | #define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff) |
345 | 357 | ||
346 | /* EXYNOS_DP_AUX_ADDR_15_8 */ | 358 | /* ANALOGIX_DP_AUX_ADDR_15_8 */ |
347 | #define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff) | 359 | #define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff) |
348 | 360 | ||
349 | /* EXYNOS_DP_AUX_ADDR_19_16 */ | 361 | /* ANALOGIX_DP_AUX_ADDR_19_16 */ |
350 | #define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f) | 362 | #define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f) |
351 | 363 | ||
352 | /* EXYNOS_DP_AUX_CH_CTL_2 */ | 364 | /* ANALOGIX_DP_AUX_CH_CTL_2 */ |
353 | #define ADDR_ONLY (0x1 << 1) | 365 | #define ADDR_ONLY (0x1 << 1) |
354 | #define AUX_EN (0x1 << 0) | 366 | #define AUX_EN (0x1 << 0) |
355 | 367 | ||
356 | /* EXYNOS_DP_SOC_GENERAL_CTL */ | 368 | /* ANALOGIX_DP_SOC_GENERAL_CTL */ |
357 | #define AUDIO_MODE_SPDIF_MODE (0x1 << 8) | 369 | #define AUDIO_MODE_SPDIF_MODE (0x1 << 8) |
358 | #define AUDIO_MODE_MASTER_MODE (0x0 << 8) | 370 | #define AUDIO_MODE_MASTER_MODE (0x0 << 8) |
359 | #define MASTER_VIDEO_INTERLACE_EN (0x1 << 4) | 371 | #define MASTER_VIDEO_INTERLACE_EN (0x1 << 4) |
@@ -363,4 +375,4 @@ | |||
363 | #define VIDEO_MODE_SLAVE_MODE (0x1 << 0) | 375 | #define VIDEO_MODE_SLAVE_MODE (0x1 << 0) |
364 | #define VIDEO_MODE_MASTER_MODE (0x0 << 0) | 376 | #define VIDEO_MODE_MASTER_MODE (0x0 << 0) |
365 | 377 | ||
366 | #endif /* _EXYNOS_DP_REG_H */ | 378 | #endif /* _ANALOGIX_DP_REG_H */ |
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index f17d39279596..2fadd8275fa5 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
@@ -71,8 +71,9 @@ config DRM_EXYNOS_DSI | |||
71 | This enables support for Exynos MIPI-DSI device. | 71 | This enables support for Exynos MIPI-DSI device. |
72 | 72 | ||
73 | config DRM_EXYNOS_DP | 73 | config DRM_EXYNOS_DP |
74 | bool "Display Port" | 74 | bool "EXYNOS specific extensions for Analogix DP driver" |
75 | depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON | 75 | depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON |
76 | select DRM_ANALOGIX_DP | ||
76 | default DRM_EXYNOS | 77 | default DRM_EXYNOS |
77 | select DRM_PANEL | 78 | select DRM_PANEL |
78 | help | 79 | help |
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 968b31c522b2..126b0a1915db 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile | |||
@@ -12,7 +12,7 @@ exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o | |||
12 | exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o | 12 | exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o |
13 | exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o | 13 | exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o |
14 | exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o | 14 | exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o |
15 | exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o | 15 | exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp.o |
16 | exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o | 16 | exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o |
17 | exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o | 17 | exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o |
18 | exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o | 18 | exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o |
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c new file mode 100644 index 000000000000..8ae3d51b5b33 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_dp.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * Samsung SoC DP (Display Port) interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/of_graph.h> | ||
18 | #include <linux/component.h> | ||
19 | #include <video/of_display_timing.h> | ||
20 | #include <video/of_videomode.h> | ||
21 | #include <video/videomode.h> | ||
22 | |||
23 | #include <drm/drmP.h> | ||
24 | #include <drm/drm_crtc.h> | ||
25 | #include <drm/drm_crtc_helper.h> | ||
26 | #include <drm/drm_panel.h> | ||
27 | |||
28 | #include <drm/bridge/analogix_dp.h> | ||
29 | #include <drm/exynos_drm.h> | ||
30 | |||
31 | #include "exynos_drm_crtc.h" | ||
32 | |||
33 | #define to_dp(nm) container_of(nm, struct exynos_dp_device, nm) | ||
34 | |||
35 | struct exynos_dp_device { | ||
36 | struct drm_encoder encoder; | ||
37 | struct drm_connector connector; | ||
38 | struct drm_bridge *ptn_bridge; | ||
39 | struct drm_device *drm_dev; | ||
40 | struct device *dev; | ||
41 | |||
42 | struct videomode vm; | ||
43 | struct analogix_dp_plat_data plat_data; | ||
44 | }; | ||
45 | |||
46 | int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data, | ||
47 | bool enable) | ||
48 | { | ||
49 | struct exynos_dp_device *dp = to_dp(plat_data); | ||
50 | struct drm_encoder *encoder = &dp->encoder; | ||
51 | struct exynos_drm_crtc *crtc; | ||
52 | |||
53 | if (!encoder) | ||
54 | return -1; | ||
55 | |||
56 | crtc = to_exynos_crtc(encoder->crtc); | ||
57 | if (crtc && crtc->ops && crtc->ops->clock_enable) | ||
58 | crtc->ops->clock_enable(crtc, enable); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int exynos_dp_poweron(struct analogix_dp_plat_data *plat_data) | ||
64 | { | ||
65 | return exynos_dp_crtc_clock_enable(plat_data, true); | ||
66 | } | ||
67 | |||
68 | static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data) | ||
69 | { | ||
70 | return exynos_dp_crtc_clock_enable(plat_data, false); | ||
71 | } | ||
72 | |||
73 | static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data) | ||
74 | { | ||
75 | struct exynos_dp_device *dp = to_dp(plat_data); | ||
76 | struct drm_connector *connector = &dp->connector; | ||
77 | struct drm_display_mode *mode; | ||
78 | int num_modes = 0; | ||
79 | |||
80 | if (dp->plat_data.panel) | ||
81 | return num_modes; | ||
82 | |||
83 | mode = drm_mode_create(connector->dev); | ||
84 | if (!mode) { | ||
85 | DRM_ERROR("failed to create a new display mode.\n"); | ||
86 | return num_modes; | ||
87 | } | ||
88 | |||
89 | drm_display_mode_from_videomode(&dp->vm, mode); | ||
90 | connector->display_info.width_mm = mode->width_mm; | ||
91 | connector->display_info.height_mm = mode->height_mm; | ||
92 | |||
93 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
94 | drm_mode_set_name(mode); | ||
95 | drm_mode_probed_add(connector, mode); | ||
96 | |||
97 | return num_modes + 1; | ||
98 | } | ||
99 | |||
100 | static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data, | ||
101 | struct drm_bridge *bridge, | ||
102 | struct drm_connector *connector) | ||
103 | { | ||
104 | struct exynos_dp_device *dp = to_dp(plat_data); | ||
105 | struct drm_encoder *encoder = &dp->encoder; | ||
106 | int ret; | ||
107 | |||
108 | drm_connector_register(connector); | ||
109 | |||
110 | /* Pre-empt DP connector creation if there's a bridge */ | ||
111 | if (dp->ptn_bridge) { | ||
112 | bridge->next = dp->ptn_bridge; | ||
113 | dp->ptn_bridge->encoder = encoder; | ||
114 | ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge); | ||
115 | if (ret) { | ||
116 | DRM_ERROR("Failed to attach bridge to drm\n"); | ||
117 | bridge->next = NULL; | ||
118 | return ret; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static void exynos_dp_mode_set(struct drm_encoder *encoder, | ||
126 | struct drm_display_mode *mode, | ||
127 | struct drm_display_mode *adjusted_mode) | ||
128 | { | ||
129 | } | ||
130 | |||
131 | static void exynos_dp_nop(struct drm_encoder *encoder) | ||
132 | { | ||
133 | /* do nothing */ | ||
134 | } | ||
135 | |||
136 | static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = { | ||
137 | .mode_set = exynos_dp_mode_set, | ||
138 | .enable = exynos_dp_nop, | ||
139 | .disable = exynos_dp_nop, | ||
140 | }; | ||
141 | |||
142 | static const struct drm_encoder_funcs exynos_dp_encoder_funcs = { | ||
143 | .destroy = drm_encoder_cleanup, | ||
144 | }; | ||
145 | |||
146 | static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) | ||
147 | { | ||
148 | int ret; | ||
149 | |||
150 | ret = of_get_videomode(dp->dev->of_node, &dp->vm, OF_USE_NATIVE_MODE); | ||
151 | if (ret) { | ||
152 | DRM_ERROR("failed: of_get_videomode() : %d\n", ret); | ||
153 | return ret; | ||
154 | } | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | ||
159 | { | ||
160 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | ||
161 | struct drm_encoder *encoder = &dp->encoder; | ||
162 | struct drm_device *drm_dev = data; | ||
163 | int pipe, ret; | ||
164 | |||
165 | /* | ||
166 | * Just like the probe function said, we don't need the | ||
167 | * device drvrate anymore, we should leave the charge to | ||
168 | * analogix dp driver, set the device drvdata to NULL. | ||
169 | */ | ||
170 | dev_set_drvdata(dev, NULL); | ||
171 | |||
172 | dp->dev = dev; | ||
173 | dp->drm_dev = drm_dev; | ||
174 | |||
175 | dp->plat_data.dev_type = EXYNOS_DP; | ||
176 | dp->plat_data.power_on = exynos_dp_poweron; | ||
177 | dp->plat_data.power_off = exynos_dp_poweroff; | ||
178 | dp->plat_data.attach = exynos_dp_bridge_attach; | ||
179 | dp->plat_data.get_modes = exynos_dp_get_modes; | ||
180 | |||
181 | if (!dp->plat_data.panel && !dp->ptn_bridge) { | ||
182 | ret = exynos_dp_dt_parse_panel(dp); | ||
183 | if (ret) | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, | ||
188 | EXYNOS_DISPLAY_TYPE_LCD); | ||
189 | if (pipe < 0) | ||
190 | return pipe; | ||
191 | |||
192 | encoder->possible_crtcs = 1 << pipe; | ||
193 | |||
194 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
195 | |||
196 | drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs, | ||
197 | DRM_MODE_ENCODER_TMDS, NULL); | ||
198 | |||
199 | drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs); | ||
200 | |||
201 | dp->plat_data.encoder = encoder; | ||
202 | |||
203 | return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); | ||
204 | } | ||
205 | |||
206 | static void exynos_dp_unbind(struct device *dev, struct device *master, | ||
207 | void *data) | ||
208 | { | ||
209 | return analogix_dp_unbind(dev, master, data); | ||
210 | } | ||
211 | |||
212 | static const struct component_ops exynos_dp_ops = { | ||
213 | .bind = exynos_dp_bind, | ||
214 | .unbind = exynos_dp_unbind, | ||
215 | }; | ||
216 | |||
217 | static int exynos_dp_probe(struct platform_device *pdev) | ||
218 | { | ||
219 | struct device *dev = &pdev->dev; | ||
220 | struct device_node *np = NULL, *endpoint = NULL; | ||
221 | struct exynos_dp_device *dp; | ||
222 | |||
223 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), | ||
224 | GFP_KERNEL); | ||
225 | if (!dp) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | /* | ||
229 | * We just use the drvdata until driver run into component | ||
230 | * add function, and then we would set drvdata to null, so | ||
231 | * that analogix dp driver would take charge of the drvdata. | ||
232 | */ | ||
233 | platform_set_drvdata(pdev, dp); | ||
234 | |||
235 | /* This is for the backward compatibility. */ | ||
236 | np = of_parse_phandle(dev->of_node, "panel", 0); | ||
237 | if (np) { | ||
238 | dp->plat_data.panel = of_drm_find_panel(np); | ||
239 | of_node_put(np); | ||
240 | if (!dp->plat_data.panel) | ||
241 | return -EPROBE_DEFER; | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | ||
246 | if (endpoint) { | ||
247 | np = of_graph_get_remote_port_parent(endpoint); | ||
248 | if (np) { | ||
249 | /* The remote port can be either a panel or a bridge */ | ||
250 | dp->plat_data.panel = of_drm_find_panel(np); | ||
251 | if (!dp->plat_data.panel) { | ||
252 | dp->ptn_bridge = of_drm_find_bridge(np); | ||
253 | if (!dp->ptn_bridge) { | ||
254 | of_node_put(np); | ||
255 | return -EPROBE_DEFER; | ||
256 | } | ||
257 | } | ||
258 | of_node_put(np); | ||
259 | } else { | ||
260 | DRM_ERROR("no remote endpoint device node found.\n"); | ||
261 | return -EINVAL; | ||
262 | } | ||
263 | } else { | ||
264 | DRM_ERROR("no port endpoint subnode found.\n"); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | |||
268 | out: | ||
269 | return component_add(&pdev->dev, &exynos_dp_ops); | ||
270 | } | ||
271 | |||
272 | static int exynos_dp_remove(struct platform_device *pdev) | ||
273 | { | ||
274 | component_del(&pdev->dev, &exynos_dp_ops); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | #ifdef CONFIG_PM | ||
280 | static int exynos_dp_suspend(struct device *dev) | ||
281 | { | ||
282 | return analogix_dp_suspend(dev); | ||
283 | } | ||
284 | |||
285 | static int exynos_dp_resume(struct device *dev) | ||
286 | { | ||
287 | return analogix_dp_resume(dev); | ||
288 | } | ||
289 | #endif | ||
290 | |||
291 | static const struct dev_pm_ops exynos_dp_pm_ops = { | ||
292 | SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) | ||
293 | }; | ||
294 | |||
295 | static const struct of_device_id exynos_dp_match[] = { | ||
296 | { .compatible = "samsung,exynos5-dp" }, | ||
297 | {}, | ||
298 | }; | ||
299 | MODULE_DEVICE_TABLE(of, exynos_dp_match); | ||
300 | |||
301 | struct platform_driver dp_driver = { | ||
302 | .probe = exynos_dp_probe, | ||
303 | .remove = exynos_dp_remove, | ||
304 | .driver = { | ||
305 | .name = "exynos-dp", | ||
306 | .owner = THIS_MODULE, | ||
307 | .pm = &exynos_dp_pm_ops, | ||
308 | .of_match_table = exynos_dp_match, | ||
309 | }, | ||
310 | }; | ||
311 | |||
312 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | ||
313 | MODULE_DESCRIPTION("Samsung Specific Analogix-DP Driver Extension"); | ||
314 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c deleted file mode 100644 index cff8dc788820..000000000000 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ /dev/null | |||
@@ -1,1499 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung SoC DP (Display Port) interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_gpio.h> | ||
21 | #include <linux/of_graph.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/component.h> | ||
24 | #include <linux/phy/phy.h> | ||
25 | #include <video/of_display_timing.h> | ||
26 | #include <video/of_videomode.h> | ||
27 | |||
28 | #include <drm/drmP.h> | ||
29 | #include <drm/drm_crtc.h> | ||
30 | #include <drm/drm_crtc_helper.h> | ||
31 | #include <drm/drm_atomic_helper.h> | ||
32 | #include <drm/drm_panel.h> | ||
33 | |||
34 | #include "exynos_dp_core.h" | ||
35 | #include "exynos_drm_crtc.h" | ||
36 | |||
37 | #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ | ||
38 | connector) | ||
39 | |||
40 | static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) | ||
41 | { | ||
42 | return to_exynos_crtc(dp->encoder.crtc); | ||
43 | } | ||
44 | |||
45 | static inline struct exynos_dp_device *encoder_to_dp( | ||
46 | struct drm_encoder *e) | ||
47 | { | ||
48 | return container_of(e, struct exynos_dp_device, encoder); | ||
49 | } | ||
50 | |||
51 | struct bridge_init { | ||
52 | struct i2c_client *client; | ||
53 | struct device_node *node; | ||
54 | }; | ||
55 | |||
56 | static void exynos_dp_init_dp(struct exynos_dp_device *dp) | ||
57 | { | ||
58 | exynos_dp_reset(dp); | ||
59 | |||
60 | exynos_dp_swreset(dp); | ||
61 | |||
62 | exynos_dp_init_analog_param(dp); | ||
63 | exynos_dp_init_interrupt(dp); | ||
64 | |||
65 | /* SW defined function Normal operation */ | ||
66 | exynos_dp_enable_sw_function(dp); | ||
67 | |||
68 | exynos_dp_config_interrupt(dp); | ||
69 | exynos_dp_init_analog_func(dp); | ||
70 | |||
71 | exynos_dp_init_hpd(dp); | ||
72 | exynos_dp_init_aux(dp); | ||
73 | } | ||
74 | |||
75 | static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) | ||
76 | { | ||
77 | int timeout_loop = 0; | ||
78 | |||
79 | while (exynos_dp_get_plug_in_status(dp) != 0) { | ||
80 | timeout_loop++; | ||
81 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
82 | dev_err(dp->dev, "failed to get hpd plug status\n"); | ||
83 | return -ETIMEDOUT; | ||
84 | } | ||
85 | usleep_range(10, 11); | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) | ||
92 | { | ||
93 | int i; | ||
94 | unsigned char sum = 0; | ||
95 | |||
96 | for (i = 0; i < EDID_BLOCK_LENGTH; i++) | ||
97 | sum = sum + edid_data[i]; | ||
98 | |||
99 | return sum; | ||
100 | } | ||
101 | |||
102 | static int exynos_dp_read_edid(struct exynos_dp_device *dp) | ||
103 | { | ||
104 | unsigned char edid[EDID_BLOCK_LENGTH * 2]; | ||
105 | unsigned int extend_block = 0; | ||
106 | unsigned char sum; | ||
107 | unsigned char test_vector; | ||
108 | int retval; | ||
109 | |||
110 | /* | ||
111 | * EDID device address is 0x50. | ||
112 | * However, if necessary, you must have set upper address | ||
113 | * into E-EDID in I2C device, 0x30. | ||
114 | */ | ||
115 | |||
116 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ | ||
117 | retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | ||
118 | EDID_EXTENSION_FLAG, | ||
119 | &extend_block); | ||
120 | if (retval) | ||
121 | return retval; | ||
122 | |||
123 | if (extend_block > 0) { | ||
124 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); | ||
125 | |||
126 | /* Read EDID data */ | ||
127 | retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | ||
128 | EDID_HEADER_PATTERN, | ||
129 | EDID_BLOCK_LENGTH, | ||
130 | &edid[EDID_HEADER_PATTERN]); | ||
131 | if (retval != 0) { | ||
132 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
133 | return -EIO; | ||
134 | } | ||
135 | sum = exynos_dp_calc_edid_check_sum(edid); | ||
136 | if (sum != 0) { | ||
137 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
138 | return -EIO; | ||
139 | } | ||
140 | |||
141 | /* Read additional EDID data */ | ||
142 | retval = exynos_dp_read_bytes_from_i2c(dp, | ||
143 | I2C_EDID_DEVICE_ADDR, | ||
144 | EDID_BLOCK_LENGTH, | ||
145 | EDID_BLOCK_LENGTH, | ||
146 | &edid[EDID_BLOCK_LENGTH]); | ||
147 | if (retval != 0) { | ||
148 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
149 | return -EIO; | ||
150 | } | ||
151 | sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); | ||
152 | if (sum != 0) { | ||
153 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
154 | return -EIO; | ||
155 | } | ||
156 | |||
157 | exynos_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, | ||
158 | &test_vector); | ||
159 | if (test_vector & DP_TEST_LINK_EDID_READ) { | ||
160 | exynos_dp_write_byte_to_dpcd(dp, | ||
161 | DP_TEST_EDID_CHECKSUM, | ||
162 | edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); | ||
163 | exynos_dp_write_byte_to_dpcd(dp, | ||
164 | DP_TEST_RESPONSE, | ||
165 | DP_TEST_EDID_CHECKSUM_WRITE); | ||
166 | } | ||
167 | } else { | ||
168 | dev_info(dp->dev, "EDID data does not include any extensions.\n"); | ||
169 | |||
170 | /* Read EDID data */ | ||
171 | retval = exynos_dp_read_bytes_from_i2c(dp, | ||
172 | I2C_EDID_DEVICE_ADDR, | ||
173 | EDID_HEADER_PATTERN, | ||
174 | EDID_BLOCK_LENGTH, | ||
175 | &edid[EDID_HEADER_PATTERN]); | ||
176 | if (retval != 0) { | ||
177 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
178 | return -EIO; | ||
179 | } | ||
180 | sum = exynos_dp_calc_edid_check_sum(edid); | ||
181 | if (sum != 0) { | ||
182 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
183 | return -EIO; | ||
184 | } | ||
185 | |||
186 | exynos_dp_read_byte_from_dpcd(dp, | ||
187 | DP_TEST_REQUEST, | ||
188 | &test_vector); | ||
189 | if (test_vector & DP_TEST_LINK_EDID_READ) { | ||
190 | exynos_dp_write_byte_to_dpcd(dp, | ||
191 | DP_TEST_EDID_CHECKSUM, | ||
192 | edid[EDID_CHECKSUM]); | ||
193 | exynos_dp_write_byte_to_dpcd(dp, | ||
194 | DP_TEST_RESPONSE, | ||
195 | DP_TEST_EDID_CHECKSUM_WRITE); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | dev_dbg(dp->dev, "EDID Read success!\n"); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int exynos_dp_handle_edid(struct exynos_dp_device *dp) | ||
204 | { | ||
205 | u8 buf[12]; | ||
206 | int i; | ||
207 | int retval; | ||
208 | |||
209 | /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | ||
210 | retval = exynos_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, | ||
211 | 12, buf); | ||
212 | if (retval) | ||
213 | return retval; | ||
214 | |||
215 | /* Read EDID */ | ||
216 | for (i = 0; i < 3; i++) { | ||
217 | retval = exynos_dp_read_edid(dp); | ||
218 | if (!retval) | ||
219 | break; | ||
220 | } | ||
221 | |||
222 | return retval; | ||
223 | } | ||
224 | |||
225 | static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp, | ||
226 | bool enable) | ||
227 | { | ||
228 | u8 data; | ||
229 | |||
230 | exynos_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); | ||
231 | |||
232 | if (enable) | ||
233 | exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, | ||
234 | DP_LANE_COUNT_ENHANCED_FRAME_EN | | ||
235 | DPCD_LANE_COUNT_SET(data)); | ||
236 | else | ||
237 | exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, | ||
238 | DPCD_LANE_COUNT_SET(data)); | ||
239 | } | ||
240 | |||
241 | static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp) | ||
242 | { | ||
243 | u8 data; | ||
244 | int retval; | ||
245 | |||
246 | exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); | ||
247 | retval = DPCD_ENHANCED_FRAME_CAP(data); | ||
248 | |||
249 | return retval; | ||
250 | } | ||
251 | |||
252 | static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp) | ||
253 | { | ||
254 | u8 data; | ||
255 | |||
256 | data = exynos_dp_is_enhanced_mode_available(dp); | ||
257 | exynos_dp_enable_rx_to_enhanced_mode(dp, data); | ||
258 | exynos_dp_enable_enhanced_mode(dp, data); | ||
259 | } | ||
260 | |||
261 | static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp) | ||
262 | { | ||
263 | exynos_dp_set_training_pattern(dp, DP_NONE); | ||
264 | |||
265 | exynos_dp_write_byte_to_dpcd(dp, | ||
266 | DP_TRAINING_PATTERN_SET, | ||
267 | DP_TRAINING_PATTERN_DISABLE); | ||
268 | } | ||
269 | |||
270 | static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, | ||
271 | int pre_emphasis, int lane) | ||
272 | { | ||
273 | switch (lane) { | ||
274 | case 0: | ||
275 | exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis); | ||
276 | break; | ||
277 | case 1: | ||
278 | exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis); | ||
279 | break; | ||
280 | |||
281 | case 2: | ||
282 | exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis); | ||
283 | break; | ||
284 | |||
285 | case 3: | ||
286 | exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis); | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | static int exynos_dp_link_start(struct exynos_dp_device *dp) | ||
292 | { | ||
293 | u8 buf[4]; | ||
294 | int lane, lane_count, pll_tries, retval; | ||
295 | |||
296 | lane_count = dp->link_train.lane_count; | ||
297 | |||
298 | dp->link_train.lt_state = CLOCK_RECOVERY; | ||
299 | dp->link_train.eq_loop = 0; | ||
300 | |||
301 | for (lane = 0; lane < lane_count; lane++) | ||
302 | dp->link_train.cr_loop[lane] = 0; | ||
303 | |||
304 | /* Set link rate and count as you want to establish*/ | ||
305 | exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); | ||
306 | exynos_dp_set_lane_count(dp, dp->link_train.lane_count); | ||
307 | |||
308 | /* Setup RX configuration */ | ||
309 | buf[0] = dp->link_train.link_rate; | ||
310 | buf[1] = dp->link_train.lane_count; | ||
311 | retval = exynos_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, | ||
312 | 2, buf); | ||
313 | if (retval) | ||
314 | return retval; | ||
315 | |||
316 | /* Set TX pre-emphasis to minimum */ | ||
317 | for (lane = 0; lane < lane_count; lane++) | ||
318 | exynos_dp_set_lane_lane_pre_emphasis(dp, | ||
319 | PRE_EMPHASIS_LEVEL_0, lane); | ||
320 | |||
321 | /* Wait for PLL lock */ | ||
322 | pll_tries = 0; | ||
323 | while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
324 | if (pll_tries == DP_TIMEOUT_LOOP_COUNT) { | ||
325 | dev_err(dp->dev, "Wait for PLL lock timed out\n"); | ||
326 | return -ETIMEDOUT; | ||
327 | } | ||
328 | |||
329 | pll_tries++; | ||
330 | usleep_range(90, 120); | ||
331 | } | ||
332 | |||
333 | /* Set training pattern 1 */ | ||
334 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); | ||
335 | |||
336 | /* Set RX training pattern */ | ||
337 | retval = exynos_dp_write_byte_to_dpcd(dp, | ||
338 | DP_TRAINING_PATTERN_SET, | ||
339 | DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); | ||
340 | if (retval) | ||
341 | return retval; | ||
342 | |||
343 | for (lane = 0; lane < lane_count; lane++) | ||
344 | buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | | ||
345 | DP_TRAIN_VOLTAGE_SWING_LEVEL_0; | ||
346 | |||
347 | retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, | ||
348 | lane_count, buf); | ||
349 | |||
350 | return retval; | ||
351 | } | ||
352 | |||
353 | static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) | ||
354 | { | ||
355 | int shift = (lane & 1) * 4; | ||
356 | u8 link_value = link_status[lane>>1]; | ||
357 | |||
358 | return (link_value >> shift) & 0xf; | ||
359 | } | ||
360 | |||
361 | static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) | ||
362 | { | ||
363 | int lane; | ||
364 | u8 lane_status; | ||
365 | |||
366 | for (lane = 0; lane < lane_count; lane++) { | ||
367 | lane_status = exynos_dp_get_lane_status(link_status, lane); | ||
368 | if ((lane_status & DP_LANE_CR_DONE) == 0) | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, | ||
375 | int lane_count) | ||
376 | { | ||
377 | int lane; | ||
378 | u8 lane_status; | ||
379 | |||
380 | if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) | ||
381 | return -EINVAL; | ||
382 | |||
383 | for (lane = 0; lane < lane_count; lane++) { | ||
384 | lane_status = exynos_dp_get_lane_status(link_status, lane); | ||
385 | lane_status &= DP_CHANNEL_EQ_BITS; | ||
386 | if (lane_status != DP_CHANNEL_EQ_BITS) | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2], | ||
394 | int lane) | ||
395 | { | ||
396 | int shift = (lane & 1) * 4; | ||
397 | u8 link_value = adjust_request[lane>>1]; | ||
398 | |||
399 | return (link_value >> shift) & 0x3; | ||
400 | } | ||
401 | |||
402 | static unsigned char exynos_dp_get_adjust_request_pre_emphasis( | ||
403 | u8 adjust_request[2], | ||
404 | int lane) | ||
405 | { | ||
406 | int shift = (lane & 1) * 4; | ||
407 | u8 link_value = adjust_request[lane>>1]; | ||
408 | |||
409 | return ((link_value >> shift) & 0xc) >> 2; | ||
410 | } | ||
411 | |||
412 | static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp, | ||
413 | u8 training_lane_set, int lane) | ||
414 | { | ||
415 | switch (lane) { | ||
416 | case 0: | ||
417 | exynos_dp_set_lane0_link_training(dp, training_lane_set); | ||
418 | break; | ||
419 | case 1: | ||
420 | exynos_dp_set_lane1_link_training(dp, training_lane_set); | ||
421 | break; | ||
422 | |||
423 | case 2: | ||
424 | exynos_dp_set_lane2_link_training(dp, training_lane_set); | ||
425 | break; | ||
426 | |||
427 | case 3: | ||
428 | exynos_dp_set_lane3_link_training(dp, training_lane_set); | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | static unsigned int exynos_dp_get_lane_link_training( | ||
434 | struct exynos_dp_device *dp, | ||
435 | int lane) | ||
436 | { | ||
437 | u32 reg; | ||
438 | |||
439 | switch (lane) { | ||
440 | case 0: | ||
441 | reg = exynos_dp_get_lane0_link_training(dp); | ||
442 | break; | ||
443 | case 1: | ||
444 | reg = exynos_dp_get_lane1_link_training(dp); | ||
445 | break; | ||
446 | case 2: | ||
447 | reg = exynos_dp_get_lane2_link_training(dp); | ||
448 | break; | ||
449 | case 3: | ||
450 | reg = exynos_dp_get_lane3_link_training(dp); | ||
451 | break; | ||
452 | default: | ||
453 | WARN_ON(1); | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | return reg; | ||
458 | } | ||
459 | |||
460 | static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) | ||
461 | { | ||
462 | exynos_dp_training_pattern_dis(dp); | ||
463 | exynos_dp_set_enhanced_mode(dp); | ||
464 | |||
465 | dp->link_train.lt_state = FAILED; | ||
466 | } | ||
467 | |||
468 | static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, | ||
469 | u8 adjust_request[2]) | ||
470 | { | ||
471 | int lane, lane_count; | ||
472 | u8 voltage_swing, pre_emphasis, training_lane; | ||
473 | |||
474 | lane_count = dp->link_train.lane_count; | ||
475 | for (lane = 0; lane < lane_count; lane++) { | ||
476 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
477 | adjust_request, lane); | ||
478 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
479 | adjust_request, lane); | ||
480 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
481 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
482 | |||
483 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
484 | training_lane |= DP_TRAIN_MAX_SWING_REACHED; | ||
485 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
486 | training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; | ||
487 | |||
488 | dp->link_train.training_lane[lane] = training_lane; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | ||
493 | { | ||
494 | int lane, lane_count, retval; | ||
495 | u8 voltage_swing, pre_emphasis, training_lane; | ||
496 | u8 link_status[2], adjust_request[2]; | ||
497 | |||
498 | usleep_range(100, 101); | ||
499 | |||
500 | lane_count = dp->link_train.lane_count; | ||
501 | |||
502 | retval = exynos_dp_read_bytes_from_dpcd(dp, | ||
503 | DP_LANE0_1_STATUS, 2, link_status); | ||
504 | if (retval) | ||
505 | return retval; | ||
506 | |||
507 | retval = exynos_dp_read_bytes_from_dpcd(dp, | ||
508 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | ||
509 | if (retval) | ||
510 | return retval; | ||
511 | |||
512 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | ||
513 | /* set training pattern 2 for EQ */ | ||
514 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | ||
515 | |||
516 | retval = exynos_dp_write_byte_to_dpcd(dp, | ||
517 | DP_TRAINING_PATTERN_SET, | ||
518 | DP_LINK_SCRAMBLING_DISABLE | | ||
519 | DP_TRAINING_PATTERN_2); | ||
520 | if (retval) | ||
521 | return retval; | ||
522 | |||
523 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); | ||
524 | dp->link_train.lt_state = EQUALIZER_TRAINING; | ||
525 | } else { | ||
526 | for (lane = 0; lane < lane_count; lane++) { | ||
527 | training_lane = exynos_dp_get_lane_link_training( | ||
528 | dp, lane); | ||
529 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
530 | adjust_request, lane); | ||
531 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
532 | adjust_request, lane); | ||
533 | |||
534 | if (DPCD_VOLTAGE_SWING_GET(training_lane) == | ||
535 | voltage_swing && | ||
536 | DPCD_PRE_EMPHASIS_GET(training_lane) == | ||
537 | pre_emphasis) | ||
538 | dp->link_train.cr_loop[lane]++; | ||
539 | |||
540 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || | ||
541 | voltage_swing == VOLTAGE_LEVEL_3 || | ||
542 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { | ||
543 | dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", | ||
544 | dp->link_train.cr_loop[lane], | ||
545 | voltage_swing, pre_emphasis); | ||
546 | exynos_dp_reduce_link_rate(dp); | ||
547 | return -EIO; | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
552 | exynos_dp_get_adjust_training_lane(dp, adjust_request); | ||
553 | |||
554 | for (lane = 0; lane < lane_count; lane++) | ||
555 | exynos_dp_set_lane_link_training(dp, | ||
556 | dp->link_train.training_lane[lane], lane); | ||
557 | |||
558 | retval = exynos_dp_write_bytes_to_dpcd(dp, | ||
559 | DP_TRAINING_LANE0_SET, lane_count, | ||
560 | dp->link_train.training_lane); | ||
561 | if (retval) | ||
562 | return retval; | ||
563 | |||
564 | return retval; | ||
565 | } | ||
566 | |||
567 | static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | ||
568 | { | ||
569 | int lane, lane_count, retval; | ||
570 | u32 reg; | ||
571 | u8 link_align, link_status[2], adjust_request[2]; | ||
572 | |||
573 | usleep_range(400, 401); | ||
574 | |||
575 | lane_count = dp->link_train.lane_count; | ||
576 | |||
577 | retval = exynos_dp_read_bytes_from_dpcd(dp, | ||
578 | DP_LANE0_1_STATUS, 2, link_status); | ||
579 | if (retval) | ||
580 | return retval; | ||
581 | |||
582 | if (exynos_dp_clock_recovery_ok(link_status, lane_count)) { | ||
583 | exynos_dp_reduce_link_rate(dp); | ||
584 | return -EIO; | ||
585 | } | ||
586 | |||
587 | retval = exynos_dp_read_bytes_from_dpcd(dp, | ||
588 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | ||
589 | if (retval) | ||
590 | return retval; | ||
591 | |||
592 | retval = exynos_dp_read_byte_from_dpcd(dp, | ||
593 | DP_LANE_ALIGN_STATUS_UPDATED, &link_align); | ||
594 | if (retval) | ||
595 | return retval; | ||
596 | |||
597 | exynos_dp_get_adjust_training_lane(dp, adjust_request); | ||
598 | |||
599 | if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) { | ||
600 | /* traing pattern Set to Normal */ | ||
601 | exynos_dp_training_pattern_dis(dp); | ||
602 | |||
603 | dev_info(dp->dev, "Link Training success!\n"); | ||
604 | |||
605 | exynos_dp_get_link_bandwidth(dp, ®); | ||
606 | dp->link_train.link_rate = reg; | ||
607 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", | ||
608 | dp->link_train.link_rate); | ||
609 | |||
610 | exynos_dp_get_lane_count(dp, ®); | ||
611 | dp->link_train.lane_count = reg; | ||
612 | dev_dbg(dp->dev, "final lane count = %.2x\n", | ||
613 | dp->link_train.lane_count); | ||
614 | |||
615 | /* set enhanced mode if available */ | ||
616 | exynos_dp_set_enhanced_mode(dp); | ||
617 | dp->link_train.lt_state = FINISHED; | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | /* not all locked */ | ||
623 | dp->link_train.eq_loop++; | ||
624 | |||
625 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { | ||
626 | dev_err(dp->dev, "EQ Max loop\n"); | ||
627 | exynos_dp_reduce_link_rate(dp); | ||
628 | return -EIO; | ||
629 | } | ||
630 | |||
631 | for (lane = 0; lane < lane_count; lane++) | ||
632 | exynos_dp_set_lane_link_training(dp, | ||
633 | dp->link_train.training_lane[lane], lane); | ||
634 | |||
635 | retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, | ||
636 | lane_count, dp->link_train.training_lane); | ||
637 | |||
638 | return retval; | ||
639 | } | ||
640 | |||
641 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | ||
642 | u8 *bandwidth) | ||
643 | { | ||
644 | u8 data; | ||
645 | |||
646 | /* | ||
647 | * For DP rev.1.1, Maximum link rate of Main Link lanes | ||
648 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps | ||
649 | */ | ||
650 | exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); | ||
651 | *bandwidth = data; | ||
652 | } | ||
653 | |||
654 | static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, | ||
655 | u8 *lane_count) | ||
656 | { | ||
657 | u8 data; | ||
658 | |||
659 | /* | ||
660 | * For DP rev.1.1, Maximum number of Main Link lanes | ||
661 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes | ||
662 | */ | ||
663 | exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); | ||
664 | *lane_count = DPCD_MAX_LANE_COUNT(data); | ||
665 | } | ||
666 | |||
667 | static void exynos_dp_init_training(struct exynos_dp_device *dp, | ||
668 | enum link_lane_count_type max_lane, | ||
669 | enum link_rate_type max_rate) | ||
670 | { | ||
671 | /* | ||
672 | * MACRO_RST must be applied after the PLL_LOCK to avoid | ||
673 | * the DP inter pair skew issue for at least 10 us | ||
674 | */ | ||
675 | exynos_dp_reset_macro(dp); | ||
676 | |||
677 | /* Initialize by reading RX's DPCD */ | ||
678 | exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); | ||
679 | exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); | ||
680 | |||
681 | if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && | ||
682 | (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { | ||
683 | dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n", | ||
684 | dp->link_train.link_rate); | ||
685 | dp->link_train.link_rate = LINK_RATE_1_62GBPS; | ||
686 | } | ||
687 | |||
688 | if (dp->link_train.lane_count == 0) { | ||
689 | dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n", | ||
690 | dp->link_train.lane_count); | ||
691 | dp->link_train.lane_count = (u8)LANE_COUNT1; | ||
692 | } | ||
693 | |||
694 | /* Setup TX lane count & rate */ | ||
695 | if (dp->link_train.lane_count > max_lane) | ||
696 | dp->link_train.lane_count = max_lane; | ||
697 | if (dp->link_train.link_rate > max_rate) | ||
698 | dp->link_train.link_rate = max_rate; | ||
699 | |||
700 | /* All DP analog module power up */ | ||
701 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
702 | } | ||
703 | |||
704 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | ||
705 | { | ||
706 | int retval = 0, training_finished = 0; | ||
707 | |||
708 | dp->link_train.lt_state = START; | ||
709 | |||
710 | /* Process here */ | ||
711 | while (!retval && !training_finished) { | ||
712 | switch (dp->link_train.lt_state) { | ||
713 | case START: | ||
714 | retval = exynos_dp_link_start(dp); | ||
715 | if (retval) | ||
716 | dev_err(dp->dev, "LT link start failed!\n"); | ||
717 | break; | ||
718 | case CLOCK_RECOVERY: | ||
719 | retval = exynos_dp_process_clock_recovery(dp); | ||
720 | if (retval) | ||
721 | dev_err(dp->dev, "LT CR failed!\n"); | ||
722 | break; | ||
723 | case EQUALIZER_TRAINING: | ||
724 | retval = exynos_dp_process_equalizer_training(dp); | ||
725 | if (retval) | ||
726 | dev_err(dp->dev, "LT EQ failed!\n"); | ||
727 | break; | ||
728 | case FINISHED: | ||
729 | training_finished = 1; | ||
730 | break; | ||
731 | case FAILED: | ||
732 | return -EREMOTEIO; | ||
733 | } | ||
734 | } | ||
735 | if (retval) | ||
736 | dev_err(dp->dev, "eDP link training failed (%d)\n", retval); | ||
737 | |||
738 | return retval; | ||
739 | } | ||
740 | |||
741 | static int exynos_dp_set_link_train(struct exynos_dp_device *dp, | ||
742 | u32 count, | ||
743 | u32 bwtype) | ||
744 | { | ||
745 | int i; | ||
746 | int retval; | ||
747 | |||
748 | for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) { | ||
749 | exynos_dp_init_training(dp, count, bwtype); | ||
750 | retval = exynos_dp_sw_link_training(dp); | ||
751 | if (retval == 0) | ||
752 | break; | ||
753 | |||
754 | usleep_range(100, 110); | ||
755 | } | ||
756 | |||
757 | return retval; | ||
758 | } | ||
759 | |||
760 | static int exynos_dp_config_video(struct exynos_dp_device *dp) | ||
761 | { | ||
762 | int retval = 0; | ||
763 | int timeout_loop = 0; | ||
764 | int done_count = 0; | ||
765 | |||
766 | exynos_dp_config_video_slave_mode(dp); | ||
767 | |||
768 | exynos_dp_set_video_color_format(dp); | ||
769 | |||
770 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
771 | dev_err(dp->dev, "PLL is not locked yet.\n"); | ||
772 | return -EINVAL; | ||
773 | } | ||
774 | |||
775 | for (;;) { | ||
776 | timeout_loop++; | ||
777 | if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0) | ||
778 | break; | ||
779 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
780 | dev_err(dp->dev, "Timeout of video streamclk ok\n"); | ||
781 | return -ETIMEDOUT; | ||
782 | } | ||
783 | |||
784 | usleep_range(1, 2); | ||
785 | } | ||
786 | |||
787 | /* Set to use the register calculated M/N video */ | ||
788 | exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); | ||
789 | |||
790 | /* For video bist, Video timing must be generated by register */ | ||
791 | exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); | ||
792 | |||
793 | /* Disable video mute */ | ||
794 | exynos_dp_enable_video_mute(dp, 0); | ||
795 | |||
796 | /* Configure video slave mode */ | ||
797 | exynos_dp_enable_video_master(dp, 0); | ||
798 | |||
799 | timeout_loop = 0; | ||
800 | |||
801 | for (;;) { | ||
802 | timeout_loop++; | ||
803 | if (exynos_dp_is_video_stream_on(dp) == 0) { | ||
804 | done_count++; | ||
805 | if (done_count > 10) | ||
806 | break; | ||
807 | } else if (done_count) { | ||
808 | done_count = 0; | ||
809 | } | ||
810 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
811 | dev_err(dp->dev, "Timeout of video streamclk ok\n"); | ||
812 | return -ETIMEDOUT; | ||
813 | } | ||
814 | |||
815 | usleep_range(1000, 1001); | ||
816 | } | ||
817 | |||
818 | if (retval != 0) | ||
819 | dev_err(dp->dev, "Video stream is not detected!\n"); | ||
820 | |||
821 | return retval; | ||
822 | } | ||
823 | |||
824 | static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable) | ||
825 | { | ||
826 | u8 data; | ||
827 | |||
828 | if (enable) { | ||
829 | exynos_dp_enable_scrambling(dp); | ||
830 | |||
831 | exynos_dp_read_byte_from_dpcd(dp, | ||
832 | DP_TRAINING_PATTERN_SET, | ||
833 | &data); | ||
834 | exynos_dp_write_byte_to_dpcd(dp, | ||
835 | DP_TRAINING_PATTERN_SET, | ||
836 | (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); | ||
837 | } else { | ||
838 | exynos_dp_disable_scrambling(dp); | ||
839 | |||
840 | exynos_dp_read_byte_from_dpcd(dp, | ||
841 | DP_TRAINING_PATTERN_SET, | ||
842 | &data); | ||
843 | exynos_dp_write_byte_to_dpcd(dp, | ||
844 | DP_TRAINING_PATTERN_SET, | ||
845 | (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); | ||
846 | } | ||
847 | } | ||
848 | |||
849 | static irqreturn_t exynos_dp_irq_handler(int irq, void *arg) | ||
850 | { | ||
851 | struct exynos_dp_device *dp = arg; | ||
852 | |||
853 | enum dp_irq_type irq_type; | ||
854 | |||
855 | irq_type = exynos_dp_get_irq_type(dp); | ||
856 | switch (irq_type) { | ||
857 | case DP_IRQ_TYPE_HP_CABLE_IN: | ||
858 | dev_dbg(dp->dev, "Received irq - cable in\n"); | ||
859 | schedule_work(&dp->hotplug_work); | ||
860 | exynos_dp_clear_hotplug_interrupts(dp); | ||
861 | break; | ||
862 | case DP_IRQ_TYPE_HP_CABLE_OUT: | ||
863 | dev_dbg(dp->dev, "Received irq - cable out\n"); | ||
864 | exynos_dp_clear_hotplug_interrupts(dp); | ||
865 | break; | ||
866 | case DP_IRQ_TYPE_HP_CHANGE: | ||
867 | /* | ||
868 | * We get these change notifications once in a while, but there | ||
869 | * is nothing we can do with them. Just ignore it for now and | ||
870 | * only handle cable changes. | ||
871 | */ | ||
872 | dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n"); | ||
873 | exynos_dp_clear_hotplug_interrupts(dp); | ||
874 | break; | ||
875 | default: | ||
876 | dev_err(dp->dev, "Received irq - unknown type!\n"); | ||
877 | break; | ||
878 | } | ||
879 | return IRQ_HANDLED; | ||
880 | } | ||
881 | |||
882 | static void exynos_dp_hotplug(struct work_struct *work) | ||
883 | { | ||
884 | struct exynos_dp_device *dp; | ||
885 | |||
886 | dp = container_of(work, struct exynos_dp_device, hotplug_work); | ||
887 | |||
888 | if (dp->drm_dev) | ||
889 | drm_helper_hpd_irq_event(dp->drm_dev); | ||
890 | } | ||
891 | |||
892 | static void exynos_dp_commit(struct drm_encoder *encoder) | ||
893 | { | ||
894 | struct exynos_dp_device *dp = encoder_to_dp(encoder); | ||
895 | int ret; | ||
896 | |||
897 | /* Keep the panel disabled while we configure video */ | ||
898 | if (dp->panel) { | ||
899 | if (drm_panel_disable(dp->panel)) | ||
900 | DRM_ERROR("failed to disable the panel\n"); | ||
901 | } | ||
902 | |||
903 | ret = exynos_dp_detect_hpd(dp); | ||
904 | if (ret) { | ||
905 | /* Cable has been disconnected, we're done */ | ||
906 | return; | ||
907 | } | ||
908 | |||
909 | ret = exynos_dp_handle_edid(dp); | ||
910 | if (ret) { | ||
911 | dev_err(dp->dev, "unable to handle edid\n"); | ||
912 | return; | ||
913 | } | ||
914 | |||
915 | ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
916 | dp->video_info->link_rate); | ||
917 | if (ret) { | ||
918 | dev_err(dp->dev, "unable to do link train\n"); | ||
919 | return; | ||
920 | } | ||
921 | |||
922 | exynos_dp_enable_scramble(dp, 1); | ||
923 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
924 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
925 | |||
926 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
927 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
928 | |||
929 | exynos_dp_init_video(dp); | ||
930 | ret = exynos_dp_config_video(dp); | ||
931 | if (ret) | ||
932 | dev_err(dp->dev, "unable to config video\n"); | ||
933 | |||
934 | /* Safe to enable the panel now */ | ||
935 | if (dp->panel) { | ||
936 | if (drm_panel_enable(dp->panel)) | ||
937 | DRM_ERROR("failed to enable the panel\n"); | ||
938 | } | ||
939 | |||
940 | /* Enable video */ | ||
941 | exynos_dp_start_video(dp); | ||
942 | } | ||
943 | |||
944 | static enum drm_connector_status exynos_dp_detect( | ||
945 | struct drm_connector *connector, bool force) | ||
946 | { | ||
947 | return connector_status_connected; | ||
948 | } | ||
949 | |||
950 | static void exynos_dp_connector_destroy(struct drm_connector *connector) | ||
951 | { | ||
952 | drm_connector_unregister(connector); | ||
953 | drm_connector_cleanup(connector); | ||
954 | } | ||
955 | |||
956 | static const struct drm_connector_funcs exynos_dp_connector_funcs = { | ||
957 | .dpms = drm_atomic_helper_connector_dpms, | ||
958 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
959 | .detect = exynos_dp_detect, | ||
960 | .destroy = exynos_dp_connector_destroy, | ||
961 | .reset = drm_atomic_helper_connector_reset, | ||
962 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
963 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
964 | }; | ||
965 | |||
966 | static int exynos_dp_get_modes(struct drm_connector *connector) | ||
967 | { | ||
968 | struct exynos_dp_device *dp = ctx_from_connector(connector); | ||
969 | struct drm_display_mode *mode; | ||
970 | |||
971 | if (dp->panel) | ||
972 | return drm_panel_get_modes(dp->panel); | ||
973 | |||
974 | mode = drm_mode_create(connector->dev); | ||
975 | if (!mode) { | ||
976 | DRM_ERROR("failed to create a new display mode.\n"); | ||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | drm_display_mode_from_videomode(&dp->vm, mode); | ||
981 | connector->display_info.width_mm = mode->width_mm; | ||
982 | connector->display_info.height_mm = mode->height_mm; | ||
983 | |||
984 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
985 | drm_mode_set_name(mode); | ||
986 | drm_mode_probed_add(connector, mode); | ||
987 | |||
988 | return 1; | ||
989 | } | ||
990 | |||
991 | static struct drm_encoder *exynos_dp_best_encoder( | ||
992 | struct drm_connector *connector) | ||
993 | { | ||
994 | struct exynos_dp_device *dp = ctx_from_connector(connector); | ||
995 | |||
996 | return &dp->encoder; | ||
997 | } | ||
998 | |||
999 | static const struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { | ||
1000 | .get_modes = exynos_dp_get_modes, | ||
1001 | .best_encoder = exynos_dp_best_encoder, | ||
1002 | }; | ||
1003 | |||
1004 | /* returns the number of bridges attached */ | ||
1005 | static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp, | ||
1006 | struct drm_encoder *encoder) | ||
1007 | { | ||
1008 | int ret; | ||
1009 | |||
1010 | encoder->bridge->next = dp->ptn_bridge; | ||
1011 | dp->ptn_bridge->encoder = encoder; | ||
1012 | ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge); | ||
1013 | if (ret) { | ||
1014 | DRM_ERROR("Failed to attach bridge to drm\n"); | ||
1015 | return ret; | ||
1016 | } | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static int exynos_dp_bridge_attach(struct drm_bridge *bridge) | ||
1022 | { | ||
1023 | struct exynos_dp_device *dp = bridge->driver_private; | ||
1024 | struct drm_encoder *encoder = &dp->encoder; | ||
1025 | struct drm_connector *connector = &dp->connector; | ||
1026 | int ret; | ||
1027 | |||
1028 | /* Pre-empt DP connector creation if there's a bridge */ | ||
1029 | if (dp->ptn_bridge) { | ||
1030 | ret = exynos_drm_attach_lcd_bridge(dp, encoder); | ||
1031 | if (!ret) | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
1036 | |||
1037 | ret = drm_connector_init(dp->drm_dev, connector, | ||
1038 | &exynos_dp_connector_funcs, DRM_MODE_CONNECTOR_eDP); | ||
1039 | if (ret) { | ||
1040 | DRM_ERROR("Failed to initialize connector with drm\n"); | ||
1041 | return ret; | ||
1042 | } | ||
1043 | |||
1044 | drm_connector_helper_add(connector, &exynos_dp_connector_helper_funcs); | ||
1045 | drm_connector_register(connector); | ||
1046 | drm_mode_connector_attach_encoder(connector, encoder); | ||
1047 | |||
1048 | if (dp->panel) | ||
1049 | ret = drm_panel_attach(dp->panel, &dp->connector); | ||
1050 | |||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1054 | static void exynos_dp_bridge_enable(struct drm_bridge *bridge) | ||
1055 | { | ||
1056 | struct exynos_dp_device *dp = bridge->driver_private; | ||
1057 | struct exynos_drm_crtc *crtc = dp_to_crtc(dp); | ||
1058 | |||
1059 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) | ||
1060 | return; | ||
1061 | |||
1062 | pm_runtime_get_sync(dp->dev); | ||
1063 | |||
1064 | if (dp->panel) { | ||
1065 | if (drm_panel_prepare(dp->panel)) { | ||
1066 | DRM_ERROR("failed to setup the panel\n"); | ||
1067 | return; | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | if (crtc->ops->clock_enable) | ||
1072 | crtc->ops->clock_enable(dp_to_crtc(dp), true); | ||
1073 | |||
1074 | phy_power_on(dp->phy); | ||
1075 | exynos_dp_init_dp(dp); | ||
1076 | enable_irq(dp->irq); | ||
1077 | exynos_dp_commit(&dp->encoder); | ||
1078 | |||
1079 | dp->dpms_mode = DRM_MODE_DPMS_ON; | ||
1080 | } | ||
1081 | |||
1082 | static void exynos_dp_bridge_disable(struct drm_bridge *bridge) | ||
1083 | { | ||
1084 | struct exynos_dp_device *dp = bridge->driver_private; | ||
1085 | struct exynos_drm_crtc *crtc = dp_to_crtc(dp); | ||
1086 | |||
1087 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) | ||
1088 | return; | ||
1089 | |||
1090 | if (dp->panel) { | ||
1091 | if (drm_panel_disable(dp->panel)) { | ||
1092 | DRM_ERROR("failed to disable the panel\n"); | ||
1093 | return; | ||
1094 | } | ||
1095 | } | ||
1096 | |||
1097 | disable_irq(dp->irq); | ||
1098 | flush_work(&dp->hotplug_work); | ||
1099 | phy_power_off(dp->phy); | ||
1100 | |||
1101 | if (crtc->ops->clock_enable) | ||
1102 | crtc->ops->clock_enable(dp_to_crtc(dp), false); | ||
1103 | |||
1104 | if (dp->panel) { | ||
1105 | if (drm_panel_unprepare(dp->panel)) | ||
1106 | DRM_ERROR("failed to turnoff the panel\n"); | ||
1107 | } | ||
1108 | |||
1109 | pm_runtime_put_sync(dp->dev); | ||
1110 | |||
1111 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | ||
1112 | } | ||
1113 | |||
1114 | static void exynos_dp_bridge_nop(struct drm_bridge *bridge) | ||
1115 | { | ||
1116 | /* do nothing */ | ||
1117 | } | ||
1118 | |||
1119 | static const struct drm_bridge_funcs exynos_dp_bridge_funcs = { | ||
1120 | .enable = exynos_dp_bridge_enable, | ||
1121 | .disable = exynos_dp_bridge_disable, | ||
1122 | .pre_enable = exynos_dp_bridge_nop, | ||
1123 | .post_disable = exynos_dp_bridge_nop, | ||
1124 | .attach = exynos_dp_bridge_attach, | ||
1125 | }; | ||
1126 | |||
1127 | static int exynos_dp_create_connector(struct drm_encoder *encoder) | ||
1128 | { | ||
1129 | struct exynos_dp_device *dp = encoder_to_dp(encoder); | ||
1130 | struct drm_device *drm_dev = dp->drm_dev; | ||
1131 | struct drm_bridge *bridge; | ||
1132 | int ret; | ||
1133 | |||
1134 | bridge = devm_kzalloc(drm_dev->dev, sizeof(*bridge), GFP_KERNEL); | ||
1135 | if (!bridge) { | ||
1136 | DRM_ERROR("failed to allocate for drm bridge\n"); | ||
1137 | return -ENOMEM; | ||
1138 | } | ||
1139 | |||
1140 | dp->bridge = bridge; | ||
1141 | |||
1142 | encoder->bridge = bridge; | ||
1143 | bridge->driver_private = dp; | ||
1144 | bridge->encoder = encoder; | ||
1145 | bridge->funcs = &exynos_dp_bridge_funcs; | ||
1146 | |||
1147 | ret = drm_bridge_attach(drm_dev, bridge); | ||
1148 | if (ret) { | ||
1149 | DRM_ERROR("failed to attach drm bridge\n"); | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | |||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | static void exynos_dp_mode_set(struct drm_encoder *encoder, | ||
1157 | struct drm_display_mode *mode, | ||
1158 | struct drm_display_mode *adjusted_mode) | ||
1159 | { | ||
1160 | } | ||
1161 | |||
1162 | static void exynos_dp_enable(struct drm_encoder *encoder) | ||
1163 | { | ||
1164 | } | ||
1165 | |||
1166 | static void exynos_dp_disable(struct drm_encoder *encoder) | ||
1167 | { | ||
1168 | } | ||
1169 | |||
1170 | static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = { | ||
1171 | .mode_set = exynos_dp_mode_set, | ||
1172 | .enable = exynos_dp_enable, | ||
1173 | .disable = exynos_dp_disable, | ||
1174 | }; | ||
1175 | |||
1176 | static const struct drm_encoder_funcs exynos_dp_encoder_funcs = { | ||
1177 | .destroy = drm_encoder_cleanup, | ||
1178 | }; | ||
1179 | |||
1180 | static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) | ||
1181 | { | ||
1182 | struct device_node *dp_node = dev->of_node; | ||
1183 | struct video_info *dp_video_config; | ||
1184 | |||
1185 | dp_video_config = devm_kzalloc(dev, | ||
1186 | sizeof(*dp_video_config), GFP_KERNEL); | ||
1187 | if (!dp_video_config) | ||
1188 | return ERR_PTR(-ENOMEM); | ||
1189 | |||
1190 | dp_video_config->h_sync_polarity = | ||
1191 | of_property_read_bool(dp_node, "hsync-active-high"); | ||
1192 | |||
1193 | dp_video_config->v_sync_polarity = | ||
1194 | of_property_read_bool(dp_node, "vsync-active-high"); | ||
1195 | |||
1196 | dp_video_config->interlaced = | ||
1197 | of_property_read_bool(dp_node, "interlaced"); | ||
1198 | |||
1199 | if (of_property_read_u32(dp_node, "samsung,color-space", | ||
1200 | &dp_video_config->color_space)) { | ||
1201 | dev_err(dev, "failed to get color-space\n"); | ||
1202 | return ERR_PTR(-EINVAL); | ||
1203 | } | ||
1204 | |||
1205 | if (of_property_read_u32(dp_node, "samsung,dynamic-range", | ||
1206 | &dp_video_config->dynamic_range)) { | ||
1207 | dev_err(dev, "failed to get dynamic-range\n"); | ||
1208 | return ERR_PTR(-EINVAL); | ||
1209 | } | ||
1210 | |||
1211 | if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff", | ||
1212 | &dp_video_config->ycbcr_coeff)) { | ||
1213 | dev_err(dev, "failed to get ycbcr-coeff\n"); | ||
1214 | return ERR_PTR(-EINVAL); | ||
1215 | } | ||
1216 | |||
1217 | if (of_property_read_u32(dp_node, "samsung,color-depth", | ||
1218 | &dp_video_config->color_depth)) { | ||
1219 | dev_err(dev, "failed to get color-depth\n"); | ||
1220 | return ERR_PTR(-EINVAL); | ||
1221 | } | ||
1222 | |||
1223 | if (of_property_read_u32(dp_node, "samsung,link-rate", | ||
1224 | &dp_video_config->link_rate)) { | ||
1225 | dev_err(dev, "failed to get link-rate\n"); | ||
1226 | return ERR_PTR(-EINVAL); | ||
1227 | } | ||
1228 | |||
1229 | if (of_property_read_u32(dp_node, "samsung,lane-count", | ||
1230 | &dp_video_config->lane_count)) { | ||
1231 | dev_err(dev, "failed to get lane-count\n"); | ||
1232 | return ERR_PTR(-EINVAL); | ||
1233 | } | ||
1234 | |||
1235 | return dp_video_config; | ||
1236 | } | ||
1237 | |||
1238 | static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) | ||
1239 | { | ||
1240 | int ret; | ||
1241 | |||
1242 | ret = of_get_videomode(dp->dev->of_node, &dp->vm, OF_USE_NATIVE_MODE); | ||
1243 | if (ret) { | ||
1244 | DRM_ERROR("failed: of_get_videomode() : %d\n", ret); | ||
1245 | return ret; | ||
1246 | } | ||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | ||
1251 | { | ||
1252 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | ||
1253 | struct platform_device *pdev = to_platform_device(dev); | ||
1254 | struct drm_device *drm_dev = data; | ||
1255 | struct drm_encoder *encoder = &dp->encoder; | ||
1256 | struct resource *res; | ||
1257 | unsigned int irq_flags; | ||
1258 | int pipe, ret = 0; | ||
1259 | |||
1260 | dp->dev = &pdev->dev; | ||
1261 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | ||
1262 | |||
1263 | dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev); | ||
1264 | if (IS_ERR(dp->video_info)) | ||
1265 | return PTR_ERR(dp->video_info); | ||
1266 | |||
1267 | dp->phy = devm_phy_get(dp->dev, "dp"); | ||
1268 | if (IS_ERR(dp->phy)) { | ||
1269 | dev_err(dp->dev, "no DP phy configured\n"); | ||
1270 | ret = PTR_ERR(dp->phy); | ||
1271 | if (ret) { | ||
1272 | /* | ||
1273 | * phy itself is not enabled, so we can move forward | ||
1274 | * assigning NULL to phy pointer. | ||
1275 | */ | ||
1276 | if (ret == -ENOSYS || ret == -ENODEV) | ||
1277 | dp->phy = NULL; | ||
1278 | else | ||
1279 | return ret; | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | if (!dp->panel && !dp->ptn_bridge) { | ||
1284 | ret = exynos_dp_dt_parse_panel(dp); | ||
1285 | if (ret) | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | dp->clock = devm_clk_get(&pdev->dev, "dp"); | ||
1290 | if (IS_ERR(dp->clock)) { | ||
1291 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
1292 | return PTR_ERR(dp->clock); | ||
1293 | } | ||
1294 | |||
1295 | clk_prepare_enable(dp->clock); | ||
1296 | |||
1297 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1298 | |||
1299 | dp->reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
1300 | if (IS_ERR(dp->reg_base)) | ||
1301 | return PTR_ERR(dp->reg_base); | ||
1302 | |||
1303 | dp->hpd_gpio = of_get_named_gpio(dev->of_node, "samsung,hpd-gpio", 0); | ||
1304 | |||
1305 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
1306 | /* | ||
1307 | * Set up the hotplug GPIO from the device tree as an interrupt. | ||
1308 | * Simply specifying a different interrupt in the device tree | ||
1309 | * doesn't work since we handle hotplug rather differently when | ||
1310 | * using a GPIO. We also need the actual GPIO specifier so | ||
1311 | * that we can get the current state of the GPIO. | ||
1312 | */ | ||
1313 | ret = devm_gpio_request_one(&pdev->dev, dp->hpd_gpio, GPIOF_IN, | ||
1314 | "hpd_gpio"); | ||
1315 | if (ret) { | ||
1316 | dev_err(&pdev->dev, "failed to get hpd gpio\n"); | ||
1317 | return ret; | ||
1318 | } | ||
1319 | dp->irq = gpio_to_irq(dp->hpd_gpio); | ||
1320 | irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | ||
1321 | } else { | ||
1322 | dp->hpd_gpio = -ENODEV; | ||
1323 | dp->irq = platform_get_irq(pdev, 0); | ||
1324 | irq_flags = 0; | ||
1325 | } | ||
1326 | |||
1327 | if (dp->irq == -ENXIO) { | ||
1328 | dev_err(&pdev->dev, "failed to get irq\n"); | ||
1329 | return -ENODEV; | ||
1330 | } | ||
1331 | |||
1332 | INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); | ||
1333 | |||
1334 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, | ||
1335 | irq_flags, "exynos-dp", dp); | ||
1336 | if (ret) { | ||
1337 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
1338 | return ret; | ||
1339 | } | ||
1340 | disable_irq(dp->irq); | ||
1341 | |||
1342 | dp->drm_dev = drm_dev; | ||
1343 | |||
1344 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, | ||
1345 | EXYNOS_DISPLAY_TYPE_LCD); | ||
1346 | if (pipe < 0) | ||
1347 | return pipe; | ||
1348 | |||
1349 | encoder->possible_crtcs = 1 << pipe; | ||
1350 | |||
1351 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
1352 | |||
1353 | drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs, | ||
1354 | DRM_MODE_ENCODER_TMDS, NULL); | ||
1355 | |||
1356 | drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs); | ||
1357 | |||
1358 | ret = exynos_dp_create_connector(encoder); | ||
1359 | if (ret) { | ||
1360 | DRM_ERROR("failed to create connector ret = %d\n", ret); | ||
1361 | drm_encoder_cleanup(encoder); | ||
1362 | return ret; | ||
1363 | } | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | static void exynos_dp_unbind(struct device *dev, struct device *master, | ||
1369 | void *data) | ||
1370 | { | ||
1371 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | ||
1372 | |||
1373 | exynos_dp_disable(&dp->encoder); | ||
1374 | } | ||
1375 | |||
1376 | static const struct component_ops exynos_dp_ops = { | ||
1377 | .bind = exynos_dp_bind, | ||
1378 | .unbind = exynos_dp_unbind, | ||
1379 | }; | ||
1380 | |||
1381 | static int exynos_dp_probe(struct platform_device *pdev) | ||
1382 | { | ||
1383 | struct device *dev = &pdev->dev; | ||
1384 | struct device_node *np = NULL, *endpoint = NULL; | ||
1385 | struct exynos_dp_device *dp; | ||
1386 | int ret; | ||
1387 | |||
1388 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), | ||
1389 | GFP_KERNEL); | ||
1390 | if (!dp) | ||
1391 | return -ENOMEM; | ||
1392 | |||
1393 | platform_set_drvdata(pdev, dp); | ||
1394 | |||
1395 | /* This is for the backward compatibility. */ | ||
1396 | np = of_parse_phandle(dev->of_node, "panel", 0); | ||
1397 | if (np) { | ||
1398 | dp->panel = of_drm_find_panel(np); | ||
1399 | of_node_put(np); | ||
1400 | if (!dp->panel) | ||
1401 | return -EPROBE_DEFER; | ||
1402 | goto out; | ||
1403 | } | ||
1404 | |||
1405 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | ||
1406 | if (endpoint) { | ||
1407 | np = of_graph_get_remote_port_parent(endpoint); | ||
1408 | if (np) { | ||
1409 | /* The remote port can be either a panel or a bridge */ | ||
1410 | dp->panel = of_drm_find_panel(np); | ||
1411 | if (!dp->panel) { | ||
1412 | dp->ptn_bridge = of_drm_find_bridge(np); | ||
1413 | if (!dp->ptn_bridge) { | ||
1414 | of_node_put(np); | ||
1415 | return -EPROBE_DEFER; | ||
1416 | } | ||
1417 | } | ||
1418 | of_node_put(np); | ||
1419 | } else { | ||
1420 | DRM_ERROR("no remote endpoint device node found.\n"); | ||
1421 | return -EINVAL; | ||
1422 | } | ||
1423 | } else { | ||
1424 | DRM_ERROR("no port endpoint subnode found.\n"); | ||
1425 | return -EINVAL; | ||
1426 | } | ||
1427 | |||
1428 | out: | ||
1429 | pm_runtime_enable(dev); | ||
1430 | |||
1431 | ret = component_add(&pdev->dev, &exynos_dp_ops); | ||
1432 | if (ret) | ||
1433 | goto err_disable_pm_runtime; | ||
1434 | |||
1435 | return ret; | ||
1436 | |||
1437 | err_disable_pm_runtime: | ||
1438 | pm_runtime_disable(dev); | ||
1439 | |||
1440 | return ret; | ||
1441 | } | ||
1442 | |||
1443 | static int exynos_dp_remove(struct platform_device *pdev) | ||
1444 | { | ||
1445 | pm_runtime_disable(&pdev->dev); | ||
1446 | component_del(&pdev->dev, &exynos_dp_ops); | ||
1447 | |||
1448 | return 0; | ||
1449 | } | ||
1450 | |||
1451 | #ifdef CONFIG_PM | ||
1452 | static int exynos_dp_suspend(struct device *dev) | ||
1453 | { | ||
1454 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | ||
1455 | |||
1456 | clk_disable_unprepare(dp->clock); | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | static int exynos_dp_resume(struct device *dev) | ||
1462 | { | ||
1463 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | ||
1464 | int ret; | ||
1465 | |||
1466 | ret = clk_prepare_enable(dp->clock); | ||
1467 | if (ret < 0) { | ||
1468 | DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret); | ||
1469 | return ret; | ||
1470 | } | ||
1471 | |||
1472 | return 0; | ||
1473 | } | ||
1474 | #endif | ||
1475 | |||
1476 | static const struct dev_pm_ops exynos_dp_pm_ops = { | ||
1477 | SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) | ||
1478 | }; | ||
1479 | |||
1480 | static const struct of_device_id exynos_dp_match[] = { | ||
1481 | { .compatible = "samsung,exynos5-dp" }, | ||
1482 | {}, | ||
1483 | }; | ||
1484 | MODULE_DEVICE_TABLE(of, exynos_dp_match); | ||
1485 | |||
1486 | struct platform_driver dp_driver = { | ||
1487 | .probe = exynos_dp_probe, | ||
1488 | .remove = exynos_dp_remove, | ||
1489 | .driver = { | ||
1490 | .name = "exynos-dp", | ||
1491 | .owner = THIS_MODULE, | ||
1492 | .pm = &exynos_dp_pm_ops, | ||
1493 | .of_match_table = exynos_dp_match, | ||
1494 | }, | ||
1495 | }; | ||
1496 | |||
1497 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | ||
1498 | MODULE_DESCRIPTION("Samsung SoC DP Driver"); | ||
1499 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h deleted file mode 100644 index b5c2d8f47f9c..000000000000 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ /dev/null | |||
@@ -1,282 +0,0 @@ | |||
1 | /* | ||
2 | * Header file for Samsung DP (Display Port) interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _EXYNOS_DP_CORE_H | ||
14 | #define _EXYNOS_DP_CORE_H | ||
15 | |||
16 | #include <drm/drm_crtc.h> | ||
17 | #include <drm/drm_dp_helper.h> | ||
18 | #include <drm/exynos_drm.h> | ||
19 | #include <video/videomode.h> | ||
20 | |||
21 | #include "exynos_drm_drv.h" | ||
22 | |||
23 | #define DP_TIMEOUT_LOOP_COUNT 100 | ||
24 | #define MAX_CR_LOOP 5 | ||
25 | #define MAX_EQ_LOOP 5 | ||
26 | |||
27 | enum link_rate_type { | ||
28 | LINK_RATE_1_62GBPS = 0x06, | ||
29 | LINK_RATE_2_70GBPS = 0x0a | ||
30 | }; | ||
31 | |||
32 | enum link_lane_count_type { | ||
33 | LANE_COUNT1 = 1, | ||
34 | LANE_COUNT2 = 2, | ||
35 | LANE_COUNT4 = 4 | ||
36 | }; | ||
37 | |||
38 | enum link_training_state { | ||
39 | START, | ||
40 | CLOCK_RECOVERY, | ||
41 | EQUALIZER_TRAINING, | ||
42 | FINISHED, | ||
43 | FAILED | ||
44 | }; | ||
45 | |||
46 | enum voltage_swing_level { | ||
47 | VOLTAGE_LEVEL_0, | ||
48 | VOLTAGE_LEVEL_1, | ||
49 | VOLTAGE_LEVEL_2, | ||
50 | VOLTAGE_LEVEL_3, | ||
51 | }; | ||
52 | |||
53 | enum pre_emphasis_level { | ||
54 | PRE_EMPHASIS_LEVEL_0, | ||
55 | PRE_EMPHASIS_LEVEL_1, | ||
56 | PRE_EMPHASIS_LEVEL_2, | ||
57 | PRE_EMPHASIS_LEVEL_3, | ||
58 | }; | ||
59 | |||
60 | enum pattern_set { | ||
61 | PRBS7, | ||
62 | D10_2, | ||
63 | TRAINING_PTN1, | ||
64 | TRAINING_PTN2, | ||
65 | DP_NONE | ||
66 | }; | ||
67 | |||
68 | enum color_space { | ||
69 | COLOR_RGB, | ||
70 | COLOR_YCBCR422, | ||
71 | COLOR_YCBCR444 | ||
72 | }; | ||
73 | |||
74 | enum color_depth { | ||
75 | COLOR_6, | ||
76 | COLOR_8, | ||
77 | COLOR_10, | ||
78 | COLOR_12 | ||
79 | }; | ||
80 | |||
81 | enum color_coefficient { | ||
82 | COLOR_YCBCR601, | ||
83 | COLOR_YCBCR709 | ||
84 | }; | ||
85 | |||
86 | enum dynamic_range { | ||
87 | VESA, | ||
88 | CEA | ||
89 | }; | ||
90 | |||
91 | enum pll_status { | ||
92 | PLL_UNLOCKED, | ||
93 | PLL_LOCKED | ||
94 | }; | ||
95 | |||
96 | enum clock_recovery_m_value_type { | ||
97 | CALCULATED_M, | ||
98 | REGISTER_M | ||
99 | }; | ||
100 | |||
101 | enum video_timing_recognition_type { | ||
102 | VIDEO_TIMING_FROM_CAPTURE, | ||
103 | VIDEO_TIMING_FROM_REGISTER | ||
104 | }; | ||
105 | |||
106 | enum analog_power_block { | ||
107 | AUX_BLOCK, | ||
108 | CH0_BLOCK, | ||
109 | CH1_BLOCK, | ||
110 | CH2_BLOCK, | ||
111 | CH3_BLOCK, | ||
112 | ANALOG_TOTAL, | ||
113 | POWER_ALL | ||
114 | }; | ||
115 | |||
116 | enum dp_irq_type { | ||
117 | DP_IRQ_TYPE_HP_CABLE_IN, | ||
118 | DP_IRQ_TYPE_HP_CABLE_OUT, | ||
119 | DP_IRQ_TYPE_HP_CHANGE, | ||
120 | DP_IRQ_TYPE_UNKNOWN, | ||
121 | }; | ||
122 | |||
123 | struct video_info { | ||
124 | char *name; | ||
125 | |||
126 | bool h_sync_polarity; | ||
127 | bool v_sync_polarity; | ||
128 | bool interlaced; | ||
129 | |||
130 | enum color_space color_space; | ||
131 | enum dynamic_range dynamic_range; | ||
132 | enum color_coefficient ycbcr_coeff; | ||
133 | enum color_depth color_depth; | ||
134 | |||
135 | enum link_rate_type link_rate; | ||
136 | enum link_lane_count_type lane_count; | ||
137 | }; | ||
138 | |||
139 | struct link_train { | ||
140 | int eq_loop; | ||
141 | int cr_loop[4]; | ||
142 | |||
143 | u8 link_rate; | ||
144 | u8 lane_count; | ||
145 | u8 training_lane[4]; | ||
146 | |||
147 | enum link_training_state lt_state; | ||
148 | }; | ||
149 | |||
150 | struct exynos_dp_device { | ||
151 | struct drm_encoder encoder; | ||
152 | struct device *dev; | ||
153 | struct drm_device *drm_dev; | ||
154 | struct drm_connector connector; | ||
155 | struct drm_panel *panel; | ||
156 | struct drm_bridge *bridge; | ||
157 | struct drm_bridge *ptn_bridge; | ||
158 | struct clk *clock; | ||
159 | unsigned int irq; | ||
160 | void __iomem *reg_base; | ||
161 | |||
162 | struct video_info *video_info; | ||
163 | struct link_train link_train; | ||
164 | struct work_struct hotplug_work; | ||
165 | struct phy *phy; | ||
166 | int dpms_mode; | ||
167 | int hpd_gpio; | ||
168 | struct videomode vm; | ||
169 | }; | ||
170 | |||
171 | /* exynos_dp_reg.c */ | ||
172 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable); | ||
173 | void exynos_dp_stop_video(struct exynos_dp_device *dp); | ||
174 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable); | ||
175 | void exynos_dp_init_analog_param(struct exynos_dp_device *dp); | ||
176 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp); | ||
177 | void exynos_dp_reset(struct exynos_dp_device *dp); | ||
178 | void exynos_dp_swreset(struct exynos_dp_device *dp); | ||
179 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp); | ||
180 | enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); | ||
181 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); | ||
182 | void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | ||
183 | enum analog_power_block block, | ||
184 | bool enable); | ||
185 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp); | ||
186 | void exynos_dp_init_hpd(struct exynos_dp_device *dp); | ||
187 | enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp); | ||
188 | void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp); | ||
189 | void exynos_dp_reset_aux(struct exynos_dp_device *dp); | ||
190 | void exynos_dp_init_aux(struct exynos_dp_device *dp); | ||
191 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); | ||
192 | void exynos_dp_enable_sw_function(struct exynos_dp_device *dp); | ||
193 | int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp); | ||
194 | int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, | ||
195 | unsigned int reg_addr, | ||
196 | unsigned char data); | ||
197 | int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | ||
198 | unsigned int reg_addr, | ||
199 | unsigned char *data); | ||
200 | int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | ||
201 | unsigned int reg_addr, | ||
202 | unsigned int count, | ||
203 | unsigned char data[]); | ||
204 | int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | ||
205 | unsigned int reg_addr, | ||
206 | unsigned int count, | ||
207 | unsigned char data[]); | ||
208 | int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, | ||
209 | unsigned int device_addr, | ||
210 | unsigned int reg_addr); | ||
211 | int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | ||
212 | unsigned int device_addr, | ||
213 | unsigned int reg_addr, | ||
214 | unsigned int *data); | ||
215 | int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | ||
216 | unsigned int device_addr, | ||
217 | unsigned int reg_addr, | ||
218 | unsigned int count, | ||
219 | unsigned char edid[]); | ||
220 | void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype); | ||
221 | void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype); | ||
222 | void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count); | ||
223 | void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count); | ||
224 | void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable); | ||
225 | void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, | ||
226 | enum pattern_set pattern); | ||
227 | void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
228 | void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
229 | void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
230 | void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
231 | void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, | ||
232 | u32 training_lane); | ||
233 | void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, | ||
234 | u32 training_lane); | ||
235 | void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, | ||
236 | u32 training_lane); | ||
237 | void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, | ||
238 | u32 training_lane); | ||
239 | u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp); | ||
240 | u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp); | ||
241 | u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp); | ||
242 | u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); | ||
243 | void exynos_dp_reset_macro(struct exynos_dp_device *dp); | ||
244 | void exynos_dp_init_video(struct exynos_dp_device *dp); | ||
245 | |||
246 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp); | ||
247 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); | ||
248 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | ||
249 | enum clock_recovery_m_value_type type, | ||
250 | u32 m_value, | ||
251 | u32 n_value); | ||
252 | void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type); | ||
253 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); | ||
254 | void exynos_dp_start_video(struct exynos_dp_device *dp); | ||
255 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); | ||
256 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp); | ||
257 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); | ||
258 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); | ||
259 | |||
260 | /* I2C EDID Chip ID, Slave Address */ | ||
261 | #define I2C_EDID_DEVICE_ADDR 0x50 | ||
262 | #define I2C_E_EDID_DEVICE_ADDR 0x30 | ||
263 | |||
264 | #define EDID_BLOCK_LENGTH 0x80 | ||
265 | #define EDID_HEADER_PATTERN 0x00 | ||
266 | #define EDID_EXTENSION_FLAG 0x7e | ||
267 | #define EDID_CHECKSUM 0x7f | ||
268 | |||
269 | /* DP_MAX_LANE_COUNT */ | ||
270 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) | ||
271 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) | ||
272 | |||
273 | /* DP_LANE_COUNT_SET */ | ||
274 | #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) | ||
275 | |||
276 | /* DP_TRAINING_LANE0_SET */ | ||
277 | #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) | ||
278 | #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) | ||
279 | #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) | ||
280 | #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) | ||
281 | |||
282 | #endif /* _EXYNOS_DP_CORE_H */ | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.c b/drivers/gpu/drm/exynos/exynos_dp_reg.c deleted file mode 100644 index c1f87a2a9284..000000000000 --- a/drivers/gpu/drm/exynos/exynos_dp_reg.c +++ /dev/null | |||
@@ -1,1263 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung DP (Display port) register interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/gpio.h> | ||
17 | |||
18 | #include "exynos_dp_core.h" | ||
19 | #include "exynos_dp_reg.h" | ||
20 | |||
21 | #define COMMON_INT_MASK_1 0 | ||
22 | #define COMMON_INT_MASK_2 0 | ||
23 | #define COMMON_INT_MASK_3 0 | ||
24 | #define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) | ||
25 | #define INT_STA_MASK INT_HPD | ||
26 | |||
27 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) | ||
28 | { | ||
29 | u32 reg; | ||
30 | |||
31 | if (enable) { | ||
32 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
33 | reg |= HDCP_VIDEO_MUTE; | ||
34 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
35 | } else { | ||
36 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
37 | reg &= ~HDCP_VIDEO_MUTE; | ||
38 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | void exynos_dp_stop_video(struct exynos_dp_device *dp) | ||
43 | { | ||
44 | u32 reg; | ||
45 | |||
46 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
47 | reg &= ~VIDEO_EN; | ||
48 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
49 | } | ||
50 | |||
51 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable) | ||
52 | { | ||
53 | u32 reg; | ||
54 | |||
55 | if (enable) | ||
56 | reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | | ||
57 | LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; | ||
58 | else | ||
59 | reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | | ||
60 | LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; | ||
61 | |||
62 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP); | ||
63 | } | ||
64 | |||
65 | void exynos_dp_init_analog_param(struct exynos_dp_device *dp) | ||
66 | { | ||
67 | u32 reg; | ||
68 | |||
69 | reg = TX_TERMINAL_CTRL_50_OHM; | ||
70 | writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1); | ||
71 | |||
72 | reg = SEL_24M | TX_DVDD_BIT_1_0625V; | ||
73 | writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2); | ||
74 | |||
75 | reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; | ||
76 | writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3); | ||
77 | |||
78 | reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | | ||
79 | TX_CUR1_2X | TX_CUR_16_MA; | ||
80 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1); | ||
81 | |||
82 | reg = CH3_AMP_400_MV | CH2_AMP_400_MV | | ||
83 | CH1_AMP_400_MV | CH0_AMP_400_MV; | ||
84 | writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL); | ||
85 | } | ||
86 | |||
87 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) | ||
88 | { | ||
89 | /* Set interrupt pin assertion polarity as high */ | ||
90 | writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL); | ||
91 | |||
92 | /* Clear pending regisers */ | ||
93 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
94 | writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2); | ||
95 | writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3); | ||
96 | writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
97 | writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA); | ||
98 | |||
99 | /* 0:mask,1: unmask */ | ||
100 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); | ||
101 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); | ||
102 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); | ||
103 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); | ||
104 | writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK); | ||
105 | } | ||
106 | |||
107 | void exynos_dp_reset(struct exynos_dp_device *dp) | ||
108 | { | ||
109 | u32 reg; | ||
110 | |||
111 | exynos_dp_stop_video(dp); | ||
112 | exynos_dp_enable_video_mute(dp, 0); | ||
113 | |||
114 | reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | | ||
115 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | | ||
116 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; | ||
117 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
118 | |||
119 | reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | | ||
120 | SERDES_FIFO_FUNC_EN_N | | ||
121 | LS_CLK_DOMAIN_FUNC_EN_N; | ||
122 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
123 | |||
124 | usleep_range(20, 30); | ||
125 | |||
126 | exynos_dp_lane_swap(dp, 0); | ||
127 | |||
128 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
129 | writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
130 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
131 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
132 | |||
133 | writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL); | ||
134 | writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL); | ||
135 | |||
136 | writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L); | ||
137 | writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H); | ||
138 | |||
139 | writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL); | ||
140 | |||
141 | writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
142 | |||
143 | writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD); | ||
144 | writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN); | ||
145 | |||
146 | writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH); | ||
147 | writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH); | ||
148 | |||
149 | writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
150 | } | ||
151 | |||
152 | void exynos_dp_swreset(struct exynos_dp_device *dp) | ||
153 | { | ||
154 | writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET); | ||
155 | } | ||
156 | |||
157 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp) | ||
158 | { | ||
159 | u32 reg; | ||
160 | |||
161 | /* 0: mask, 1: unmask */ | ||
162 | reg = COMMON_INT_MASK_1; | ||
163 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); | ||
164 | |||
165 | reg = COMMON_INT_MASK_2; | ||
166 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); | ||
167 | |||
168 | reg = COMMON_INT_MASK_3; | ||
169 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); | ||
170 | |||
171 | reg = COMMON_INT_MASK_4; | ||
172 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); | ||
173 | |||
174 | reg = INT_STA_MASK; | ||
175 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK); | ||
176 | } | ||
177 | |||
178 | enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) | ||
179 | { | ||
180 | u32 reg; | ||
181 | |||
182 | reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
183 | if (reg & PLL_LOCK) | ||
184 | return PLL_LOCKED; | ||
185 | else | ||
186 | return PLL_UNLOCKED; | ||
187 | } | ||
188 | |||
189 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable) | ||
190 | { | ||
191 | u32 reg; | ||
192 | |||
193 | if (enable) { | ||
194 | reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
195 | reg |= DP_PLL_PD; | ||
196 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
197 | } else { | ||
198 | reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
199 | reg &= ~DP_PLL_PD; | ||
200 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | ||
205 | enum analog_power_block block, | ||
206 | bool enable) | ||
207 | { | ||
208 | u32 reg; | ||
209 | |||
210 | switch (block) { | ||
211 | case AUX_BLOCK: | ||
212 | if (enable) { | ||
213 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
214 | reg |= AUX_PD; | ||
215 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
216 | } else { | ||
217 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
218 | reg &= ~AUX_PD; | ||
219 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
220 | } | ||
221 | break; | ||
222 | case CH0_BLOCK: | ||
223 | if (enable) { | ||
224 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
225 | reg |= CH0_PD; | ||
226 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
227 | } else { | ||
228 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
229 | reg &= ~CH0_PD; | ||
230 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
231 | } | ||
232 | break; | ||
233 | case CH1_BLOCK: | ||
234 | if (enable) { | ||
235 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
236 | reg |= CH1_PD; | ||
237 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
238 | } else { | ||
239 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
240 | reg &= ~CH1_PD; | ||
241 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
242 | } | ||
243 | break; | ||
244 | case CH2_BLOCK: | ||
245 | if (enable) { | ||
246 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
247 | reg |= CH2_PD; | ||
248 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
249 | } else { | ||
250 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
251 | reg &= ~CH2_PD; | ||
252 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
253 | } | ||
254 | break; | ||
255 | case CH3_BLOCK: | ||
256 | if (enable) { | ||
257 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
258 | reg |= CH3_PD; | ||
259 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
260 | } else { | ||
261 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
262 | reg &= ~CH3_PD; | ||
263 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
264 | } | ||
265 | break; | ||
266 | case ANALOG_TOTAL: | ||
267 | if (enable) { | ||
268 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
269 | reg |= DP_PHY_PD; | ||
270 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
271 | } else { | ||
272 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
273 | reg &= ~DP_PHY_PD; | ||
274 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
275 | } | ||
276 | break; | ||
277 | case POWER_ALL: | ||
278 | if (enable) { | ||
279 | reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | | ||
280 | CH1_PD | CH0_PD; | ||
281 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
282 | } else { | ||
283 | writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
284 | } | ||
285 | break; | ||
286 | default: | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | ||
292 | { | ||
293 | u32 reg; | ||
294 | int timeout_loop = 0; | ||
295 | |||
296 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
297 | |||
298 | reg = PLL_LOCK_CHG; | ||
299 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
300 | |||
301 | reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
302 | reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); | ||
303 | writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
304 | |||
305 | /* Power up PLL */ | ||
306 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
307 | exynos_dp_set_pll_power_down(dp, 0); | ||
308 | |||
309 | while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
310 | timeout_loop++; | ||
311 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
312 | dev_err(dp->dev, "failed to get pll lock status\n"); | ||
313 | return; | ||
314 | } | ||
315 | usleep_range(10, 20); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /* Enable Serdes FIFO function and Link symbol clock domain module */ | ||
320 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
321 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | ||
322 | | AUX_FUNC_EN_N); | ||
323 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
324 | } | ||
325 | |||
326 | void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp) | ||
327 | { | ||
328 | u32 reg; | ||
329 | |||
330 | if (gpio_is_valid(dp->hpd_gpio)) | ||
331 | return; | ||
332 | |||
333 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; | ||
334 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
335 | |||
336 | reg = INT_HPD; | ||
337 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | ||
338 | } | ||
339 | |||
340 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | ||
341 | { | ||
342 | u32 reg; | ||
343 | |||
344 | if (gpio_is_valid(dp->hpd_gpio)) | ||
345 | return; | ||
346 | |||
347 | exynos_dp_clear_hotplug_interrupts(dp); | ||
348 | |||
349 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
350 | reg &= ~(F_HPD | HPD_CTRL); | ||
351 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
352 | } | ||
353 | |||
354 | enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp) | ||
355 | { | ||
356 | u32 reg; | ||
357 | |||
358 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
359 | reg = gpio_get_value(dp->hpd_gpio); | ||
360 | if (reg) | ||
361 | return DP_IRQ_TYPE_HP_CABLE_IN; | ||
362 | else | ||
363 | return DP_IRQ_TYPE_HP_CABLE_OUT; | ||
364 | } else { | ||
365 | /* Parse hotplug interrupt status register */ | ||
366 | reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
367 | |||
368 | if (reg & PLUG) | ||
369 | return DP_IRQ_TYPE_HP_CABLE_IN; | ||
370 | |||
371 | if (reg & HPD_LOST) | ||
372 | return DP_IRQ_TYPE_HP_CABLE_OUT; | ||
373 | |||
374 | if (reg & HOTPLUG_CHG) | ||
375 | return DP_IRQ_TYPE_HP_CHANGE; | ||
376 | |||
377 | return DP_IRQ_TYPE_UNKNOWN; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) | ||
382 | { | ||
383 | u32 reg; | ||
384 | |||
385 | /* Disable AUX channel module */ | ||
386 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
387 | reg |= AUX_FUNC_EN_N; | ||
388 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
389 | } | ||
390 | |||
391 | void exynos_dp_init_aux(struct exynos_dp_device *dp) | ||
392 | { | ||
393 | u32 reg; | ||
394 | |||
395 | /* Clear inerrupts related to AUX channel */ | ||
396 | reg = RPLY_RECEIV | AUX_ERR; | ||
397 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | ||
398 | |||
399 | exynos_dp_reset_aux(dp); | ||
400 | |||
401 | /* Disable AUX transaction H/W retry */ | ||
402 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| | ||
403 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | ||
404 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL); | ||
405 | |||
406 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ | ||
407 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); | ||
408 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL); | ||
409 | |||
410 | /* Enable AUX channel module */ | ||
411 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
412 | reg &= ~AUX_FUNC_EN_N; | ||
413 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
414 | } | ||
415 | |||
416 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp) | ||
417 | { | ||
418 | u32 reg; | ||
419 | |||
420 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
421 | if (gpio_get_value(dp->hpd_gpio)) | ||
422 | return 0; | ||
423 | } else { | ||
424 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
425 | if (reg & HPD_STATUS) | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | return -EINVAL; | ||
430 | } | ||
431 | |||
432 | void exynos_dp_enable_sw_function(struct exynos_dp_device *dp) | ||
433 | { | ||
434 | u32 reg; | ||
435 | |||
436 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
437 | reg &= ~SW_FUNC_EN_N; | ||
438 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
439 | } | ||
440 | |||
441 | int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) | ||
442 | { | ||
443 | int reg; | ||
444 | int retval = 0; | ||
445 | int timeout_loop = 0; | ||
446 | |||
447 | /* Enable AUX CH operation */ | ||
448 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
449 | reg |= AUX_EN; | ||
450 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
451 | |||
452 | /* Is AUX CH command reply received? */ | ||
453 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
454 | while (!(reg & RPLY_RECEIV)) { | ||
455 | timeout_loop++; | ||
456 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
457 | dev_err(dp->dev, "AUX CH command reply failed!\n"); | ||
458 | return -ETIMEDOUT; | ||
459 | } | ||
460 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
461 | usleep_range(10, 11); | ||
462 | } | ||
463 | |||
464 | /* Clear interrupt source for AUX CH command reply */ | ||
465 | writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA); | ||
466 | |||
467 | /* Clear interrupt source for AUX CH access error */ | ||
468 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
469 | if (reg & AUX_ERR) { | ||
470 | writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA); | ||
471 | return -EREMOTEIO; | ||
472 | } | ||
473 | |||
474 | /* Check AUX CH error access status */ | ||
475 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA); | ||
476 | if ((reg & AUX_STATUS_MASK) != 0) { | ||
477 | dev_err(dp->dev, "AUX CH error happens: %d\n\n", | ||
478 | reg & AUX_STATUS_MASK); | ||
479 | return -EREMOTEIO; | ||
480 | } | ||
481 | |||
482 | return retval; | ||
483 | } | ||
484 | |||
485 | int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, | ||
486 | unsigned int reg_addr, | ||
487 | unsigned char data) | ||
488 | { | ||
489 | u32 reg; | ||
490 | int i; | ||
491 | int retval; | ||
492 | |||
493 | for (i = 0; i < 3; i++) { | ||
494 | /* Clear AUX CH data buffer */ | ||
495 | reg = BUF_CLR; | ||
496 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
497 | |||
498 | /* Select DPCD device address */ | ||
499 | reg = AUX_ADDR_7_0(reg_addr); | ||
500 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
501 | reg = AUX_ADDR_15_8(reg_addr); | ||
502 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
503 | reg = AUX_ADDR_19_16(reg_addr); | ||
504 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
505 | |||
506 | /* Write data buffer */ | ||
507 | reg = (unsigned int)data; | ||
508 | writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
509 | |||
510 | /* | ||
511 | * Set DisplayPort transaction and write 1 byte | ||
512 | * If bit 3 is 1, DisplayPort transaction. | ||
513 | * If Bit 3 is 0, I2C transaction. | ||
514 | */ | ||
515 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
516 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
517 | |||
518 | /* Start AUX transaction */ | ||
519 | retval = exynos_dp_start_aux_transaction(dp); | ||
520 | if (retval == 0) | ||
521 | break; | ||
522 | else | ||
523 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
524 | __func__); | ||
525 | } | ||
526 | |||
527 | return retval; | ||
528 | } | ||
529 | |||
530 | int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | ||
531 | unsigned int reg_addr, | ||
532 | unsigned char *data) | ||
533 | { | ||
534 | u32 reg; | ||
535 | int i; | ||
536 | int retval; | ||
537 | |||
538 | for (i = 0; i < 3; i++) { | ||
539 | /* Clear AUX CH data buffer */ | ||
540 | reg = BUF_CLR; | ||
541 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
542 | |||
543 | /* Select DPCD device address */ | ||
544 | reg = AUX_ADDR_7_0(reg_addr); | ||
545 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
546 | reg = AUX_ADDR_15_8(reg_addr); | ||
547 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
548 | reg = AUX_ADDR_19_16(reg_addr); | ||
549 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
550 | |||
551 | /* | ||
552 | * Set DisplayPort transaction and read 1 byte | ||
553 | * If bit 3 is 1, DisplayPort transaction. | ||
554 | * If Bit 3 is 0, I2C transaction. | ||
555 | */ | ||
556 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
557 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
558 | |||
559 | /* Start AUX transaction */ | ||
560 | retval = exynos_dp_start_aux_transaction(dp); | ||
561 | if (retval == 0) | ||
562 | break; | ||
563 | else | ||
564 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
565 | __func__); | ||
566 | } | ||
567 | |||
568 | /* Read data buffer */ | ||
569 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
570 | *data = (unsigned char)(reg & 0xff); | ||
571 | |||
572 | return retval; | ||
573 | } | ||
574 | |||
575 | int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | ||
576 | unsigned int reg_addr, | ||
577 | unsigned int count, | ||
578 | unsigned char data[]) | ||
579 | { | ||
580 | u32 reg; | ||
581 | unsigned int start_offset; | ||
582 | unsigned int cur_data_count; | ||
583 | unsigned int cur_data_idx; | ||
584 | int i; | ||
585 | int retval = 0; | ||
586 | |||
587 | /* Clear AUX CH data buffer */ | ||
588 | reg = BUF_CLR; | ||
589 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
590 | |||
591 | start_offset = 0; | ||
592 | while (start_offset < count) { | ||
593 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
594 | if ((count - start_offset) > 16) | ||
595 | cur_data_count = 16; | ||
596 | else | ||
597 | cur_data_count = count - start_offset; | ||
598 | |||
599 | for (i = 0; i < 3; i++) { | ||
600 | /* Select DPCD device address */ | ||
601 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
602 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
603 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
604 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
605 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
606 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
607 | |||
608 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
609 | cur_data_idx++) { | ||
610 | reg = data[start_offset + cur_data_idx]; | ||
611 | writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
612 | + 4 * cur_data_idx); | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * Set DisplayPort transaction and write | ||
617 | * If bit 3 is 1, DisplayPort transaction. | ||
618 | * If Bit 3 is 0, I2C transaction. | ||
619 | */ | ||
620 | reg = AUX_LENGTH(cur_data_count) | | ||
621 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
622 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
623 | |||
624 | /* Start AUX transaction */ | ||
625 | retval = exynos_dp_start_aux_transaction(dp); | ||
626 | if (retval == 0) | ||
627 | break; | ||
628 | else | ||
629 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
630 | __func__); | ||
631 | } | ||
632 | |||
633 | start_offset += cur_data_count; | ||
634 | } | ||
635 | |||
636 | return retval; | ||
637 | } | ||
638 | |||
639 | int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | ||
640 | unsigned int reg_addr, | ||
641 | unsigned int count, | ||
642 | unsigned char data[]) | ||
643 | { | ||
644 | u32 reg; | ||
645 | unsigned int start_offset; | ||
646 | unsigned int cur_data_count; | ||
647 | unsigned int cur_data_idx; | ||
648 | int i; | ||
649 | int retval = 0; | ||
650 | |||
651 | /* Clear AUX CH data buffer */ | ||
652 | reg = BUF_CLR; | ||
653 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
654 | |||
655 | start_offset = 0; | ||
656 | while (start_offset < count) { | ||
657 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
658 | if ((count - start_offset) > 16) | ||
659 | cur_data_count = 16; | ||
660 | else | ||
661 | cur_data_count = count - start_offset; | ||
662 | |||
663 | /* AUX CH Request Transaction process */ | ||
664 | for (i = 0; i < 3; i++) { | ||
665 | /* Select DPCD device address */ | ||
666 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
667 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
668 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
669 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
670 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
671 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
672 | |||
673 | /* | ||
674 | * Set DisplayPort transaction and read | ||
675 | * If bit 3 is 1, DisplayPort transaction. | ||
676 | * If Bit 3 is 0, I2C transaction. | ||
677 | */ | ||
678 | reg = AUX_LENGTH(cur_data_count) | | ||
679 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
680 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
681 | |||
682 | /* Start AUX transaction */ | ||
683 | retval = exynos_dp_start_aux_transaction(dp); | ||
684 | if (retval == 0) | ||
685 | break; | ||
686 | else | ||
687 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
688 | __func__); | ||
689 | } | ||
690 | |||
691 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
692 | cur_data_idx++) { | ||
693 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
694 | + 4 * cur_data_idx); | ||
695 | data[start_offset + cur_data_idx] = | ||
696 | (unsigned char)reg; | ||
697 | } | ||
698 | |||
699 | start_offset += cur_data_count; | ||
700 | } | ||
701 | |||
702 | return retval; | ||
703 | } | ||
704 | |||
705 | int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, | ||
706 | unsigned int device_addr, | ||
707 | unsigned int reg_addr) | ||
708 | { | ||
709 | u32 reg; | ||
710 | int retval; | ||
711 | |||
712 | /* Set EDID device address */ | ||
713 | reg = device_addr; | ||
714 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
715 | writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
716 | writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
717 | |||
718 | /* Set offset from base address of EDID device */ | ||
719 | writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
720 | |||
721 | /* | ||
722 | * Set I2C transaction and write address | ||
723 | * If bit 3 is 1, DisplayPort transaction. | ||
724 | * If Bit 3 is 0, I2C transaction. | ||
725 | */ | ||
726 | reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | | ||
727 | AUX_TX_COMM_WRITE; | ||
728 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
729 | |||
730 | /* Start AUX transaction */ | ||
731 | retval = exynos_dp_start_aux_transaction(dp); | ||
732 | if (retval != 0) | ||
733 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
734 | |||
735 | return retval; | ||
736 | } | ||
737 | |||
738 | int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | ||
739 | unsigned int device_addr, | ||
740 | unsigned int reg_addr, | ||
741 | unsigned int *data) | ||
742 | { | ||
743 | u32 reg; | ||
744 | int i; | ||
745 | int retval; | ||
746 | |||
747 | for (i = 0; i < 3; i++) { | ||
748 | /* Clear AUX CH data buffer */ | ||
749 | reg = BUF_CLR; | ||
750 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
751 | |||
752 | /* Select EDID device */ | ||
753 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); | ||
754 | if (retval != 0) | ||
755 | continue; | ||
756 | |||
757 | /* | ||
758 | * Set I2C transaction and read data | ||
759 | * If bit 3 is 1, DisplayPort transaction. | ||
760 | * If Bit 3 is 0, I2C transaction. | ||
761 | */ | ||
762 | reg = AUX_TX_COMM_I2C_TRANSACTION | | ||
763 | AUX_TX_COMM_READ; | ||
764 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
765 | |||
766 | /* Start AUX transaction */ | ||
767 | retval = exynos_dp_start_aux_transaction(dp); | ||
768 | if (retval == 0) | ||
769 | break; | ||
770 | else | ||
771 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
772 | __func__); | ||
773 | } | ||
774 | |||
775 | /* Read data */ | ||
776 | if (retval == 0) | ||
777 | *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
778 | |||
779 | return retval; | ||
780 | } | ||
781 | |||
782 | int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | ||
783 | unsigned int device_addr, | ||
784 | unsigned int reg_addr, | ||
785 | unsigned int count, | ||
786 | unsigned char edid[]) | ||
787 | { | ||
788 | u32 reg; | ||
789 | unsigned int i, j; | ||
790 | unsigned int cur_data_idx; | ||
791 | unsigned int defer = 0; | ||
792 | int retval = 0; | ||
793 | |||
794 | for (i = 0; i < count; i += 16) { | ||
795 | for (j = 0; j < 3; j++) { | ||
796 | /* Clear AUX CH data buffer */ | ||
797 | reg = BUF_CLR; | ||
798 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
799 | |||
800 | /* Set normal AUX CH command */ | ||
801 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
802 | reg &= ~ADDR_ONLY; | ||
803 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
804 | |||
805 | /* | ||
806 | * If Rx sends defer, Tx sends only reads | ||
807 | * request without sending address | ||
808 | */ | ||
809 | if (!defer) | ||
810 | retval = exynos_dp_select_i2c_device(dp, | ||
811 | device_addr, reg_addr + i); | ||
812 | else | ||
813 | defer = 0; | ||
814 | |||
815 | if (retval == 0) { | ||
816 | /* | ||
817 | * Set I2C transaction and write data | ||
818 | * If bit 3 is 1, DisplayPort transaction. | ||
819 | * If Bit 3 is 0, I2C transaction. | ||
820 | */ | ||
821 | reg = AUX_LENGTH(16) | | ||
822 | AUX_TX_COMM_I2C_TRANSACTION | | ||
823 | AUX_TX_COMM_READ; | ||
824 | writel(reg, dp->reg_base + | ||
825 | EXYNOS_DP_AUX_CH_CTL_1); | ||
826 | |||
827 | /* Start AUX transaction */ | ||
828 | retval = exynos_dp_start_aux_transaction(dp); | ||
829 | if (retval == 0) | ||
830 | break; | ||
831 | else | ||
832 | dev_dbg(dp->dev, | ||
833 | "%s: Aux Transaction fail!\n", | ||
834 | __func__); | ||
835 | } | ||
836 | /* Check if Rx sends defer */ | ||
837 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM); | ||
838 | if (reg == AUX_RX_COMM_AUX_DEFER || | ||
839 | reg == AUX_RX_COMM_I2C_DEFER) { | ||
840 | dev_err(dp->dev, "Defer: %d\n\n", reg); | ||
841 | defer = 1; | ||
842 | } | ||
843 | } | ||
844 | |||
845 | for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { | ||
846 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
847 | + 4 * cur_data_idx); | ||
848 | edid[i + cur_data_idx] = (unsigned char)reg; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | return retval; | ||
853 | } | ||
854 | |||
855 | void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype) | ||
856 | { | ||
857 | u32 reg; | ||
858 | |||
859 | reg = bwtype; | ||
860 | if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS)) | ||
861 | writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET); | ||
862 | } | ||
863 | |||
864 | void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype) | ||
865 | { | ||
866 | u32 reg; | ||
867 | |||
868 | reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET); | ||
869 | *bwtype = reg; | ||
870 | } | ||
871 | |||
872 | void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count) | ||
873 | { | ||
874 | u32 reg; | ||
875 | |||
876 | reg = count; | ||
877 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); | ||
878 | } | ||
879 | |||
880 | void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count) | ||
881 | { | ||
882 | u32 reg; | ||
883 | |||
884 | reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); | ||
885 | *count = reg; | ||
886 | } | ||
887 | |||
888 | void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable) | ||
889 | { | ||
890 | u32 reg; | ||
891 | |||
892 | if (enable) { | ||
893 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
894 | reg |= ENHANCED; | ||
895 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
896 | } else { | ||
897 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
898 | reg &= ~ENHANCED; | ||
899 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
900 | } | ||
901 | } | ||
902 | |||
903 | void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, | ||
904 | enum pattern_set pattern) | ||
905 | { | ||
906 | u32 reg; | ||
907 | |||
908 | switch (pattern) { | ||
909 | case PRBS7: | ||
910 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; | ||
911 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
912 | break; | ||
913 | case D10_2: | ||
914 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; | ||
915 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
916 | break; | ||
917 | case TRAINING_PTN1: | ||
918 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; | ||
919 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
920 | break; | ||
921 | case TRAINING_PTN2: | ||
922 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; | ||
923 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
924 | break; | ||
925 | case DP_NONE: | ||
926 | reg = SCRAMBLING_ENABLE | | ||
927 | LINK_QUAL_PATTERN_SET_DISABLE | | ||
928 | SW_TRAINING_PATTERN_SET_NORMAL; | ||
929 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
930 | break; | ||
931 | default: | ||
932 | break; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
937 | { | ||
938 | u32 reg; | ||
939 | |||
940 | reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
941 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
942 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
943 | writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
944 | } | ||
945 | |||
946 | void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
947 | { | ||
948 | u32 reg; | ||
949 | |||
950 | reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
951 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
952 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
953 | writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
954 | } | ||
955 | |||
956 | void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
957 | { | ||
958 | u32 reg; | ||
959 | |||
960 | reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
961 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
962 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
963 | writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
964 | } | ||
965 | |||
966 | void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
967 | { | ||
968 | u32 reg; | ||
969 | |||
970 | reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
971 | reg &= ~PRE_EMPHASIS_SET_MASK; | ||
972 | reg |= level << PRE_EMPHASIS_SET_SHIFT; | ||
973 | writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
974 | } | ||
975 | |||
976 | void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, | ||
977 | u32 training_lane) | ||
978 | { | ||
979 | u32 reg; | ||
980 | |||
981 | reg = training_lane; | ||
982 | writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
983 | } | ||
984 | |||
985 | void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, | ||
986 | u32 training_lane) | ||
987 | { | ||
988 | u32 reg; | ||
989 | |||
990 | reg = training_lane; | ||
991 | writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
992 | } | ||
993 | |||
994 | void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, | ||
995 | u32 training_lane) | ||
996 | { | ||
997 | u32 reg; | ||
998 | |||
999 | reg = training_lane; | ||
1000 | writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
1001 | } | ||
1002 | |||
1003 | void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, | ||
1004 | u32 training_lane) | ||
1005 | { | ||
1006 | u32 reg; | ||
1007 | |||
1008 | reg = training_lane; | ||
1009 | writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
1010 | } | ||
1011 | |||
1012 | u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp) | ||
1013 | { | ||
1014 | u32 reg; | ||
1015 | |||
1016 | reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
1017 | return reg; | ||
1018 | } | ||
1019 | |||
1020 | u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp) | ||
1021 | { | ||
1022 | u32 reg; | ||
1023 | |||
1024 | reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
1025 | return reg; | ||
1026 | } | ||
1027 | |||
1028 | u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp) | ||
1029 | { | ||
1030 | u32 reg; | ||
1031 | |||
1032 | reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
1033 | return reg; | ||
1034 | } | ||
1035 | |||
1036 | u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp) | ||
1037 | { | ||
1038 | u32 reg; | ||
1039 | |||
1040 | reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
1041 | return reg; | ||
1042 | } | ||
1043 | |||
1044 | void exynos_dp_reset_macro(struct exynos_dp_device *dp) | ||
1045 | { | ||
1046 | u32 reg; | ||
1047 | |||
1048 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
1049 | reg |= MACRO_RST; | ||
1050 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
1051 | |||
1052 | /* 10 us is the minimum reset time. */ | ||
1053 | usleep_range(10, 20); | ||
1054 | |||
1055 | reg &= ~MACRO_RST; | ||
1056 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
1057 | } | ||
1058 | |||
1059 | void exynos_dp_init_video(struct exynos_dp_device *dp) | ||
1060 | { | ||
1061 | u32 reg; | ||
1062 | |||
1063 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; | ||
1064 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
1065 | |||
1066 | reg = 0x0; | ||
1067 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1068 | |||
1069 | reg = CHA_CRI(4) | CHA_CTRL; | ||
1070 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1071 | |||
1072 | reg = 0x0; | ||
1073 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1074 | |||
1075 | reg = VID_HRES_TH(2) | VID_VRES_TH(0); | ||
1076 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); | ||
1077 | } | ||
1078 | |||
1079 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp) | ||
1080 | { | ||
1081 | u32 reg; | ||
1082 | |||
1083 | /* Configure the input color depth, color space, dynamic range */ | ||
1084 | reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) | | ||
1085 | (dp->video_info->color_depth << IN_BPC_SHIFT) | | ||
1086 | (dp->video_info->color_space << IN_COLOR_F_SHIFT); | ||
1087 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); | ||
1088 | |||
1089 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | ||
1090 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | ||
1091 | reg &= ~IN_YC_COEFFI_MASK; | ||
1092 | if (dp->video_info->ycbcr_coeff) | ||
1093 | reg |= IN_YC_COEFFI_ITU709; | ||
1094 | else | ||
1095 | reg |= IN_YC_COEFFI_ITU601; | ||
1096 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | ||
1097 | } | ||
1098 | |||
1099 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp) | ||
1100 | { | ||
1101 | u32 reg; | ||
1102 | |||
1103 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1104 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1105 | |||
1106 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1107 | |||
1108 | if (!(reg & DET_STA)) { | ||
1109 | dev_dbg(dp->dev, "Input stream clock not detected.\n"); | ||
1110 | return -EINVAL; | ||
1111 | } | ||
1112 | |||
1113 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1114 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1115 | |||
1116 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1117 | dev_dbg(dp->dev, "wait SYS_CTL_2.\n"); | ||
1118 | |||
1119 | if (reg & CHA_STA) { | ||
1120 | dev_dbg(dp->dev, "Input stream clk is changing\n"); | ||
1121 | return -EINVAL; | ||
1122 | } | ||
1123 | |||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
1127 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | ||
1128 | enum clock_recovery_m_value_type type, | ||
1129 | u32 m_value, | ||
1130 | u32 n_value) | ||
1131 | { | ||
1132 | u32 reg; | ||
1133 | |||
1134 | if (type == REGISTER_M) { | ||
1135 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1136 | reg |= FIX_M_VID; | ||
1137 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1138 | reg = m_value & 0xff; | ||
1139 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0); | ||
1140 | reg = (m_value >> 8) & 0xff; | ||
1141 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1); | ||
1142 | reg = (m_value >> 16) & 0xff; | ||
1143 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2); | ||
1144 | |||
1145 | reg = n_value & 0xff; | ||
1146 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0); | ||
1147 | reg = (n_value >> 8) & 0xff; | ||
1148 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1); | ||
1149 | reg = (n_value >> 16) & 0xff; | ||
1150 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2); | ||
1151 | } else { | ||
1152 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1153 | reg &= ~FIX_M_VID; | ||
1154 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1155 | |||
1156 | writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0); | ||
1157 | writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1); | ||
1158 | writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2); | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1162 | void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type) | ||
1163 | { | ||
1164 | u32 reg; | ||
1165 | |||
1166 | if (type == VIDEO_TIMING_FROM_CAPTURE) { | ||
1167 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1168 | reg &= ~FORMAT_SEL; | ||
1169 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1170 | } else { | ||
1171 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1172 | reg |= FORMAT_SEL; | ||
1173 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable) | ||
1178 | { | ||
1179 | u32 reg; | ||
1180 | |||
1181 | if (enable) { | ||
1182 | reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1183 | reg &= ~VIDEO_MODE_MASK; | ||
1184 | reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; | ||
1185 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1186 | } else { | ||
1187 | reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1188 | reg &= ~VIDEO_MODE_MASK; | ||
1189 | reg |= VIDEO_MODE_SLAVE_MODE; | ||
1190 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1191 | } | ||
1192 | } | ||
1193 | |||
1194 | void exynos_dp_start_video(struct exynos_dp_device *dp) | ||
1195 | { | ||
1196 | u32 reg; | ||
1197 | |||
1198 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
1199 | reg |= VIDEO_EN; | ||
1200 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
1201 | } | ||
1202 | |||
1203 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp) | ||
1204 | { | ||
1205 | u32 reg; | ||
1206 | |||
1207 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1208 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1209 | |||
1210 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1211 | if (!(reg & STRM_VALID)) { | ||
1212 | dev_dbg(dp->dev, "Input video stream is not detected.\n"); | ||
1213 | return -EINVAL; | ||
1214 | } | ||
1215 | |||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp) | ||
1220 | { | ||
1221 | u32 reg; | ||
1222 | |||
1223 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
1224 | reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); | ||
1225 | reg |= MASTER_VID_FUNC_EN_N; | ||
1226 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
1227 | |||
1228 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1229 | reg &= ~INTERACE_SCAN_CFG; | ||
1230 | reg |= (dp->video_info->interlaced << 2); | ||
1231 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1232 | |||
1233 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1234 | reg &= ~VSYNC_POLARITY_CFG; | ||
1235 | reg |= (dp->video_info->v_sync_polarity << 1); | ||
1236 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1237 | |||
1238 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1239 | reg &= ~HSYNC_POLARITY_CFG; | ||
1240 | reg |= (dp->video_info->h_sync_polarity << 0); | ||
1241 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1242 | |||
1243 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; | ||
1244 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1245 | } | ||
1246 | |||
1247 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp) | ||
1248 | { | ||
1249 | u32 reg; | ||
1250 | |||
1251 | reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1252 | reg &= ~SCRAMBLING_DISABLE; | ||
1253 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1254 | } | ||
1255 | |||
1256 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp) | ||
1257 | { | ||
1258 | u32 reg; | ||
1259 | |||
1260 | reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1261 | reg |= SCRAMBLING_DISABLE; | ||
1262 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1263 | } | ||
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 76b3362c5e59..d30bdc38a760 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig | |||
@@ -16,6 +16,15 @@ config DRM_ROCKCHIP | |||
16 | 2D or 3D acceleration; acceleration is performed by other | 16 | 2D or 3D acceleration; acceleration is performed by other |
17 | IP found on the SoC. | 17 | IP found on the SoC. |
18 | 18 | ||
19 | config ROCKCHIP_ANALOGIX_DP | ||
20 | tristate "Rockchip specific extensions for Analogix DP driver" | ||
21 | depends on DRM_ROCKCHIP | ||
22 | select DRM_ANALOGIX_DP | ||
23 | help | ||
24 | This selects support for Rockchip SoC specific extensions | ||
25 | for the Analogix Core DP driver. If you want to enable DP | ||
26 | on RK3288 based SoC, you should selet this option. | ||
27 | |||
19 | config ROCKCHIP_DW_HDMI | 28 | config ROCKCHIP_DW_HDMI |
20 | tristate "Rockchip specific extensions for Synopsys DW HDMI" | 29 | tristate "Rockchip specific extensions for Synopsys DW HDMI" |
21 | depends on DRM_ROCKCHIP | 30 | depends on DRM_ROCKCHIP |
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index df8fbef17791..05d07138a2b2 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile | |||
@@ -6,6 +6,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ | |||
6 | rockchip_drm_gem.o rockchip_drm_vop.o | 6 | rockchip_drm_gem.o rockchip_drm_vop.o |
7 | rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o | 7 | rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o |
8 | 8 | ||
9 | obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o | ||
9 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o | 10 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o |
10 | obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o | 11 | obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o |
11 | obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o | 12 | obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o |
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c new file mode 100644 index 000000000000..a1d94d8d9443 --- /dev/null +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * Rockchip SoC DP (Display Port) interface driver. | ||
3 | * | ||
4 | * Copyright (C) Fuzhou Rockchip Electronics Co., Ltd. | ||
5 | * Author: Andy Yan <andy.yan@rock-chips.com> | ||
6 | * Yakir Yang <ykk@rock-chips.com> | ||
7 | * Jeff Chen <jeff.chen@rock-chips.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/component.h> | ||
16 | #include <linux/mfd/syscon.h> | ||
17 | #include <linux/of_graph.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/reset.h> | ||
20 | #include <linux/clk.h> | ||
21 | |||
22 | #include <drm/drmP.h> | ||
23 | #include <drm/drm_crtc_helper.h> | ||
24 | #include <drm/drm_dp_helper.h> | ||
25 | #include <drm/drm_of.h> | ||
26 | #include <drm/drm_panel.h> | ||
27 | |||
28 | #include <video/of_videomode.h> | ||
29 | #include <video/videomode.h> | ||
30 | |||
31 | #include <drm/bridge/analogix_dp.h> | ||
32 | |||
33 | #include "rockchip_drm_drv.h" | ||
34 | #include "rockchip_drm_vop.h" | ||
35 | |||
36 | #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) | ||
37 | |||
38 | /* dp grf register offset */ | ||
39 | #define GRF_SOC_CON6 0x025c | ||
40 | #define GRF_EDP_LCD_SEL_MASK BIT(5) | ||
41 | #define GRF_EDP_SEL_VOP_LIT BIT(5) | ||
42 | #define GRF_EDP_SEL_VOP_BIG 0 | ||
43 | |||
44 | struct rockchip_dp_device { | ||
45 | struct drm_device *drm_dev; | ||
46 | struct device *dev; | ||
47 | struct drm_encoder encoder; | ||
48 | struct drm_display_mode mode; | ||
49 | |||
50 | struct clk *pclk; | ||
51 | struct regmap *grf; | ||
52 | struct reset_control *rst; | ||
53 | |||
54 | struct analogix_dp_plat_data plat_data; | ||
55 | }; | ||
56 | |||
57 | static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) | ||
58 | { | ||
59 | reset_control_assert(dp->rst); | ||
60 | usleep_range(10, 20); | ||
61 | reset_control_deassert(dp->rst); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) | ||
67 | { | ||
68 | struct rockchip_dp_device *dp = to_dp(plat_data); | ||
69 | int ret; | ||
70 | |||
71 | ret = clk_prepare_enable(dp->pclk); | ||
72 | if (ret < 0) { | ||
73 | dev_err(dp->dev, "failed to enable pclk %d\n", ret); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | ret = rockchip_dp_pre_init(dp); | ||
78 | if (ret < 0) { | ||
79 | dev_err(dp->dev, "failed to dp pre init %d\n", ret); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) | ||
87 | { | ||
88 | struct rockchip_dp_device *dp = to_dp(plat_data); | ||
89 | |||
90 | clk_disable_unprepare(dp->pclk); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static bool | ||
96 | rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, | ||
97 | const struct drm_display_mode *mode, | ||
98 | struct drm_display_mode *adjusted_mode) | ||
99 | { | ||
100 | /* do nothing */ | ||
101 | return true; | ||
102 | } | ||
103 | |||
104 | static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder, | ||
105 | struct drm_display_mode *mode, | ||
106 | struct drm_display_mode *adjusted) | ||
107 | { | ||
108 | /* do nothing */ | ||
109 | } | ||
110 | |||
111 | static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) | ||
112 | { | ||
113 | struct rockchip_dp_device *dp = to_dp(encoder); | ||
114 | int ret; | ||
115 | u32 val; | ||
116 | |||
117 | /* | ||
118 | * FIXME(Yakir): driver should configure the CRTC output video | ||
119 | * mode with the display information which indicated the monitor | ||
120 | * support colorimetry. | ||
121 | * | ||
122 | * But don't know why the CRTC driver seems could only output the | ||
123 | * RGBaaa rightly. For example, if connect the "innolux,n116bge" | ||
124 | * eDP screen, EDID would indicated that screen only accepted the | ||
125 | * 6bpc mode. But if I configure CRTC to RGB666 output, then eDP | ||
126 | * screen would show a blue picture (RGB888 show a green picture). | ||
127 | * But if I configure CTRC to RGBaaa, and eDP driver still keep | ||
128 | * RGB666 input video mode, then screen would works prefect. | ||
129 | */ | ||
130 | ret = rockchip_drm_crtc_mode_config(encoder->crtc, | ||
131 | DRM_MODE_CONNECTOR_eDP, | ||
132 | ROCKCHIP_OUT_MODE_AAAA); | ||
133 | if (ret < 0) { | ||
134 | dev_err(dp->dev, "Could not set crtc mode config (%d)\n", ret); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); | ||
139 | if (ret < 0) | ||
140 | return; | ||
141 | |||
142 | if (ret) | ||
143 | val = GRF_EDP_SEL_VOP_LIT | (GRF_EDP_LCD_SEL_MASK << 16); | ||
144 | else | ||
145 | val = GRF_EDP_SEL_VOP_BIG | (GRF_EDP_LCD_SEL_MASK << 16); | ||
146 | |||
147 | dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); | ||
148 | |||
149 | ret = regmap_write(dp->grf, GRF_SOC_CON6, val); | ||
150 | if (ret != 0) { | ||
151 | dev_err(dp->dev, "Could not write to GRF: %d\n", ret); | ||
152 | return; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static void rockchip_dp_drm_encoder_nop(struct drm_encoder *encoder) | ||
157 | { | ||
158 | /* do nothing */ | ||
159 | } | ||
160 | |||
161 | static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = { | ||
162 | .mode_fixup = rockchip_dp_drm_encoder_mode_fixup, | ||
163 | .mode_set = rockchip_dp_drm_encoder_mode_set, | ||
164 | .enable = rockchip_dp_drm_encoder_enable, | ||
165 | .disable = rockchip_dp_drm_encoder_nop, | ||
166 | }; | ||
167 | |||
168 | static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder) | ||
169 | { | ||
170 | drm_encoder_cleanup(encoder); | ||
171 | } | ||
172 | |||
173 | static struct drm_encoder_funcs rockchip_dp_encoder_funcs = { | ||
174 | .destroy = rockchip_dp_drm_encoder_destroy, | ||
175 | }; | ||
176 | |||
177 | static int rockchip_dp_init(struct rockchip_dp_device *dp) | ||
178 | { | ||
179 | struct device *dev = dp->dev; | ||
180 | struct device_node *np = dev->of_node; | ||
181 | int ret; | ||
182 | |||
183 | dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | ||
184 | if (IS_ERR(dp->grf)) { | ||
185 | dev_err(dev, "failed to get rockchip,grf property\n"); | ||
186 | return PTR_ERR(dp->grf); | ||
187 | } | ||
188 | |||
189 | dp->pclk = devm_clk_get(dev, "pclk"); | ||
190 | if (IS_ERR(dp->pclk)) { | ||
191 | dev_err(dev, "failed to get pclk property\n"); | ||
192 | return PTR_ERR(dp->pclk); | ||
193 | } | ||
194 | |||
195 | dp->rst = devm_reset_control_get(dev, "dp"); | ||
196 | if (IS_ERR(dp->rst)) { | ||
197 | dev_err(dev, "failed to get dp reset control\n"); | ||
198 | return PTR_ERR(dp->rst); | ||
199 | } | ||
200 | |||
201 | ret = clk_prepare_enable(dp->pclk); | ||
202 | if (ret < 0) { | ||
203 | dev_err(dp->dev, "failed to enable pclk %d\n", ret); | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | ret = rockchip_dp_pre_init(dp); | ||
208 | if (ret < 0) { | ||
209 | dev_err(dp->dev, "failed to pre init %d\n", ret); | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) | ||
217 | { | ||
218 | struct drm_encoder *encoder = &dp->encoder; | ||
219 | struct drm_device *drm_dev = dp->drm_dev; | ||
220 | struct device *dev = dp->dev; | ||
221 | int ret; | ||
222 | |||
223 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, | ||
224 | dev->of_node); | ||
225 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
226 | |||
227 | ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs, | ||
228 | DRM_MODE_ENCODER_TMDS, NULL); | ||
229 | if (ret) { | ||
230 | DRM_ERROR("failed to initialize encoder with drm\n"); | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | drm_encoder_helper_add(encoder, &rockchip_dp_encoder_helper_funcs); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int rockchip_dp_bind(struct device *dev, struct device *master, | ||
240 | void *data) | ||
241 | { | ||
242 | struct rockchip_dp_device *dp = dev_get_drvdata(dev); | ||
243 | struct drm_device *drm_dev = data; | ||
244 | int ret; | ||
245 | |||
246 | /* | ||
247 | * Just like the probe function said, we don't need the | ||
248 | * device drvrate anymore, we should leave the charge to | ||
249 | * analogix dp driver, set the device drvdata to NULL. | ||
250 | */ | ||
251 | dev_set_drvdata(dev, NULL); | ||
252 | |||
253 | ret = rockchip_dp_init(dp); | ||
254 | if (ret < 0) | ||
255 | return ret; | ||
256 | |||
257 | dp->drm_dev = drm_dev; | ||
258 | |||
259 | ret = rockchip_dp_drm_create_encoder(dp); | ||
260 | if (ret) { | ||
261 | DRM_ERROR("failed to create drm encoder\n"); | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | dp->plat_data.encoder = &dp->encoder; | ||
266 | |||
267 | dp->plat_data.dev_type = RK3288_DP; | ||
268 | dp->plat_data.power_on = rockchip_dp_poweron; | ||
269 | dp->plat_data.power_off = rockchip_dp_powerdown; | ||
270 | |||
271 | return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); | ||
272 | } | ||
273 | |||
274 | static void rockchip_dp_unbind(struct device *dev, struct device *master, | ||
275 | void *data) | ||
276 | { | ||
277 | return analogix_dp_unbind(dev, master, data); | ||
278 | } | ||
279 | |||
280 | static const struct component_ops rockchip_dp_component_ops = { | ||
281 | .bind = rockchip_dp_bind, | ||
282 | .unbind = rockchip_dp_unbind, | ||
283 | }; | ||
284 | |||
285 | static int rockchip_dp_probe(struct platform_device *pdev) | ||
286 | { | ||
287 | struct device *dev = &pdev->dev; | ||
288 | struct device_node *panel_node, *port, *endpoint; | ||
289 | struct rockchip_dp_device *dp; | ||
290 | struct drm_panel *panel; | ||
291 | |||
292 | port = of_graph_get_port_by_id(dev->of_node, 1); | ||
293 | if (!port) { | ||
294 | dev_err(dev, "can't find output port\n"); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | endpoint = of_get_child_by_name(port, "endpoint"); | ||
299 | of_node_put(port); | ||
300 | if (!endpoint) { | ||
301 | dev_err(dev, "no output endpoint found\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | panel_node = of_graph_get_remote_port_parent(endpoint); | ||
306 | of_node_put(endpoint); | ||
307 | if (!panel_node) { | ||
308 | dev_err(dev, "no output node found\n"); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | panel = of_drm_find_panel(panel_node); | ||
313 | if (!panel) { | ||
314 | DRM_ERROR("failed to find panel\n"); | ||
315 | of_node_put(panel_node); | ||
316 | return -EPROBE_DEFER; | ||
317 | } | ||
318 | |||
319 | of_node_put(panel_node); | ||
320 | |||
321 | dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); | ||
322 | if (!dp) | ||
323 | return -ENOMEM; | ||
324 | |||
325 | dp->dev = dev; | ||
326 | |||
327 | dp->plat_data.panel = panel; | ||
328 | |||
329 | /* | ||
330 | * We just use the drvdata until driver run into component | ||
331 | * add function, and then we would set drvdata to null, so | ||
332 | * that analogix dp driver could take charge of the drvdata. | ||
333 | */ | ||
334 | platform_set_drvdata(pdev, dp); | ||
335 | |||
336 | return component_add(dev, &rockchip_dp_component_ops); | ||
337 | } | ||
338 | |||
339 | static int rockchip_dp_remove(struct platform_device *pdev) | ||
340 | { | ||
341 | component_del(&pdev->dev, &rockchip_dp_component_ops); | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | #ifdef CONFIG_PM_SLEEP | ||
347 | static int rockchip_dp_suspend(struct device *dev) | ||
348 | { | ||
349 | return analogix_dp_suspend(dev); | ||
350 | } | ||
351 | |||
352 | static int rockchip_dp_resume(struct device *dev) | ||
353 | { | ||
354 | return analogix_dp_resume(dev); | ||
355 | } | ||
356 | #endif | ||
357 | |||
358 | static const struct dev_pm_ops rockchip_dp_pm_ops = { | ||
359 | SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume) | ||
360 | }; | ||
361 | |||
362 | static const struct of_device_id rockchip_dp_dt_ids[] = { | ||
363 | {.compatible = "rockchip,rk3288-dp",}, | ||
364 | {} | ||
365 | }; | ||
366 | MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); | ||
367 | |||
368 | static struct platform_driver rockchip_dp_driver = { | ||
369 | .probe = rockchip_dp_probe, | ||
370 | .remove = rockchip_dp_remove, | ||
371 | .driver = { | ||
372 | .name = "rockchip-dp", | ||
373 | .owner = THIS_MODULE, | ||
374 | .pm = &rockchip_dp_pm_ops, | ||
375 | .of_match_table = of_match_ptr(rockchip_dp_dt_ids), | ||
376 | }, | ||
377 | }; | ||
378 | |||
379 | module_platform_driver(rockchip_dp_driver); | ||
380 | |||
381 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
382 | MODULE_AUTHOR("Jeff chen <jeff.chen@rock-chips.com>"); | ||
383 | MODULE_DESCRIPTION("Rockchip Specific Analogix-DP Driver Extension"); | ||
384 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h new file mode 100644 index 000000000000..25afb31f0389 --- /dev/null +++ b/include/drm/bridge/analogix_dp.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Analogix DP (Display Port) Core interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2015 Rockchip Electronics Co., Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | #ifndef _ANALOGIX_DP_H_ | ||
12 | #define _ANALOGIX_DP_H_ | ||
13 | |||
14 | #include <drm/drm_crtc.h> | ||
15 | |||
16 | enum analogix_dp_devtype { | ||
17 | EXYNOS_DP, | ||
18 | RK3288_DP, | ||
19 | }; | ||
20 | |||
21 | struct analogix_dp_plat_data { | ||
22 | enum analogix_dp_devtype dev_type; | ||
23 | struct drm_panel *panel; | ||
24 | struct drm_encoder *encoder; | ||
25 | struct drm_connector *connector; | ||
26 | |||
27 | int (*power_on)(struct analogix_dp_plat_data *); | ||
28 | int (*power_off)(struct analogix_dp_plat_data *); | ||
29 | int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *, | ||
30 | struct drm_connector *); | ||
31 | int (*get_modes)(struct analogix_dp_plat_data *); | ||
32 | }; | ||
33 | |||
34 | int analogix_dp_resume(struct device *dev); | ||
35 | int analogix_dp_suspend(struct device *dev); | ||
36 | |||
37 | int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, | ||
38 | struct analogix_dp_plat_data *plat_data); | ||
39 | void analogix_dp_unbind(struct device *dev, struct device *master, void *data); | ||
40 | |||
41 | #endif /* _ANALOGIX_DP_H_ */ | ||