diff options
author | Dave Airlie <airlied@redhat.com> | 2014-06-03 23:41:11 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-06-03 23:41:11 -0400 |
commit | b33a51e457b7e01e3e25eaa7c99aec32e65c00de (patch) | |
tree | 18db4abbdb05bd0cf97d320ab41e85af0eb2fe89 | |
parent | 1c404d88b26170b82aa274e7a40c91aa33145942 (diff) | |
parent | df5225bc9a87f1589a17797ee8e193608e4f3a9e (diff) |
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summary:
- Resolve probe order and deferred probe issue with component framework
support.
- Resolve hdmi dt broken issue.
. HDMI DT support, which was broken since CCF (common clock framework)
support, and considring legacy dt binding.
- Consolidate HDMI part.
. APB based phy support for Exynos5420 and later, and fixups related
to power on/off sequence.
- Consolidate IPP part.
. Mostly bug fixups and code cleanups.
- Trivial fixups and code cleanups.
* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (64 commits)
drm/exynos: consider deferred probe case
drm/exynos: remove unnecessary exynos_hdmi.h file
drm/exynos/fimd: allow multiplatform configuration
drm/exynos: add hdmiphy power on/off sequence
drm/exynos: ipp: remove description of non-existing field
drm/exynos: ipp: update comment for struct drm_ipp_buf_info
drm/exynos: ipp: rearrange c_node->event_lock using routine
drm/exynos: ipp: rearrange c_node->mem_lock using routines
drm/exynos: ipp: add ipp_remove_id()
drm/exynos: ipp: add cmd_lock for cmd_list
drm/exynos: ipp: rename cmd_lock to lock
drm/exynos: ipp: remove duplicated setting
drm/exynos: ipp: remove usless list_empty() functions
drm/exynos: Use PTR_ERR_OR_ZERO in exynos_dp_core.c
drm/exynos: remove hardware overlays disable from fimd probe
drm/exynos: Fix checkpatch warning in exynos_dp_reg.c
drm/exynos: add fimd dependency to fimd related encoders
drm/exynos: remove redundant mutex_unlock
drm/exynos/fimc: simplify and rename fimc_dst_get_buf_seq
drm/exynos/fimc: replace mutex by spinlock
...
30 files changed, 1807 insertions, 1419 deletions
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt index 57ccdde02c3a..53dbccfa80ca 100644 --- a/Documentation/devicetree/bindings/video/exynos_dp.txt +++ b/Documentation/devicetree/bindings/video/exynos_dp.txt | |||
@@ -62,6 +62,10 @@ Optional properties for dp-controller: | |||
62 | -hsync-active-high: | 62 | -hsync-active-high: |
63 | HSYNC polarity configuration. | 63 | HSYNC polarity configuration. |
64 | High if defined, Low if not defined | 64 | High if defined, Low if not defined |
65 | -samsung,hpd-gpio: | ||
66 | Hotplug detect GPIO. | ||
67 | Indicates which GPIO should be used for hotplug | ||
68 | detection | ||
65 | 69 | ||
66 | Example: | 70 | Example: |
67 | 71 | ||
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt index f9187a259259..1fd8cf9cbfac 100644 --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt | |||
@@ -5,6 +5,7 @@ Required properties: | |||
5 | 1) "samsung,exynos5-hdmi" <DEPRECATED> | 5 | 1) "samsung,exynos5-hdmi" <DEPRECATED> |
6 | 2) "samsung,exynos4210-hdmi" | 6 | 2) "samsung,exynos4210-hdmi" |
7 | 3) "samsung,exynos4212-hdmi" | 7 | 3) "samsung,exynos4212-hdmi" |
8 | 4) "samsung,exynos5420-hdmi" | ||
8 | - reg: physical base address of the hdmi and length of memory mapped | 9 | - reg: physical base address of the hdmi and length of memory mapped |
9 | region. | 10 | region. |
10 | - interrupts: interrupt number to the cpu. | 11 | - interrupts: interrupt number to the cpu. |
@@ -27,6 +28,7 @@ Required properties: | |||
27 | "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi". | 28 | "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi". |
28 | - ddc: phandle to the hdmi ddc node | 29 | - ddc: phandle to the hdmi ddc node |
29 | - phy: phandle to the hdmi phy node | 30 | - phy: phandle to the hdmi phy node |
31 | - samsung,syscon-phandle: phandle for system controller node for PMU. | ||
30 | 32 | ||
31 | Example: | 33 | Example: |
32 | 34 | ||
@@ -37,4 +39,5 @@ Example: | |||
37 | hpd-gpio = <&gpx3 7 1>; | 39 | hpd-gpio = <&gpx3 7 1>; |
38 | ddc = <&hdmi_ddc_node>; | 40 | ddc = <&hdmi_ddc_node>; |
39 | phy = <&hdmi_phy_node>; | 41 | phy = <&hdmi_phy_node>; |
42 | samsung,syscon-phandle = <&pmu_system_controller>; | ||
40 | }; | 43 | }; |
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index d1cc2f613a78..f5120046ff80 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -83,6 +83,8 @@ config DRM_KMS_CMA_HELPER | |||
83 | 83 | ||
84 | source "drivers/gpu/drm/i2c/Kconfig" | 84 | source "drivers/gpu/drm/i2c/Kconfig" |
85 | 85 | ||
86 | source "drivers/gpu/drm/bridge/Kconfig" | ||
87 | |||
86 | config DRM_TDFX | 88 | config DRM_TDFX |
87 | tristate "3dfx Banshee/Voodoo3+" | 89 | tristate "3dfx Banshee/Voodoo3+" |
88 | depends on DRM && PCI | 90 | depends on DRM && PCI |
@@ -199,5 +201,3 @@ source "drivers/gpu/drm/msm/Kconfig" | |||
199 | source "drivers/gpu/drm/tegra/Kconfig" | 201 | source "drivers/gpu/drm/tegra/Kconfig" |
200 | 202 | ||
201 | source "drivers/gpu/drm/panel/Kconfig" | 203 | source "drivers/gpu/drm/panel/Kconfig" |
202 | |||
203 | source "drivers/gpu/drm/bridge/Kconfig" | ||
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 5bf5bca94f56..178d2a9672a8 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
@@ -26,14 +26,14 @@ config DRM_EXYNOS_DMABUF | |||
26 | 26 | ||
27 | config DRM_EXYNOS_FIMD | 27 | config DRM_EXYNOS_FIMD |
28 | bool "Exynos DRM FIMD" | 28 | bool "Exynos DRM FIMD" |
29 | depends on DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM | 29 | depends on DRM_EXYNOS && !FB_S3C |
30 | select FB_MODE_HELPERS | 30 | select FB_MODE_HELPERS |
31 | help | 31 | help |
32 | Choose this option if you want to use Exynos FIMD for DRM. | 32 | Choose this option if you want to use Exynos FIMD for DRM. |
33 | 33 | ||
34 | config DRM_EXYNOS_DPI | 34 | config DRM_EXYNOS_DPI |
35 | bool "EXYNOS DRM parallel output support" | 35 | bool "EXYNOS DRM parallel output support" |
36 | depends on DRM_EXYNOS | 36 | depends on DRM_EXYNOS_FIMD |
37 | select DRM_PANEL | 37 | select DRM_PANEL |
38 | default n | 38 | default n |
39 | help | 39 | help |
@@ -41,7 +41,7 @@ config DRM_EXYNOS_DPI | |||
41 | 41 | ||
42 | config DRM_EXYNOS_DSI | 42 | config DRM_EXYNOS_DSI |
43 | bool "EXYNOS DRM MIPI-DSI driver support" | 43 | bool "EXYNOS DRM MIPI-DSI driver support" |
44 | depends on DRM_EXYNOS | 44 | depends on DRM_EXYNOS_FIMD |
45 | select DRM_MIPI_DSI | 45 | select DRM_MIPI_DSI |
46 | select DRM_PANEL | 46 | select DRM_PANEL |
47 | default n | 47 | default n |
@@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI | |||
50 | 50 | ||
51 | config DRM_EXYNOS_DP | 51 | config DRM_EXYNOS_DP |
52 | bool "EXYNOS DRM DP driver support" | 52 | bool "EXYNOS DRM DP driver support" |
53 | depends on DRM_EXYNOS && ARCH_EXYNOS | 53 | depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) |
54 | default DRM_EXYNOS | 54 | default DRM_EXYNOS |
55 | help | 55 | help |
56 | This enables support for DP device. | 56 | This enables support for DP device. |
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c deleted file mode 100644 index 6a8c84e7c839..000000000000 --- a/drivers/gpu/drm/exynos/exynos_ddc.c +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Samsung Electronics Co.Ltd | ||
3 | * Authors: | ||
4 | * Seung-Woo Kim <sw0312.kim@samsung.com> | ||
5 | * Inki Dae <inki.dae@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 | |||
14 | #include <drm/drmP.h> | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include "exynos_drm_drv.h" | ||
21 | #include "exynos_hdmi.h" | ||
22 | |||
23 | static int s5p_ddc_probe(struct i2c_client *client, | ||
24 | const struct i2c_device_id *dev_id) | ||
25 | { | ||
26 | hdmi_attach_ddc_client(client); | ||
27 | |||
28 | dev_info(&client->adapter->dev, | ||
29 | "attached %s into i2c adapter successfully\n", | ||
30 | client->name); | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static int s5p_ddc_remove(struct i2c_client *client) | ||
36 | { | ||
37 | dev_info(&client->adapter->dev, | ||
38 | "detached %s from i2c adapter successfully\n", | ||
39 | client->name); | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static struct of_device_id hdmiddc_match_types[] = { | ||
45 | { | ||
46 | .compatible = "samsung,exynos5-hdmiddc", | ||
47 | }, { | ||
48 | .compatible = "samsung,exynos4210-hdmiddc", | ||
49 | }, { | ||
50 | /* end node */ | ||
51 | } | ||
52 | }; | ||
53 | |||
54 | struct i2c_driver ddc_driver = { | ||
55 | .driver = { | ||
56 | .name = "exynos-hdmiddc", | ||
57 | .owner = THIS_MODULE, | ||
58 | .of_match_table = hdmiddc_match_types, | ||
59 | }, | ||
60 | .probe = s5p_ddc_probe, | ||
61 | .remove = s5p_ddc_remove, | ||
62 | .command = NULL, | ||
63 | }; | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index bb74472b4e4b..5e05dbc60082 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/of.h> | 20 | #include <linux/of.h> |
21 | #include <linux/of_gpio.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/component.h> | ||
21 | #include <linux/phy/phy.h> | 24 | #include <linux/phy/phy.h> |
22 | #include <video/of_display_timing.h> | 25 | #include <video/of_display_timing.h> |
23 | #include <video/of_videomode.h> | 26 | #include <video/of_videomode.h> |
@@ -141,15 +144,15 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) | |||
141 | return -EIO; | 144 | return -EIO; |
142 | } | 145 | } |
143 | 146 | ||
144 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, | 147 | exynos_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, |
145 | &test_vector); | 148 | &test_vector); |
146 | if (test_vector & DPCD_TEST_EDID_READ) { | 149 | if (test_vector & DP_TEST_LINK_EDID_READ) { |
147 | exynos_dp_write_byte_to_dpcd(dp, | 150 | exynos_dp_write_byte_to_dpcd(dp, |
148 | DPCD_ADDR_TEST_EDID_CHECKSUM, | 151 | DP_TEST_EDID_CHECKSUM, |
149 | edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); | 152 | edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); |
150 | exynos_dp_write_byte_to_dpcd(dp, | 153 | exynos_dp_write_byte_to_dpcd(dp, |
151 | DPCD_ADDR_TEST_RESPONSE, | 154 | DP_TEST_RESPONSE, |
152 | DPCD_TEST_EDID_CHECKSUM_WRITE); | 155 | DP_TEST_EDID_CHECKSUM_WRITE); |
153 | } | 156 | } |
154 | } else { | 157 | } else { |
155 | dev_info(dp->dev, "EDID data does not include any extensions.\n"); | 158 | dev_info(dp->dev, "EDID data does not include any extensions.\n"); |
@@ -171,15 +174,15 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) | |||
171 | } | 174 | } |
172 | 175 | ||
173 | exynos_dp_read_byte_from_dpcd(dp, | 176 | exynos_dp_read_byte_from_dpcd(dp, |
174 | DPCD_ADDR_TEST_REQUEST, | 177 | DP_TEST_REQUEST, |
175 | &test_vector); | 178 | &test_vector); |
176 | if (test_vector & DPCD_TEST_EDID_READ) { | 179 | if (test_vector & DP_TEST_LINK_EDID_READ) { |
177 | exynos_dp_write_byte_to_dpcd(dp, | 180 | exynos_dp_write_byte_to_dpcd(dp, |
178 | DPCD_ADDR_TEST_EDID_CHECKSUM, | 181 | DP_TEST_EDID_CHECKSUM, |
179 | edid[EDID_CHECKSUM]); | 182 | edid[EDID_CHECKSUM]); |
180 | exynos_dp_write_byte_to_dpcd(dp, | 183 | exynos_dp_write_byte_to_dpcd(dp, |
181 | DPCD_ADDR_TEST_RESPONSE, | 184 | DP_TEST_RESPONSE, |
182 | DPCD_TEST_EDID_CHECKSUM_WRITE); | 185 | DP_TEST_EDID_CHECKSUM_WRITE); |
183 | } | 186 | } |
184 | } | 187 | } |
185 | 188 | ||
@@ -193,8 +196,8 @@ static int exynos_dp_handle_edid(struct exynos_dp_device *dp) | |||
193 | int i; | 196 | int i; |
194 | int retval; | 197 | int retval; |
195 | 198 | ||
196 | /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | 199 | /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ |
197 | retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV, | 200 | retval = exynos_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, |
198 | 12, buf); | 201 | 12, buf); |
199 | if (retval) | 202 | if (retval) |
200 | return retval; | 203 | return retval; |
@@ -214,14 +217,14 @@ static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp, | |||
214 | { | 217 | { |
215 | u8 data; | 218 | u8 data; |
216 | 219 | ||
217 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data); | 220 | exynos_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); |
218 | 221 | ||
219 | if (enable) | 222 | if (enable) |
220 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, | 223 | exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, |
221 | DPCD_ENHANCED_FRAME_EN | | 224 | DP_LANE_COUNT_ENHANCED_FRAME_EN | |
222 | DPCD_LANE_COUNT_SET(data)); | 225 | DPCD_LANE_COUNT_SET(data)); |
223 | else | 226 | else |
224 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, | 227 | exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, |
225 | DPCD_LANE_COUNT_SET(data)); | 228 | DPCD_LANE_COUNT_SET(data)); |
226 | } | 229 | } |
227 | 230 | ||
@@ -230,7 +233,7 @@ static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp) | |||
230 | u8 data; | 233 | u8 data; |
231 | int retval; | 234 | int retval; |
232 | 235 | ||
233 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); | 236 | exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); |
234 | retval = DPCD_ENHANCED_FRAME_CAP(data); | 237 | retval = DPCD_ENHANCED_FRAME_CAP(data); |
235 | 238 | ||
236 | return retval; | 239 | return retval; |
@@ -250,8 +253,8 @@ static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp) | |||
250 | exynos_dp_set_training_pattern(dp, DP_NONE); | 253 | exynos_dp_set_training_pattern(dp, DP_NONE); |
251 | 254 | ||
252 | exynos_dp_write_byte_to_dpcd(dp, | 255 | exynos_dp_write_byte_to_dpcd(dp, |
253 | DPCD_ADDR_TRAINING_PATTERN_SET, | 256 | DP_TRAINING_PATTERN_SET, |
254 | DPCD_TRAINING_PATTERN_DISABLED); | 257 | DP_TRAINING_PATTERN_DISABLE); |
255 | } | 258 | } |
256 | 259 | ||
257 | static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, | 260 | static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, |
@@ -295,7 +298,7 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp) | |||
295 | /* Setup RX configuration */ | 298 | /* Setup RX configuration */ |
296 | buf[0] = dp->link_train.link_rate; | 299 | buf[0] = dp->link_train.link_rate; |
297 | buf[1] = dp->link_train.lane_count; | 300 | buf[1] = dp->link_train.lane_count; |
298 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, | 301 | retval = exynos_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, |
299 | 2, buf); | 302 | 2, buf); |
300 | if (retval) | 303 | if (retval) |
301 | return retval; | 304 | return retval; |
@@ -322,16 +325,16 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp) | |||
322 | 325 | ||
323 | /* Set RX training pattern */ | 326 | /* Set RX training pattern */ |
324 | retval = exynos_dp_write_byte_to_dpcd(dp, | 327 | retval = exynos_dp_write_byte_to_dpcd(dp, |
325 | DPCD_ADDR_TRAINING_PATTERN_SET, | 328 | DP_TRAINING_PATTERN_SET, |
326 | DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); | 329 | DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); |
327 | if (retval) | 330 | if (retval) |
328 | return retval; | 331 | return retval; |
329 | 332 | ||
330 | for (lane = 0; lane < lane_count; lane++) | 333 | for (lane = 0; lane < lane_count; lane++) |
331 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | | 334 | buf[lane] = DP_TRAIN_PRE_EMPHASIS_0 | |
332 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; | 335 | DP_TRAIN_VOLTAGE_SWING_400; |
333 | 336 | ||
334 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, | 337 | retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, |
335 | lane_count, buf); | 338 | lane_count, buf); |
336 | 339 | ||
337 | return retval; | 340 | return retval; |
@@ -352,7 +355,7 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) | |||
352 | 355 | ||
353 | for (lane = 0; lane < lane_count; lane++) { | 356 | for (lane = 0; lane < lane_count; lane++) { |
354 | lane_status = exynos_dp_get_lane_status(link_status, lane); | 357 | lane_status = exynos_dp_get_lane_status(link_status, lane); |
355 | if ((lane_status & DPCD_LANE_CR_DONE) == 0) | 358 | if ((lane_status & DP_LANE_CR_DONE) == 0) |
356 | return -EINVAL; | 359 | return -EINVAL; |
357 | } | 360 | } |
358 | return 0; | 361 | return 0; |
@@ -364,13 +367,13 @@ static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, | |||
364 | int lane; | 367 | int lane; |
365 | u8 lane_status; | 368 | u8 lane_status; |
366 | 369 | ||
367 | if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0) | 370 | if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) |
368 | return -EINVAL; | 371 | return -EINVAL; |
369 | 372 | ||
370 | for (lane = 0; lane < lane_count; lane++) { | 373 | for (lane = 0; lane < lane_count; lane++) { |
371 | lane_status = exynos_dp_get_lane_status(link_status, lane); | 374 | lane_status = exynos_dp_get_lane_status(link_status, lane); |
372 | lane_status &= DPCD_CHANNEL_EQ_BITS; | 375 | lane_status &= DP_CHANNEL_EQ_BITS; |
373 | if (lane_status != DPCD_CHANNEL_EQ_BITS) | 376 | if (lane_status != DP_CHANNEL_EQ_BITS) |
374 | return -EINVAL; | 377 | return -EINVAL; |
375 | } | 378 | } |
376 | 379 | ||
@@ -468,9 +471,9 @@ static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, | |||
468 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | 471 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); |
469 | 472 | ||
470 | if (voltage_swing == VOLTAGE_LEVEL_3) | 473 | if (voltage_swing == VOLTAGE_LEVEL_3) |
471 | training_lane |= DPCD_MAX_SWING_REACHED; | 474 | training_lane |= DP_TRAIN_MAX_SWING_REACHED; |
472 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | 475 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) |
473 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | 476 | training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; |
474 | 477 | ||
475 | dp->link_train.training_lane[lane] = training_lane; | 478 | dp->link_train.training_lane[lane] = training_lane; |
476 | } | 479 | } |
@@ -487,12 +490,12 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
487 | lane_count = dp->link_train.lane_count; | 490 | lane_count = dp->link_train.lane_count; |
488 | 491 | ||
489 | retval = exynos_dp_read_bytes_from_dpcd(dp, | 492 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
490 | DPCD_ADDR_LANE0_1_STATUS, 2, link_status); | 493 | DP_LANE0_1_STATUS, 2, link_status); |
491 | if (retval) | 494 | if (retval) |
492 | return retval; | 495 | return retval; |
493 | 496 | ||
494 | retval = exynos_dp_read_bytes_from_dpcd(dp, | 497 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
495 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | 498 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); |
496 | if (retval) | 499 | if (retval) |
497 | return retval; | 500 | return retval; |
498 | 501 | ||
@@ -501,9 +504,9 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
501 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | 504 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); |
502 | 505 | ||
503 | retval = exynos_dp_write_byte_to_dpcd(dp, | 506 | retval = exynos_dp_write_byte_to_dpcd(dp, |
504 | DPCD_ADDR_TRAINING_PATTERN_SET, | 507 | DP_TRAINING_PATTERN_SET, |
505 | DPCD_SCRAMBLING_DISABLED | | 508 | DP_LINK_SCRAMBLING_DISABLE | |
506 | DPCD_TRAINING_PATTERN_2); | 509 | DP_TRAINING_PATTERN_2); |
507 | if (retval) | 510 | if (retval) |
508 | return retval; | 511 | return retval; |
509 | 512 | ||
@@ -543,7 +546,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
543 | dp->link_train.training_lane[lane], lane); | 546 | dp->link_train.training_lane[lane], lane); |
544 | 547 | ||
545 | retval = exynos_dp_write_bytes_to_dpcd(dp, | 548 | retval = exynos_dp_write_bytes_to_dpcd(dp, |
546 | DPCD_ADDR_TRAINING_LANE0_SET, lane_count, | 549 | DP_TRAINING_LANE0_SET, lane_count, |
547 | dp->link_train.training_lane); | 550 | dp->link_train.training_lane); |
548 | if (retval) | 551 | if (retval) |
549 | return retval; | 552 | return retval; |
@@ -562,7 +565,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | |||
562 | lane_count = dp->link_train.lane_count; | 565 | lane_count = dp->link_train.lane_count; |
563 | 566 | ||
564 | retval = exynos_dp_read_bytes_from_dpcd(dp, | 567 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
565 | DPCD_ADDR_LANE0_1_STATUS, 2, link_status); | 568 | DP_LANE0_1_STATUS, 2, link_status); |
566 | if (retval) | 569 | if (retval) |
567 | return retval; | 570 | return retval; |
568 | 571 | ||
@@ -572,12 +575,12 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | |||
572 | } | 575 | } |
573 | 576 | ||
574 | retval = exynos_dp_read_bytes_from_dpcd(dp, | 577 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
575 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | 578 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); |
576 | if (retval) | 579 | if (retval) |
577 | return retval; | 580 | return retval; |
578 | 581 | ||
579 | retval = exynos_dp_read_byte_from_dpcd(dp, | 582 | retval = exynos_dp_read_byte_from_dpcd(dp, |
580 | DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align); | 583 | DP_LANE_ALIGN_STATUS_UPDATED, &link_align); |
581 | if (retval) | 584 | if (retval) |
582 | return retval; | 585 | return retval; |
583 | 586 | ||
@@ -619,7 +622,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | |||
619 | exynos_dp_set_lane_link_training(dp, | 622 | exynos_dp_set_lane_link_training(dp, |
620 | dp->link_train.training_lane[lane], lane); | 623 | dp->link_train.training_lane[lane], lane); |
621 | 624 | ||
622 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, | 625 | retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, |
623 | lane_count, dp->link_train.training_lane); | 626 | lane_count, dp->link_train.training_lane); |
624 | 627 | ||
625 | return retval; | 628 | return retval; |
@@ -634,7 +637,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | |||
634 | * For DP rev.1.1, Maximum link rate of Main Link lanes | 637 | * For DP rev.1.1, Maximum link rate of Main Link lanes |
635 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps | 638 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps |
636 | */ | 639 | */ |
637 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data); | 640 | exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); |
638 | *bandwidth = data; | 641 | *bandwidth = data; |
639 | } | 642 | } |
640 | 643 | ||
@@ -647,7 +650,7 @@ static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, | |||
647 | * For DP rev.1.1, Maximum number of Main Link lanes | 650 | * For DP rev.1.1, Maximum number of Main Link lanes |
648 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes | 651 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes |
649 | */ | 652 | */ |
650 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); | 653 | exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); |
651 | *lane_count = DPCD_MAX_LANE_COUNT(data); | 654 | *lane_count = DPCD_MAX_LANE_COUNT(data); |
652 | } | 655 | } |
653 | 656 | ||
@@ -819,20 +822,20 @@ static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable) | |||
819 | exynos_dp_enable_scrambling(dp); | 822 | exynos_dp_enable_scrambling(dp); |
820 | 823 | ||
821 | exynos_dp_read_byte_from_dpcd(dp, | 824 | exynos_dp_read_byte_from_dpcd(dp, |
822 | DPCD_ADDR_TRAINING_PATTERN_SET, | 825 | DP_TRAINING_PATTERN_SET, |
823 | &data); | 826 | &data); |
824 | exynos_dp_write_byte_to_dpcd(dp, | 827 | exynos_dp_write_byte_to_dpcd(dp, |
825 | DPCD_ADDR_TRAINING_PATTERN_SET, | 828 | DP_TRAINING_PATTERN_SET, |
826 | (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); | 829 | (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); |
827 | } else { | 830 | } else { |
828 | exynos_dp_disable_scrambling(dp); | 831 | exynos_dp_disable_scrambling(dp); |
829 | 832 | ||
830 | exynos_dp_read_byte_from_dpcd(dp, | 833 | exynos_dp_read_byte_from_dpcd(dp, |
831 | DPCD_ADDR_TRAINING_PATTERN_SET, | 834 | DP_TRAINING_PATTERN_SET, |
832 | &data); | 835 | &data); |
833 | exynos_dp_write_byte_to_dpcd(dp, | 836 | exynos_dp_write_byte_to_dpcd(dp, |
834 | DPCD_ADDR_TRAINING_PATTERN_SET, | 837 | DP_TRAINING_PATTERN_SET, |
835 | (u8)(data | DPCD_SCRAMBLING_DISABLED)); | 838 | (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); |
836 | } | 839 | } |
837 | } | 840 | } |
838 | 841 | ||
@@ -962,16 +965,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { | |||
962 | .best_encoder = exynos_dp_best_encoder, | 965 | .best_encoder = exynos_dp_best_encoder, |
963 | }; | 966 | }; |
964 | 967 | ||
965 | static int exynos_dp_initialize(struct exynos_drm_display *display, | ||
966 | struct drm_device *drm_dev) | ||
967 | { | ||
968 | struct exynos_dp_device *dp = display->ctx; | ||
969 | |||
970 | dp->drm_dev = drm_dev; | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static bool find_bridge(const char *compat, struct bridge_init *bridge) | 968 | static bool find_bridge(const char *compat, struct bridge_init *bridge) |
976 | { | 969 | { |
977 | bridge->client = NULL; | 970 | bridge->client = NULL; |
@@ -1099,7 +1092,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) | |||
1099 | } | 1092 | } |
1100 | 1093 | ||
1101 | static struct exynos_drm_display_ops exynos_dp_display_ops = { | 1094 | static struct exynos_drm_display_ops exynos_dp_display_ops = { |
1102 | .initialize = exynos_dp_initialize, | ||
1103 | .create_connector = exynos_dp_create_connector, | 1095 | .create_connector = exynos_dp_create_connector, |
1104 | .dpms = exynos_dp_dpms, | 1096 | .dpms = exynos_dp_dpms, |
1105 | }; | 1097 | }; |
@@ -1116,10 +1108,8 @@ static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) | |||
1116 | 1108 | ||
1117 | dp_video_config = devm_kzalloc(dev, | 1109 | dp_video_config = devm_kzalloc(dev, |
1118 | sizeof(*dp_video_config), GFP_KERNEL); | 1110 | sizeof(*dp_video_config), GFP_KERNEL); |
1119 | if (!dp_video_config) { | 1111 | if (!dp_video_config) |
1120 | dev_err(dev, "memory allocation for video config failed\n"); | ||
1121 | return ERR_PTR(-ENOMEM); | 1112 | return ERR_PTR(-ENOMEM); |
1122 | } | ||
1123 | 1113 | ||
1124 | dp_video_config->h_sync_polarity = | 1114 | dp_video_config->h_sync_polarity = |
1125 | of_property_read_bool(dp_node, "hsync-active-high"); | 1115 | of_property_read_bool(dp_node, "hsync-active-high"); |
@@ -1178,10 +1168,7 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) | |||
1178 | dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy"); | 1168 | dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy"); |
1179 | if (!dp_phy_node) { | 1169 | if (!dp_phy_node) { |
1180 | dp->phy = devm_phy_get(dp->dev, "dp"); | 1170 | dp->phy = devm_phy_get(dp->dev, "dp"); |
1181 | if (IS_ERR(dp->phy)) | 1171 | return PTR_ERR_OR_ZERO(dp->phy); |
1182 | return PTR_ERR(dp->phy); | ||
1183 | else | ||
1184 | return 0; | ||
1185 | } | 1172 | } |
1186 | 1173 | ||
1187 | if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { | 1174 | if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { |
@@ -1223,19 +1210,20 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) | |||
1223 | return 0; | 1210 | return 0; |
1224 | } | 1211 | } |
1225 | 1212 | ||
1226 | static int exynos_dp_probe(struct platform_device *pdev) | 1213 | static int exynos_dp_bind(struct device *dev, struct device *master, void *data) |
1227 | { | 1214 | { |
1215 | struct platform_device *pdev = to_platform_device(dev); | ||
1216 | struct drm_device *drm_dev = data; | ||
1228 | struct resource *res; | 1217 | struct resource *res; |
1229 | struct exynos_dp_device *dp; | 1218 | struct exynos_dp_device *dp; |
1219 | unsigned int irq_flags; | ||
1230 | 1220 | ||
1231 | int ret = 0; | 1221 | int ret = 0; |
1232 | 1222 | ||
1233 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), | 1223 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), |
1234 | GFP_KERNEL); | 1224 | GFP_KERNEL); |
1235 | if (!dp) { | 1225 | if (!dp) |
1236 | dev_err(&pdev->dev, "no memory for device data\n"); | ||
1237 | return -ENOMEM; | 1226 | return -ENOMEM; |
1238 | } | ||
1239 | 1227 | ||
1240 | dp->dev = &pdev->dev; | 1228 | dp->dev = &pdev->dev; |
1241 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | 1229 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
@@ -1266,7 +1254,30 @@ static int exynos_dp_probe(struct platform_device *pdev) | |||
1266 | if (IS_ERR(dp->reg_base)) | 1254 | if (IS_ERR(dp->reg_base)) |
1267 | return PTR_ERR(dp->reg_base); | 1255 | return PTR_ERR(dp->reg_base); |
1268 | 1256 | ||
1269 | dp->irq = platform_get_irq(pdev, 0); | 1257 | dp->hpd_gpio = of_get_named_gpio(dev->of_node, "samsung,hpd-gpio", 0); |
1258 | |||
1259 | if (gpio_is_valid(dp->hpd_gpio)) { | ||
1260 | /* | ||
1261 | * Set up the hotplug GPIO from the device tree as an interrupt. | ||
1262 | * Simply specifying a different interrupt in the device tree | ||
1263 | * doesn't work since we handle hotplug rather differently when | ||
1264 | * using a GPIO. We also need the actual GPIO specifier so | ||
1265 | * that we can get the current state of the GPIO. | ||
1266 | */ | ||
1267 | ret = devm_gpio_request_one(&pdev->dev, dp->hpd_gpio, GPIOF_IN, | ||
1268 | "hpd_gpio"); | ||
1269 | if (ret) { | ||
1270 | dev_err(&pdev->dev, "failed to get hpd gpio\n"); | ||
1271 | return ret; | ||
1272 | } | ||
1273 | dp->irq = gpio_to_irq(dp->hpd_gpio); | ||
1274 | irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | ||
1275 | } else { | ||
1276 | dp->hpd_gpio = -ENODEV; | ||
1277 | dp->irq = platform_get_irq(pdev, 0); | ||
1278 | irq_flags = 0; | ||
1279 | } | ||
1280 | |||
1270 | if (dp->irq == -ENXIO) { | 1281 | if (dp->irq == -ENXIO) { |
1271 | dev_err(&pdev->dev, "failed to get irq\n"); | 1282 | dev_err(&pdev->dev, "failed to get irq\n"); |
1272 | return -ENODEV; | 1283 | return -ENODEV; |
@@ -1278,28 +1289,61 @@ static int exynos_dp_probe(struct platform_device *pdev) | |||
1278 | 1289 | ||
1279 | exynos_dp_init_dp(dp); | 1290 | exynos_dp_init_dp(dp); |
1280 | 1291 | ||
1281 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, | 1292 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, |
1282 | "exynos-dp", dp); | 1293 | irq_flags, "exynos-dp", dp); |
1283 | if (ret) { | 1294 | if (ret) { |
1284 | dev_err(&pdev->dev, "failed to request irq\n"); | 1295 | dev_err(&pdev->dev, "failed to request irq\n"); |
1285 | return ret; | 1296 | return ret; |
1286 | } | 1297 | } |
1287 | disable_irq(dp->irq); | 1298 | disable_irq(dp->irq); |
1288 | 1299 | ||
1300 | dp->drm_dev = drm_dev; | ||
1289 | exynos_dp_display.ctx = dp; | 1301 | exynos_dp_display.ctx = dp; |
1290 | 1302 | ||
1291 | platform_set_drvdata(pdev, &exynos_dp_display); | 1303 | platform_set_drvdata(pdev, &exynos_dp_display); |
1292 | exynos_drm_display_register(&exynos_dp_display); | ||
1293 | 1304 | ||
1294 | return 0; | 1305 | return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display); |
1295 | } | 1306 | } |
1296 | 1307 | ||
1297 | static int exynos_dp_remove(struct platform_device *pdev) | 1308 | static void exynos_dp_unbind(struct device *dev, struct device *master, |
1309 | void *data) | ||
1298 | { | 1310 | { |
1299 | struct exynos_drm_display *display = platform_get_drvdata(pdev); | 1311 | struct exynos_drm_display *display = dev_get_drvdata(dev); |
1312 | struct exynos_dp_device *dp = display->ctx; | ||
1313 | struct drm_encoder *encoder = dp->encoder; | ||
1300 | 1314 | ||
1301 | exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); | 1315 | exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); |
1302 | exynos_drm_display_unregister(&exynos_dp_display); | 1316 | |
1317 | encoder->funcs->destroy(encoder); | ||
1318 | drm_connector_cleanup(&dp->connector); | ||
1319 | } | ||
1320 | |||
1321 | static const struct component_ops exynos_dp_ops = { | ||
1322 | .bind = exynos_dp_bind, | ||
1323 | .unbind = exynos_dp_unbind, | ||
1324 | }; | ||
1325 | |||
1326 | static int exynos_dp_probe(struct platform_device *pdev) | ||
1327 | { | ||
1328 | int ret; | ||
1329 | |||
1330 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, | ||
1331 | exynos_dp_display.type); | ||
1332 | if (ret) | ||
1333 | return ret; | ||
1334 | |||
1335 | ret = component_add(&pdev->dev, &exynos_dp_ops); | ||
1336 | if (ret) | ||
1337 | exynos_drm_component_del(&pdev->dev, | ||
1338 | EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
1339 | |||
1340 | return ret; | ||
1341 | } | ||
1342 | |||
1343 | static int exynos_dp_remove(struct platform_device *pdev) | ||
1344 | { | ||
1345 | component_del(&pdev->dev, &exynos_dp_ops); | ||
1346 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
1303 | 1347 | ||
1304 | return 0; | 1348 | return 0; |
1305 | } | 1349 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index d6a900d4ee40..02cc4f9ab903 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define _EXYNOS_DP_CORE_H | 14 | #define _EXYNOS_DP_CORE_H |
15 | 15 | ||
16 | #include <drm/drm_crtc.h> | 16 | #include <drm/drm_crtc.h> |
17 | #include <drm/drm_dp_helper.h> | ||
17 | #include <drm/exynos_drm.h> | 18 | #include <drm/exynos_drm.h> |
18 | 19 | ||
19 | #define DP_TIMEOUT_LOOP_COUNT 100 | 20 | #define DP_TIMEOUT_LOOP_COUNT 100 |
@@ -159,6 +160,7 @@ struct exynos_dp_device { | |||
159 | struct work_struct hotplug_work; | 160 | struct work_struct hotplug_work; |
160 | struct phy *phy; | 161 | struct phy *phy; |
161 | int dpms_mode; | 162 | int dpms_mode; |
163 | int hpd_gpio; | ||
162 | 164 | ||
163 | struct exynos_drm_panel_info panel; | 165 | struct exynos_drm_panel_info panel; |
164 | }; | 166 | }; |
@@ -261,69 +263,17 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); | |||
261 | #define EDID_EXTENSION_FLAG 0x7e | 263 | #define EDID_EXTENSION_FLAG 0x7e |
262 | #define EDID_CHECKSUM 0x7f | 264 | #define EDID_CHECKSUM 0x7f |
263 | 265 | ||
264 | /* Definition for DPCD Register */ | 266 | /* DP_MAX_LANE_COUNT */ |
265 | #define DPCD_ADDR_DPCD_REV 0x0000 | ||
266 | #define DPCD_ADDR_MAX_LINK_RATE 0x0001 | ||
267 | #define DPCD_ADDR_MAX_LANE_COUNT 0x0002 | ||
268 | #define DPCD_ADDR_LINK_BW_SET 0x0100 | ||
269 | #define DPCD_ADDR_LANE_COUNT_SET 0x0101 | ||
270 | #define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 | ||
271 | #define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 | ||
272 | #define DPCD_ADDR_LANE0_1_STATUS 0x0202 | ||
273 | #define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 | ||
274 | #define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 | ||
275 | #define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 | ||
276 | #define DPCD_ADDR_TEST_REQUEST 0x0218 | ||
277 | #define DPCD_ADDR_TEST_RESPONSE 0x0260 | ||
278 | #define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261 | ||
279 | #define DPCD_ADDR_SINK_POWER_STATE 0x0600 | ||
280 | |||
281 | /* DPCD_ADDR_MAX_LANE_COUNT */ | ||
282 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) | 267 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) |
283 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) | 268 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) |
284 | 269 | ||
285 | /* DPCD_ADDR_LANE_COUNT_SET */ | 270 | /* DP_LANE_COUNT_SET */ |
286 | #define DPCD_ENHANCED_FRAME_EN (0x1 << 7) | ||
287 | #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) | 271 | #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) |
288 | 272 | ||
289 | /* DPCD_ADDR_TRAINING_PATTERN_SET */ | 273 | /* DP_TRAINING_LANE0_SET */ |
290 | #define DPCD_SCRAMBLING_DISABLED (0x1 << 5) | ||
291 | #define DPCD_SCRAMBLING_ENABLED (0x0 << 5) | ||
292 | #define DPCD_TRAINING_PATTERN_2 (0x2 << 0) | ||
293 | #define DPCD_TRAINING_PATTERN_1 (0x1 << 0) | ||
294 | #define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0) | ||
295 | |||
296 | /* DPCD_ADDR_TRAINING_LANE0_SET */ | ||
297 | #define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5) | ||
298 | #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) | 274 | #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) |
299 | #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) | 275 | #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) |
300 | #define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3) | ||
301 | #define DPCD_MAX_SWING_REACHED (0x1 << 2) | ||
302 | #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) | 276 | #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) |
303 | #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) | 277 | #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) |
304 | #define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0) | ||
305 | |||
306 | /* DPCD_ADDR_LANE0_1_STATUS */ | ||
307 | #define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2) | ||
308 | #define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1) | ||
309 | #define DPCD_LANE_CR_DONE (0x1 << 0) | ||
310 | #define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \ | ||
311 | DPCD_LANE_CHANNEL_EQ_DONE|\ | ||
312 | DPCD_LANE_SYMBOL_LOCKED) | ||
313 | |||
314 | /* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */ | ||
315 | #define DPCD_LINK_STATUS_UPDATED (0x1 << 7) | ||
316 | #define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6) | ||
317 | #define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0) | ||
318 | |||
319 | /* DPCD_ADDR_TEST_REQUEST */ | ||
320 | #define DPCD_TEST_EDID_READ (0x1 << 2) | ||
321 | |||
322 | /* DPCD_ADDR_TEST_RESPONSE */ | ||
323 | #define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2) | ||
324 | |||
325 | /* DPCD_ADDR_SINK_POWER_STATE */ | ||
326 | #define DPCD_SET_POWER_STATE_D0 (0x1 << 0) | ||
327 | #define DPCD_SET_POWER_STATE_D4 (0x2 << 0) | ||
328 | 278 | ||
329 | #endif /* _EXYNOS_DP_CORE_H */ | 279 | #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 index b70da5052ff0..c1f87a2a9284 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_reg.c +++ b/drivers/gpu/drm/exynos/exynos_dp_reg.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/gpio.h> | ||
16 | 17 | ||
17 | #include "exynos_dp_core.h" | 18 | #include "exynos_dp_core.h" |
18 | #include "exynos_dp_reg.h" | 19 | #include "exynos_dp_reg.h" |
@@ -326,6 +327,9 @@ void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp) | |||
326 | { | 327 | { |
327 | u32 reg; | 328 | u32 reg; |
328 | 329 | ||
330 | if (gpio_is_valid(dp->hpd_gpio)) | ||
331 | return; | ||
332 | |||
329 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; | 333 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; |
330 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | 334 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); |
331 | 335 | ||
@@ -337,6 +341,9 @@ void exynos_dp_init_hpd(struct exynos_dp_device *dp) | |||
337 | { | 341 | { |
338 | u32 reg; | 342 | u32 reg; |
339 | 343 | ||
344 | if (gpio_is_valid(dp->hpd_gpio)) | ||
345 | return; | ||
346 | |||
340 | exynos_dp_clear_hotplug_interrupts(dp); | 347 | exynos_dp_clear_hotplug_interrupts(dp); |
341 | 348 | ||
342 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | 349 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); |
@@ -348,19 +355,27 @@ enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp) | |||
348 | { | 355 | { |
349 | u32 reg; | 356 | u32 reg; |
350 | 357 | ||
351 | /* Parse hotplug interrupt status register */ | 358 | if (gpio_is_valid(dp->hpd_gpio)) { |
352 | reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | 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); | ||
353 | 367 | ||
354 | if (reg & PLUG) | 368 | if (reg & PLUG) |
355 | return DP_IRQ_TYPE_HP_CABLE_IN; | 369 | return DP_IRQ_TYPE_HP_CABLE_IN; |
356 | 370 | ||
357 | if (reg & HPD_LOST) | 371 | if (reg & HPD_LOST) |
358 | return DP_IRQ_TYPE_HP_CABLE_OUT; | 372 | return DP_IRQ_TYPE_HP_CABLE_OUT; |
359 | 373 | ||
360 | if (reg & HOTPLUG_CHG) | 374 | if (reg & HOTPLUG_CHG) |
361 | return DP_IRQ_TYPE_HP_CHANGE; | 375 | return DP_IRQ_TYPE_HP_CHANGE; |
362 | 376 | ||
363 | return DP_IRQ_TYPE_UNKNOWN; | 377 | return DP_IRQ_TYPE_UNKNOWN; |
378 | } | ||
364 | } | 379 | } |
365 | 380 | ||
366 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) | 381 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) |
@@ -386,7 +401,7 @@ void exynos_dp_init_aux(struct exynos_dp_device *dp) | |||
386 | /* Disable AUX transaction H/W retry */ | 401 | /* Disable AUX transaction H/W retry */ |
387 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| | 402 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| |
388 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | 403 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; |
389 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ; | 404 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL); |
390 | 405 | ||
391 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ | 406 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ |
392 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); | 407 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); |
@@ -402,9 +417,14 @@ int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp) | |||
402 | { | 417 | { |
403 | u32 reg; | 418 | u32 reg; |
404 | 419 | ||
405 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | 420 | if (gpio_is_valid(dp->hpd_gpio)) { |
406 | if (reg & HPD_STATUS) | 421 | if (gpio_get_value(dp->hpd_gpio)) |
407 | return 0; | 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 | } | ||
408 | 428 | ||
409 | return -EINVAL; | 429 | return -EINVAL; |
410 | } | 430 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 0e9e06ce36b8..4c9f972eaa07 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c | |||
@@ -19,21 +19,19 @@ | |||
19 | #include "exynos_drm_fbdev.h" | 19 | #include "exynos_drm_fbdev.h" |
20 | 20 | ||
21 | static LIST_HEAD(exynos_drm_subdrv_list); | 21 | static LIST_HEAD(exynos_drm_subdrv_list); |
22 | static LIST_HEAD(exynos_drm_manager_list); | ||
23 | static LIST_HEAD(exynos_drm_display_list); | ||
24 | 22 | ||
25 | static int exynos_drm_create_enc_conn(struct drm_device *dev, | 23 | int exynos_drm_create_enc_conn(struct drm_device *dev, |
26 | struct exynos_drm_display *display) | 24 | struct exynos_drm_display *display) |
27 | { | 25 | { |
28 | struct drm_encoder *encoder; | 26 | struct drm_encoder *encoder; |
29 | struct exynos_drm_manager *manager; | ||
30 | int ret; | 27 | int ret; |
31 | unsigned long possible_crtcs = 0; | 28 | unsigned long possible_crtcs = 0; |
32 | 29 | ||
33 | /* Find possible crtcs for this display */ | 30 | ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type); |
34 | list_for_each_entry(manager, &exynos_drm_manager_list, list) | 31 | if (ret < 0) |
35 | if (manager->type == display->type) | 32 | return ret; |
36 | possible_crtcs |= 1 << manager->pipe; | 33 | |
34 | possible_crtcs |= 1 << ret; | ||
37 | 35 | ||
38 | /* create and initialize a encoder for this sub driver. */ | 36 | /* create and initialize a encoder for this sub driver. */ |
39 | encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); | 37 | encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); |
@@ -57,127 +55,29 @@ err_destroy_encoder: | |||
57 | return ret; | 55 | return ret; |
58 | } | 56 | } |
59 | 57 | ||
60 | static int exynos_drm_subdrv_probe(struct drm_device *dev, | 58 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) |
61 | struct exynos_drm_subdrv *subdrv) | ||
62 | { | ||
63 | if (subdrv->probe) { | ||
64 | int ret; | ||
65 | |||
66 | subdrv->drm_dev = dev; | ||
67 | |||
68 | /* | ||
69 | * this probe callback would be called by sub driver | ||
70 | * after setting of all resources to this sub driver, | ||
71 | * such as clock, irq and register map are done or by load() | ||
72 | * of exynos drm driver. | ||
73 | * | ||
74 | * P.S. note that this driver is considered for modularization. | ||
75 | */ | ||
76 | ret = subdrv->probe(dev, subdrv->dev); | ||
77 | if (ret) | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static void exynos_drm_subdrv_remove(struct drm_device *dev, | ||
85 | struct exynos_drm_subdrv *subdrv) | ||
86 | { | ||
87 | if (subdrv->remove) | ||
88 | subdrv->remove(dev, subdrv->dev); | ||
89 | } | ||
90 | |||
91 | int exynos_drm_initialize_managers(struct drm_device *dev) | ||
92 | { | 59 | { |
93 | struct exynos_drm_manager *manager, *n; | 60 | if (!subdrv) |
94 | int ret, pipe = 0; | 61 | return -EINVAL; |
95 | |||
96 | list_for_each_entry(manager, &exynos_drm_manager_list, list) { | ||
97 | if (manager->ops->initialize) { | ||
98 | ret = manager->ops->initialize(manager, dev, pipe); | ||
99 | if (ret) { | ||
100 | DRM_ERROR("Mgr init [%d] failed with %d\n", | ||
101 | manager->type, ret); | ||
102 | goto err; | ||
103 | } | ||
104 | } | ||
105 | 62 | ||
106 | manager->drm_dev = dev; | 63 | list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); |
107 | manager->pipe = pipe++; | ||
108 | 64 | ||
109 | ret = exynos_drm_crtc_create(manager); | ||
110 | if (ret) { | ||
111 | DRM_ERROR("CRTC create [%d] failed with %d\n", | ||
112 | manager->type, ret); | ||
113 | goto err; | ||
114 | } | ||
115 | } | ||
116 | return 0; | 65 | return 0; |
117 | |||
118 | err: | ||
119 | list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) { | ||
120 | if (pipe-- > 0) | ||
121 | exynos_drm_manager_unregister(manager); | ||
122 | else | ||
123 | list_del(&manager->list); | ||
124 | } | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | void exynos_drm_remove_managers(struct drm_device *dev) | ||
129 | { | ||
130 | struct exynos_drm_manager *manager, *n; | ||
131 | |||
132 | list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) | ||
133 | exynos_drm_manager_unregister(manager); | ||
134 | } | 66 | } |
67 | EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register); | ||
135 | 68 | ||
136 | int exynos_drm_initialize_displays(struct drm_device *dev) | 69 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) |
137 | { | 70 | { |
138 | struct exynos_drm_display *display, *n; | 71 | if (!subdrv) |
139 | int ret, initialized = 0; | 72 | return -EINVAL; |
140 | |||
141 | list_for_each_entry(display, &exynos_drm_display_list, list) { | ||
142 | if (display->ops->initialize) { | ||
143 | ret = display->ops->initialize(display, dev); | ||
144 | if (ret) { | ||
145 | DRM_ERROR("Display init [%d] failed with %d\n", | ||
146 | display->type, ret); | ||
147 | goto err; | ||
148 | } | ||
149 | } | ||
150 | 73 | ||
151 | initialized++; | 74 | list_del(&subdrv->list); |
152 | 75 | ||
153 | ret = exynos_drm_create_enc_conn(dev, display); | ||
154 | if (ret) { | ||
155 | DRM_ERROR("Encoder create [%d] failed with %d\n", | ||
156 | display->type, ret); | ||
157 | goto err; | ||
158 | } | ||
159 | } | ||
160 | return 0; | 76 | return 0; |
161 | |||
162 | err: | ||
163 | list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) { | ||
164 | if (initialized-- > 0) | ||
165 | exynos_drm_display_unregister(display); | ||
166 | else | ||
167 | list_del(&display->list); | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | void exynos_drm_remove_displays(struct drm_device *dev) | ||
173 | { | ||
174 | struct exynos_drm_display *display, *n; | ||
175 | |||
176 | list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) | ||
177 | exynos_drm_display_unregister(display); | ||
178 | } | 77 | } |
78 | EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister); | ||
179 | 79 | ||
180 | int exynos_drm_device_register(struct drm_device *dev) | 80 | int exynos_drm_device_subdrv_probe(struct drm_device *dev) |
181 | { | 81 | { |
182 | struct exynos_drm_subdrv *subdrv, *n; | 82 | struct exynos_drm_subdrv *subdrv, *n; |
183 | int err; | 83 | int err; |
@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev) | |||
186 | return -EINVAL; | 86 | return -EINVAL; |
187 | 87 | ||
188 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { | 88 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { |
189 | err = exynos_drm_subdrv_probe(dev, subdrv); | 89 | if (subdrv->probe) { |
190 | if (err) { | 90 | subdrv->drm_dev = dev; |
191 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); | 91 | |
192 | list_del(&subdrv->list); | 92 | /* |
193 | continue; | 93 | * this probe callback would be called by sub driver |
94 | * after setting of all resources to this sub driver, | ||
95 | * such as clock, irq and register map are done. | ||
96 | */ | ||
97 | err = subdrv->probe(dev, subdrv->dev); | ||
98 | if (err) { | ||
99 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); | ||
100 | list_del(&subdrv->list); | ||
101 | continue; | ||
102 | } | ||
194 | } | 103 | } |
195 | } | 104 | } |
196 | 105 | ||
197 | return 0; | 106 | return 0; |
198 | } | 107 | } |
199 | EXPORT_SYMBOL_GPL(exynos_drm_device_register); | 108 | EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe); |
200 | 109 | ||
201 | int exynos_drm_device_unregister(struct drm_device *dev) | 110 | int exynos_drm_device_subdrv_remove(struct drm_device *dev) |
202 | { | 111 | { |
203 | struct exynos_drm_subdrv *subdrv; | 112 | struct exynos_drm_subdrv *subdrv; |
204 | 113 | ||
@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev) | |||
208 | } | 117 | } |
209 | 118 | ||
210 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { | 119 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { |
211 | exynos_drm_subdrv_remove(dev, subdrv); | 120 | if (subdrv->remove) |
121 | subdrv->remove(dev, subdrv->dev); | ||
212 | } | 122 | } |
213 | 123 | ||
214 | return 0; | 124 | return 0; |
215 | } | 125 | } |
216 | EXPORT_SYMBOL_GPL(exynos_drm_device_unregister); | 126 | EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove); |
217 | |||
218 | int exynos_drm_manager_register(struct exynos_drm_manager *manager) | ||
219 | { | ||
220 | BUG_ON(!manager->ops); | ||
221 | list_add_tail(&manager->list, &exynos_drm_manager_list); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | int exynos_drm_manager_unregister(struct exynos_drm_manager *manager) | ||
226 | { | ||
227 | if (manager->ops->remove) | ||
228 | manager->ops->remove(manager); | ||
229 | |||
230 | list_del(&manager->list); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | int exynos_drm_display_register(struct exynos_drm_display *display) | ||
235 | { | ||
236 | BUG_ON(!display->ops); | ||
237 | list_add_tail(&display->list, &exynos_drm_display_list); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | int exynos_drm_display_unregister(struct exynos_drm_display *display) | ||
242 | { | ||
243 | if (display->ops->remove) | ||
244 | display->ops->remove(display); | ||
245 | |||
246 | list_del(&display->list); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) | ||
251 | { | ||
252 | if (!subdrv) | ||
253 | return -EINVAL; | ||
254 | |||
255 | list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register); | ||
260 | |||
261 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) | ||
262 | { | ||
263 | if (!subdrv) | ||
264 | return -EINVAL; | ||
265 | |||
266 | list_del(&subdrv->list); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister); | ||
271 | 127 | ||
272 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) | 128 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) |
273 | { | 129 | { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1ef5ab9c9d51..95c9435d0266 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c | |||
@@ -368,6 +368,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager) | |||
368 | return -ENOMEM; | 368 | return -ENOMEM; |
369 | } | 369 | } |
370 | 370 | ||
371 | manager->crtc = &exynos_crtc->drm_crtc; | ||
371 | crtc = &exynos_crtc->drm_crtc; | 372 | crtc = &exynos_crtc->drm_crtc; |
372 | 373 | ||
373 | private->crtc[manager->pipe] = crtc; | 374 | private->crtc[manager->pipe] = crtc; |
@@ -491,3 +492,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) | |||
491 | manager->ops->wait_for_vblank(manager); | 492 | manager->ops->wait_for_vblank(manager); |
492 | } | 493 | } |
493 | } | 494 | } |
495 | |||
496 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | ||
497 | unsigned int out_type) | ||
498 | { | ||
499 | struct drm_crtc *crtc; | ||
500 | |||
501 | list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { | ||
502 | struct exynos_drm_crtc *exynos_crtc; | ||
503 | |||
504 | exynos_crtc = to_exynos_crtc(crtc); | ||
505 | if (exynos_crtc->manager->type == out_type) | ||
506 | return exynos_crtc->manager->pipe; | ||
507 | } | ||
508 | |||
509 | return -EPERM; | ||
510 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index c27b66cc5d24..9f74b10a8a01 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h | |||
@@ -32,4 +32,8 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos); | |||
32 | void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos); | 32 | void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos); |
33 | void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos); | 33 | void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos); |
34 | 34 | ||
35 | /* This function gets pipe value to crtc device matched with out_type. */ | ||
36 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | ||
37 | unsigned int out_type); | ||
38 | |||
35 | #endif | 39 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 82e52c71bccc..f1b8587cc63d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c | |||
@@ -40,20 +40,10 @@ exynos_dpi_detect(struct drm_connector *connector, bool force) | |||
40 | { | 40 | { |
41 | struct exynos_dpi *ctx = connector_to_dpi(connector); | 41 | struct exynos_dpi *ctx = connector_to_dpi(connector); |
42 | 42 | ||
43 | /* panels supported only by boot-loader are always connected */ | 43 | if (!ctx->panel->connector) |
44 | if (!ctx->panel_node) | 44 | drm_panel_attach(ctx->panel, &ctx->connector); |
45 | return connector_status_connected; | ||
46 | 45 | ||
47 | if (!ctx->panel) { | 46 | return connector_status_connected; |
48 | ctx->panel = of_drm_find_panel(ctx->panel_node); | ||
49 | if (ctx->panel) | ||
50 | drm_panel_attach(ctx->panel, &ctx->connector); | ||
51 | } | ||
52 | |||
53 | if (ctx->panel) | ||
54 | return connector_status_connected; | ||
55 | |||
56 | return connector_status_disconnected; | ||
57 | } | 47 | } |
58 | 48 | ||
59 | static void exynos_dpi_connector_destroy(struct drm_connector *connector) | 49 | static void exynos_dpi_connector_destroy(struct drm_connector *connector) |
@@ -116,10 +106,7 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display, | |||
116 | 106 | ||
117 | ctx->encoder = encoder; | 107 | ctx->encoder = encoder; |
118 | 108 | ||
119 | if (ctx->panel_node) | 109 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
120 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; | ||
121 | else | ||
122 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
123 | 110 | ||
124 | ret = drm_connector_init(encoder->dev, connector, | 111 | ret = drm_connector_init(encoder->dev, connector, |
125 | &exynos_dpi_connector_funcs, | 112 | &exynos_dpi_connector_funcs, |
@@ -287,8 +274,10 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) | |||
287 | return -ENOMEM; | 274 | return -ENOMEM; |
288 | 275 | ||
289 | ret = of_get_videomode(dn, vm, 0); | 276 | ret = of_get_videomode(dn, vm, 0); |
290 | if (ret < 0) | 277 | if (ret < 0) { |
278 | devm_kfree(dev, vm); | ||
291 | return ret; | 279 | return ret; |
280 | } | ||
292 | 281 | ||
293 | ctx->vm = vm; | 282 | ctx->vm = vm; |
294 | 283 | ||
@@ -301,32 +290,58 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) | |||
301 | return 0; | 290 | return 0; |
302 | } | 291 | } |
303 | 292 | ||
304 | int exynos_dpi_probe(struct device *dev) | 293 | struct exynos_drm_display *exynos_dpi_probe(struct device *dev) |
305 | { | 294 | { |
306 | struct exynos_dpi *ctx; | 295 | struct exynos_dpi *ctx; |
307 | int ret; | 296 | int ret; |
308 | 297 | ||
298 | ret = exynos_drm_component_add(dev, | ||
299 | EXYNOS_DEVICE_TYPE_CONNECTOR, | ||
300 | exynos_dpi_display.type); | ||
301 | if (ret) | ||
302 | return ERR_PTR(ret); | ||
303 | |||
309 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | 304 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); |
310 | if (!ctx) | 305 | if (!ctx) |
311 | return -ENOMEM; | 306 | goto err_del_component; |
312 | 307 | ||
313 | ctx->dev = dev; | 308 | ctx->dev = dev; |
314 | exynos_dpi_display.ctx = ctx; | 309 | exynos_dpi_display.ctx = ctx; |
315 | ctx->dpms_mode = DRM_MODE_DPMS_OFF; | 310 | ctx->dpms_mode = DRM_MODE_DPMS_OFF; |
316 | 311 | ||
317 | ret = exynos_dpi_parse_dt(ctx); | 312 | ret = exynos_dpi_parse_dt(ctx); |
318 | if (ret < 0) | 313 | if (ret < 0) { |
319 | return ret; | 314 | devm_kfree(dev, ctx); |
315 | goto err_del_component; | ||
316 | } | ||
320 | 317 | ||
321 | exynos_drm_display_register(&exynos_dpi_display); | 318 | if (ctx->panel_node) { |
319 | ctx->panel = of_drm_find_panel(ctx->panel_node); | ||
320 | if (!ctx->panel) { | ||
321 | exynos_drm_component_del(dev, | ||
322 | EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
323 | return ERR_PTR(-EPROBE_DEFER); | ||
324 | } | ||
325 | } | ||
322 | 326 | ||
323 | return 0; | 327 | return &exynos_dpi_display; |
328 | |||
329 | err_del_component: | ||
330 | exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
331 | |||
332 | return NULL; | ||
324 | } | 333 | } |
325 | 334 | ||
326 | int exynos_dpi_remove(struct device *dev) | 335 | int exynos_dpi_remove(struct device *dev) |
327 | { | 336 | { |
337 | struct drm_encoder *encoder = exynos_dpi_display.encoder; | ||
338 | struct exynos_dpi *ctx = exynos_dpi_display.ctx; | ||
339 | |||
328 | exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF); | 340 | exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF); |
329 | exynos_drm_display_unregister(&exynos_dpi_display); | 341 | encoder->funcs->destroy(encoder); |
342 | drm_connector_cleanup(&ctx->connector); | ||
343 | |||
344 | exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
330 | 345 | ||
331 | return 0; | 346 | return 0; |
332 | } | 347 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 2d27ba23a6a8..5d225dd58a87 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <drm/drm_crtc_helper.h> | 16 | #include <drm/drm_crtc_helper.h> |
17 | 17 | ||
18 | #include <linux/anon_inodes.h> | 18 | #include <linux/anon_inodes.h> |
19 | #include <linux/component.h> | ||
19 | 20 | ||
20 | #include <drm/exynos_drm.h> | 21 | #include <drm/exynos_drm.h> |
21 | 22 | ||
@@ -40,9 +41,19 @@ | |||
40 | 41 | ||
41 | #define VBLANK_OFF_DELAY 50000 | 42 | #define VBLANK_OFF_DELAY 50000 |
42 | 43 | ||
43 | /* platform device pointer for eynos drm device. */ | ||
44 | static struct platform_device *exynos_drm_pdev; | 44 | static struct platform_device *exynos_drm_pdev; |
45 | 45 | ||
46 | static DEFINE_MUTEX(drm_component_lock); | ||
47 | static LIST_HEAD(drm_component_list); | ||
48 | |||
49 | struct component_dev { | ||
50 | struct list_head list; | ||
51 | struct device *crtc_dev; | ||
52 | struct device *conn_dev; | ||
53 | enum exynos_drm_output_type out_type; | ||
54 | unsigned int dev_type_flag; | ||
55 | }; | ||
56 | |||
46 | static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | 57 | static int exynos_drm_load(struct drm_device *dev, unsigned long flags) |
47 | { | 58 | { |
48 | struct exynos_drm_private *private; | 59 | struct exynos_drm_private *private; |
@@ -73,38 +84,21 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | |||
73 | 84 | ||
74 | exynos_drm_mode_config_init(dev); | 85 | exynos_drm_mode_config_init(dev); |
75 | 86 | ||
76 | ret = exynos_drm_initialize_managers(dev); | ||
77 | if (ret) | ||
78 | goto err_mode_config_cleanup; | ||
79 | |||
80 | for (nr = 0; nr < MAX_PLANE; nr++) { | 87 | for (nr = 0; nr < MAX_PLANE; nr++) { |
81 | struct drm_plane *plane; | 88 | struct drm_plane *plane; |
82 | unsigned long possible_crtcs = (1 << MAX_CRTC) - 1; | 89 | unsigned long possible_crtcs = (1 << MAX_CRTC) - 1; |
83 | 90 | ||
84 | plane = exynos_plane_init(dev, possible_crtcs, false); | 91 | plane = exynos_plane_init(dev, possible_crtcs, false); |
85 | if (!plane) | 92 | if (!plane) |
86 | goto err_manager_cleanup; | 93 | goto err_mode_config_cleanup; |
87 | } | 94 | } |
88 | 95 | ||
89 | ret = exynos_drm_initialize_displays(dev); | ||
90 | if (ret) | ||
91 | goto err_manager_cleanup; | ||
92 | |||
93 | /* init kms poll for handling hpd */ | 96 | /* init kms poll for handling hpd */ |
94 | drm_kms_helper_poll_init(dev); | 97 | drm_kms_helper_poll_init(dev); |
95 | 98 | ||
96 | ret = drm_vblank_init(dev, MAX_CRTC); | 99 | ret = drm_vblank_init(dev, MAX_CRTC); |
97 | if (ret) | 100 | if (ret) |
98 | goto err_display_cleanup; | 101 | goto err_mode_config_cleanup; |
99 | |||
100 | /* | ||
101 | * probe sub drivers such as display controller and hdmi driver, | ||
102 | * that were registered at probe() of platform driver | ||
103 | * to the sub driver and create encoder and connector for them. | ||
104 | */ | ||
105 | ret = exynos_drm_device_register(dev); | ||
106 | if (ret) | ||
107 | goto err_vblank; | ||
108 | 102 | ||
109 | /* setup possible_clones. */ | 103 | /* setup possible_clones. */ |
110 | exynos_drm_encoder_setup(dev); | 104 | exynos_drm_encoder_setup(dev); |
@@ -113,17 +107,25 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | |||
113 | 107 | ||
114 | platform_set_drvdata(dev->platformdev, dev); | 108 | platform_set_drvdata(dev->platformdev, dev); |
115 | 109 | ||
110 | /* Try to bind all sub drivers. */ | ||
111 | ret = component_bind_all(dev->dev, dev); | ||
112 | if (ret) | ||
113 | goto err_cleanup_vblank; | ||
114 | |||
115 | /* Probe non kms sub drivers and virtual display driver. */ | ||
116 | ret = exynos_drm_device_subdrv_probe(dev); | ||
117 | if (ret) | ||
118 | goto err_unbind_all; | ||
119 | |||
116 | /* force connectors detection */ | 120 | /* force connectors detection */ |
117 | drm_helper_hpd_irq_event(dev); | 121 | drm_helper_hpd_irq_event(dev); |
118 | 122 | ||
119 | return 0; | 123 | return 0; |
120 | 124 | ||
121 | err_vblank: | 125 | err_unbind_all: |
126 | component_unbind_all(dev->dev, dev); | ||
127 | err_cleanup_vblank: | ||
122 | drm_vblank_cleanup(dev); | 128 | drm_vblank_cleanup(dev); |
123 | err_display_cleanup: | ||
124 | exynos_drm_remove_displays(dev); | ||
125 | err_manager_cleanup: | ||
126 | exynos_drm_remove_managers(dev); | ||
127 | err_mode_config_cleanup: | 129 | err_mode_config_cleanup: |
128 | drm_mode_config_cleanup(dev); | 130 | drm_mode_config_cleanup(dev); |
129 | drm_release_iommu_mapping(dev); | 131 | drm_release_iommu_mapping(dev); |
@@ -135,17 +137,17 @@ err_free_private: | |||
135 | 137 | ||
136 | static int exynos_drm_unload(struct drm_device *dev) | 138 | static int exynos_drm_unload(struct drm_device *dev) |
137 | { | 139 | { |
140 | exynos_drm_device_subdrv_remove(dev); | ||
141 | |||
138 | exynos_drm_fbdev_fini(dev); | 142 | exynos_drm_fbdev_fini(dev); |
139 | exynos_drm_device_unregister(dev); | ||
140 | drm_vblank_cleanup(dev); | 143 | drm_vblank_cleanup(dev); |
141 | drm_kms_helper_poll_fini(dev); | 144 | drm_kms_helper_poll_fini(dev); |
142 | exynos_drm_remove_displays(dev); | ||
143 | exynos_drm_remove_managers(dev); | ||
144 | drm_mode_config_cleanup(dev); | 145 | drm_mode_config_cleanup(dev); |
145 | 146 | ||
146 | drm_release_iommu_mapping(dev); | 147 | drm_release_iommu_mapping(dev); |
147 | kfree(dev->dev_private); | 148 | kfree(dev->dev_private); |
148 | 149 | ||
150 | component_unbind_all(dev->dev, dev); | ||
149 | dev->dev_private = NULL; | 151 | dev->dev_private = NULL; |
150 | 152 | ||
151 | return 0; | 153 | return 0; |
@@ -183,9 +185,9 @@ static int exynos_drm_resume(struct drm_device *dev) | |||
183 | if (connector->funcs->dpms) | 185 | if (connector->funcs->dpms) |
184 | connector->funcs->dpms(connector, connector->dpms); | 186 | connector->funcs->dpms(connector, connector->dpms); |
185 | } | 187 | } |
188 | drm_modeset_unlock_all(dev); | ||
186 | 189 | ||
187 | drm_helper_resume_force_mode(dev); | 190 | drm_helper_resume_force_mode(dev); |
188 | drm_modeset_unlock_all(dev); | ||
189 | 191 | ||
190 | return 0; | 192 | return 0; |
191 | } | 193 | } |
@@ -323,8 +325,7 @@ static const struct file_operations exynos_drm_driver_fops = { | |||
323 | }; | 325 | }; |
324 | 326 | ||
325 | static struct drm_driver exynos_drm_driver = { | 327 | static struct drm_driver exynos_drm_driver = { |
326 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | | 328 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, |
327 | DRIVER_GEM | DRIVER_PRIME, | ||
328 | .load = exynos_drm_load, | 329 | .load = exynos_drm_load, |
329 | .unload = exynos_drm_unload, | 330 | .unload = exynos_drm_unload, |
330 | .suspend = exynos_drm_suspend, | 331 | .suspend = exynos_drm_suspend, |
@@ -355,27 +356,6 @@ static struct drm_driver exynos_drm_driver = { | |||
355 | .minor = DRIVER_MINOR, | 356 | .minor = DRIVER_MINOR, |
356 | }; | 357 | }; |
357 | 358 | ||
358 | static int exynos_drm_platform_probe(struct platform_device *pdev) | ||
359 | { | ||
360 | int ret; | ||
361 | |||
362 | ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | ||
363 | if (ret) | ||
364 | return ret; | ||
365 | |||
366 | pm_runtime_enable(&pdev->dev); | ||
367 | pm_runtime_get_sync(&pdev->dev); | ||
368 | |||
369 | return drm_platform_init(&exynos_drm_driver, pdev); | ||
370 | } | ||
371 | |||
372 | static int exynos_drm_platform_remove(struct platform_device *pdev) | ||
373 | { | ||
374 | drm_put_dev(platform_get_drvdata(pdev)); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | #ifdef CONFIG_PM_SLEEP | 359 | #ifdef CONFIG_PM_SLEEP |
380 | static int exynos_drm_sys_suspend(struct device *dev) | 360 | static int exynos_drm_sys_suspend(struct device *dev) |
381 | { | 361 | { |
@@ -400,196 +380,319 @@ static int exynos_drm_sys_resume(struct device *dev) | |||
400 | } | 380 | } |
401 | #endif | 381 | #endif |
402 | 382 | ||
403 | #ifdef CONFIG_PM_RUNTIME | 383 | static const struct dev_pm_ops exynos_drm_pm_ops = { |
404 | static int exynos_drm_runtime_suspend(struct device *dev) | 384 | SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) |
385 | }; | ||
386 | |||
387 | int exynos_drm_component_add(struct device *dev, | ||
388 | enum exynos_drm_device_type dev_type, | ||
389 | enum exynos_drm_output_type out_type) | ||
405 | { | 390 | { |
406 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 391 | struct component_dev *cdev; |
407 | pm_message_t message; | ||
408 | 392 | ||
409 | if (pm_runtime_suspended(dev)) | 393 | if (dev_type != EXYNOS_DEVICE_TYPE_CRTC && |
410 | return 0; | 394 | dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) { |
395 | DRM_ERROR("invalid device type.\n"); | ||
396 | return -EINVAL; | ||
397 | } | ||
411 | 398 | ||
412 | message.event = PM_EVENT_SUSPEND; | 399 | mutex_lock(&drm_component_lock); |
413 | return exynos_drm_suspend(drm_dev, message); | 400 | |
401 | /* | ||
402 | * Make sure to check if there is a component which has two device | ||
403 | * objects, for connector and for encoder/connector. | ||
404 | * It should make sure that crtc and encoder/connector drivers are | ||
405 | * ready before exynos drm core binds them. | ||
406 | */ | ||
407 | list_for_each_entry(cdev, &drm_component_list, list) { | ||
408 | if (cdev->out_type == out_type) { | ||
409 | /* | ||
410 | * If crtc and encoder/connector device objects are | ||
411 | * added already just return. | ||
412 | */ | ||
413 | if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC | | ||
414 | EXYNOS_DEVICE_TYPE_CONNECTOR)) { | ||
415 | mutex_unlock(&drm_component_lock); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) { | ||
420 | cdev->crtc_dev = dev; | ||
421 | cdev->dev_type_flag |= dev_type; | ||
422 | } | ||
423 | |||
424 | if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) { | ||
425 | cdev->conn_dev = dev; | ||
426 | cdev->dev_type_flag |= dev_type; | ||
427 | } | ||
428 | |||
429 | mutex_unlock(&drm_component_lock); | ||
430 | return 0; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | mutex_unlock(&drm_component_lock); | ||
435 | |||
436 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | ||
437 | if (!cdev) | ||
438 | return -ENOMEM; | ||
439 | |||
440 | if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) | ||
441 | cdev->crtc_dev = dev; | ||
442 | if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) | ||
443 | cdev->conn_dev = dev; | ||
444 | |||
445 | cdev->out_type = out_type; | ||
446 | cdev->dev_type_flag = dev_type; | ||
447 | |||
448 | mutex_lock(&drm_component_lock); | ||
449 | list_add_tail(&cdev->list, &drm_component_list); | ||
450 | mutex_unlock(&drm_component_lock); | ||
451 | |||
452 | return 0; | ||
414 | } | 453 | } |
415 | 454 | ||
416 | static int exynos_drm_runtime_resume(struct device *dev) | 455 | void exynos_drm_component_del(struct device *dev, |
456 | enum exynos_drm_device_type dev_type) | ||
417 | { | 457 | { |
418 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 458 | struct component_dev *cdev, *next; |
419 | 459 | ||
420 | if (!pm_runtime_suspended(dev)) | 460 | mutex_lock(&drm_component_lock); |
421 | return 0; | ||
422 | 461 | ||
423 | return exynos_drm_resume(drm_dev); | 462 | list_for_each_entry_safe(cdev, next, &drm_component_list, list) { |
463 | if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) { | ||
464 | if (cdev->crtc_dev == dev) { | ||
465 | cdev->crtc_dev = NULL; | ||
466 | cdev->dev_type_flag &= ~dev_type; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) { | ||
471 | if (cdev->conn_dev == dev) { | ||
472 | cdev->conn_dev = NULL; | ||
473 | cdev->dev_type_flag &= ~dev_type; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Release cdev object only in case that both of crtc and | ||
479 | * encoder/connector device objects are NULL. | ||
480 | */ | ||
481 | if (!cdev->crtc_dev && !cdev->conn_dev) { | ||
482 | list_del(&cdev->list); | ||
483 | kfree(cdev); | ||
484 | } | ||
485 | |||
486 | break; | ||
487 | } | ||
488 | |||
489 | mutex_unlock(&drm_component_lock); | ||
424 | } | 490 | } |
425 | #endif | ||
426 | 491 | ||
427 | static const struct dev_pm_ops exynos_drm_pm_ops = { | 492 | static int compare_of(struct device *dev, void *data) |
428 | SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) | 493 | { |
429 | SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend, | 494 | return dev == (struct device *)data; |
430 | exynos_drm_runtime_resume, NULL) | 495 | } |
431 | }; | ||
432 | 496 | ||
433 | static struct platform_driver exynos_drm_platform_driver = { | 497 | static int exynos_drm_add_components(struct device *dev, struct master *m) |
434 | .probe = exynos_drm_platform_probe, | 498 | { |
435 | .remove = exynos_drm_platform_remove, | 499 | struct component_dev *cdev; |
436 | .driver = { | 500 | unsigned int attach_cnt = 0; |
437 | .owner = THIS_MODULE, | 501 | |
438 | .name = "exynos-drm", | 502 | mutex_lock(&drm_component_lock); |
439 | .pm = &exynos_drm_pm_ops, | 503 | |
440 | }, | 504 | list_for_each_entry(cdev, &drm_component_list, list) { |
505 | int ret; | ||
506 | |||
507 | /* | ||
508 | * Add components to master only in case that crtc and | ||
509 | * encoder/connector device objects exist. | ||
510 | */ | ||
511 | if (!cdev->crtc_dev || !cdev->conn_dev) | ||
512 | continue; | ||
513 | |||
514 | attach_cnt++; | ||
515 | |||
516 | mutex_unlock(&drm_component_lock); | ||
517 | |||
518 | /* | ||
519 | * fimd and dpi modules have same device object so add | ||
520 | * only crtc device object in this case. | ||
521 | * | ||
522 | * TODO. if dpi module follows driver-model driver then | ||
523 | * below codes can be removed. | ||
524 | */ | ||
525 | if (cdev->crtc_dev == cdev->conn_dev) { | ||
526 | ret = component_master_add_child(m, compare_of, | ||
527 | cdev->crtc_dev); | ||
528 | if (ret < 0) | ||
529 | return ret; | ||
530 | |||
531 | goto out_lock; | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | * Do not chage below call order. | ||
536 | * crtc device first should be added to master because | ||
537 | * connector/encoder need pipe number of crtc when they | ||
538 | * are created. | ||
539 | */ | ||
540 | ret = component_master_add_child(m, compare_of, cdev->crtc_dev); | ||
541 | ret |= component_master_add_child(m, compare_of, | ||
542 | cdev->conn_dev); | ||
543 | if (ret < 0) | ||
544 | return ret; | ||
545 | |||
546 | out_lock: | ||
547 | mutex_lock(&drm_component_lock); | ||
548 | } | ||
549 | |||
550 | mutex_unlock(&drm_component_lock); | ||
551 | |||
552 | return attach_cnt ? 0 : -ENODEV; | ||
553 | } | ||
554 | |||
555 | static int exynos_drm_bind(struct device *dev) | ||
556 | { | ||
557 | return drm_platform_init(&exynos_drm_driver, to_platform_device(dev)); | ||
558 | } | ||
559 | |||
560 | static void exynos_drm_unbind(struct device *dev) | ||
561 | { | ||
562 | drm_put_dev(dev_get_drvdata(dev)); | ||
563 | } | ||
564 | |||
565 | static const struct component_master_ops exynos_drm_ops = { | ||
566 | .add_components = exynos_drm_add_components, | ||
567 | .bind = exynos_drm_bind, | ||
568 | .unbind = exynos_drm_unbind, | ||
441 | }; | 569 | }; |
442 | 570 | ||
443 | static int __init exynos_drm_init(void) | 571 | static int exynos_drm_platform_probe(struct platform_device *pdev) |
444 | { | 572 | { |
445 | int ret; | 573 | int ret; |
446 | 574 | ||
575 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
576 | exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls); | ||
577 | |||
578 | #ifdef CONFIG_DRM_EXYNOS_FIMD | ||
579 | ret = platform_driver_register(&fimd_driver); | ||
580 | if (ret < 0) | ||
581 | return ret; | ||
582 | #endif | ||
583 | |||
447 | #ifdef CONFIG_DRM_EXYNOS_DP | 584 | #ifdef CONFIG_DRM_EXYNOS_DP |
448 | ret = platform_driver_register(&dp_driver); | 585 | ret = platform_driver_register(&dp_driver); |
449 | if (ret < 0) | 586 | if (ret < 0) |
450 | goto out_dp; | 587 | goto err_unregister_fimd_drv; |
451 | #endif | 588 | #endif |
452 | 589 | ||
453 | #ifdef CONFIG_DRM_EXYNOS_DSI | 590 | #ifdef CONFIG_DRM_EXYNOS_DSI |
454 | ret = platform_driver_register(&dsi_driver); | 591 | ret = platform_driver_register(&dsi_driver); |
455 | if (ret < 0) | 592 | if (ret < 0) |
456 | goto out_dsi; | 593 | goto err_unregister_dp_drv; |
457 | #endif | ||
458 | |||
459 | #ifdef CONFIG_DRM_EXYNOS_FIMD | ||
460 | ret = platform_driver_register(&fimd_driver); | ||
461 | if (ret < 0) | ||
462 | goto out_fimd; | ||
463 | #endif | 594 | #endif |
464 | 595 | ||
465 | #ifdef CONFIG_DRM_EXYNOS_HDMI | 596 | #ifdef CONFIG_DRM_EXYNOS_HDMI |
466 | ret = platform_driver_register(&hdmi_driver); | ||
467 | if (ret < 0) | ||
468 | goto out_hdmi; | ||
469 | ret = platform_driver_register(&mixer_driver); | 597 | ret = platform_driver_register(&mixer_driver); |
470 | if (ret < 0) | 598 | if (ret < 0) |
471 | goto out_mixer; | 599 | goto err_unregister_dsi_drv; |
472 | #endif | 600 | ret = platform_driver_register(&hdmi_driver); |
473 | |||
474 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
475 | ret = platform_driver_register(&vidi_driver); | ||
476 | if (ret < 0) | 601 | if (ret < 0) |
477 | goto out_vidi; | 602 | goto err_unregister_mixer_drv; |
478 | #endif | 603 | #endif |
479 | 604 | ||
480 | #ifdef CONFIG_DRM_EXYNOS_G2D | 605 | #ifdef CONFIG_DRM_EXYNOS_G2D |
481 | ret = platform_driver_register(&g2d_driver); | 606 | ret = platform_driver_register(&g2d_driver); |
482 | if (ret < 0) | 607 | if (ret < 0) |
483 | goto out_g2d; | 608 | goto err_unregister_hdmi_drv; |
484 | #endif | 609 | #endif |
485 | 610 | ||
486 | #ifdef CONFIG_DRM_EXYNOS_FIMC | 611 | #ifdef CONFIG_DRM_EXYNOS_FIMC |
487 | ret = platform_driver_register(&fimc_driver); | 612 | ret = platform_driver_register(&fimc_driver); |
488 | if (ret < 0) | 613 | if (ret < 0) |
489 | goto out_fimc; | 614 | goto err_unregister_g2d_drv; |
490 | #endif | 615 | #endif |
491 | 616 | ||
492 | #ifdef CONFIG_DRM_EXYNOS_ROTATOR | 617 | #ifdef CONFIG_DRM_EXYNOS_ROTATOR |
493 | ret = platform_driver_register(&rotator_driver); | 618 | ret = platform_driver_register(&rotator_driver); |
494 | if (ret < 0) | 619 | if (ret < 0) |
495 | goto out_rotator; | 620 | goto err_unregister_fimc_drv; |
496 | #endif | 621 | #endif |
497 | 622 | ||
498 | #ifdef CONFIG_DRM_EXYNOS_GSC | 623 | #ifdef CONFIG_DRM_EXYNOS_GSC |
499 | ret = platform_driver_register(&gsc_driver); | 624 | ret = platform_driver_register(&gsc_driver); |
500 | if (ret < 0) | 625 | if (ret < 0) |
501 | goto out_gsc; | 626 | goto err_unregister_rotator_drv; |
502 | #endif | 627 | #endif |
503 | 628 | ||
504 | #ifdef CONFIG_DRM_EXYNOS_IPP | 629 | #ifdef CONFIG_DRM_EXYNOS_IPP |
505 | ret = platform_driver_register(&ipp_driver); | 630 | ret = platform_driver_register(&ipp_driver); |
506 | if (ret < 0) | 631 | if (ret < 0) |
507 | goto out_ipp; | 632 | goto err_unregister_gsc_drv; |
508 | 633 | ||
509 | ret = exynos_platform_device_ipp_register(); | 634 | ret = exynos_platform_device_ipp_register(); |
510 | if (ret < 0) | 635 | if (ret < 0) |
511 | goto out_ipp_dev; | 636 | goto err_unregister_ipp_drv; |
512 | #endif | 637 | #endif |
513 | 638 | ||
514 | ret = platform_driver_register(&exynos_drm_platform_driver); | 639 | ret = component_master_add(&pdev->dev, &exynos_drm_ops); |
515 | if (ret < 0) | 640 | if (ret < 0) |
516 | goto out_drm; | 641 | DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n"); |
517 | |||
518 | exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, | ||
519 | NULL, 0); | ||
520 | if (IS_ERR(exynos_drm_pdev)) { | ||
521 | ret = PTR_ERR(exynos_drm_pdev); | ||
522 | goto out; | ||
523 | } | ||
524 | 642 | ||
525 | return 0; | 643 | return 0; |
526 | 644 | ||
527 | out: | ||
528 | platform_driver_unregister(&exynos_drm_platform_driver); | ||
529 | |||
530 | out_drm: | ||
531 | #ifdef CONFIG_DRM_EXYNOS_IPP | 645 | #ifdef CONFIG_DRM_EXYNOS_IPP |
532 | exynos_platform_device_ipp_unregister(); | 646 | err_unregister_ipp_drv: |
533 | out_ipp_dev: | ||
534 | platform_driver_unregister(&ipp_driver); | 647 | platform_driver_unregister(&ipp_driver); |
535 | out_ipp: | 648 | err_unregister_gsc_drv: |
536 | #endif | 649 | #endif |
537 | 650 | ||
538 | #ifdef CONFIG_DRM_EXYNOS_GSC | 651 | #ifdef CONFIG_DRM_EXYNOS_GSC |
539 | platform_driver_unregister(&gsc_driver); | 652 | platform_driver_unregister(&gsc_driver); |
540 | out_gsc: | 653 | err_unregister_rotator_drv: |
541 | #endif | 654 | #endif |
542 | 655 | ||
543 | #ifdef CONFIG_DRM_EXYNOS_ROTATOR | 656 | #ifdef CONFIG_DRM_EXYNOS_ROTATOR |
544 | platform_driver_unregister(&rotator_driver); | 657 | platform_driver_unregister(&rotator_driver); |
545 | out_rotator: | 658 | err_unregister_fimc_drv: |
546 | #endif | 659 | #endif |
547 | 660 | ||
548 | #ifdef CONFIG_DRM_EXYNOS_FIMC | 661 | #ifdef CONFIG_DRM_EXYNOS_FIMC |
549 | platform_driver_unregister(&fimc_driver); | 662 | platform_driver_unregister(&fimc_driver); |
550 | out_fimc: | 663 | err_unregister_g2d_drv: |
551 | #endif | 664 | #endif |
552 | 665 | ||
553 | #ifdef CONFIG_DRM_EXYNOS_G2D | 666 | #ifdef CONFIG_DRM_EXYNOS_G2D |
554 | platform_driver_unregister(&g2d_driver); | 667 | platform_driver_unregister(&g2d_driver); |
555 | out_g2d: | 668 | err_unregister_hdmi_drv: |
556 | #endif | ||
557 | |||
558 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
559 | platform_driver_unregister(&vidi_driver); | ||
560 | out_vidi: | ||
561 | #endif | 669 | #endif |
562 | 670 | ||
563 | #ifdef CONFIG_DRM_EXYNOS_HDMI | 671 | #ifdef CONFIG_DRM_EXYNOS_HDMI |
564 | platform_driver_unregister(&mixer_driver); | ||
565 | out_mixer: | ||
566 | platform_driver_unregister(&hdmi_driver); | 672 | platform_driver_unregister(&hdmi_driver); |
567 | out_hdmi: | 673 | err_unregister_mixer_drv: |
568 | #endif | 674 | platform_driver_unregister(&mixer_driver); |
569 | 675 | err_unregister_dsi_drv: | |
570 | #ifdef CONFIG_DRM_EXYNOS_FIMD | ||
571 | platform_driver_unregister(&fimd_driver); | ||
572 | out_fimd: | ||
573 | #endif | 676 | #endif |
574 | 677 | ||
575 | #ifdef CONFIG_DRM_EXYNOS_DSI | 678 | #ifdef CONFIG_DRM_EXYNOS_DSI |
576 | platform_driver_unregister(&dsi_driver); | 679 | platform_driver_unregister(&dsi_driver); |
577 | out_dsi: | 680 | err_unregister_dp_drv: |
578 | #endif | 681 | #endif |
579 | 682 | ||
580 | #ifdef CONFIG_DRM_EXYNOS_DP | 683 | #ifdef CONFIG_DRM_EXYNOS_DP |
581 | platform_driver_unregister(&dp_driver); | 684 | platform_driver_unregister(&dp_driver); |
582 | out_dp: | 685 | err_unregister_fimd_drv: |
686 | #endif | ||
687 | |||
688 | #ifdef CONFIG_DRM_EXYNOS_FIMD | ||
689 | platform_driver_unregister(&fimd_driver); | ||
583 | #endif | 690 | #endif |
584 | return ret; | 691 | return ret; |
585 | } | 692 | } |
586 | 693 | ||
587 | static void __exit exynos_drm_exit(void) | 694 | static int exynos_drm_platform_remove(struct platform_device *pdev) |
588 | { | 695 | { |
589 | platform_device_unregister(exynos_drm_pdev); | ||
590 | |||
591 | platform_driver_unregister(&exynos_drm_platform_driver); | ||
592 | |||
593 | #ifdef CONFIG_DRM_EXYNOS_IPP | 696 | #ifdef CONFIG_DRM_EXYNOS_IPP |
594 | exynos_platform_device_ipp_unregister(); | 697 | exynos_platform_device_ipp_unregister(); |
595 | platform_driver_unregister(&ipp_driver); | 698 | platform_driver_unregister(&ipp_driver); |
@@ -616,10 +719,6 @@ static void __exit exynos_drm_exit(void) | |||
616 | platform_driver_unregister(&hdmi_driver); | 719 | platform_driver_unregister(&hdmi_driver); |
617 | #endif | 720 | #endif |
618 | 721 | ||
619 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
620 | platform_driver_unregister(&vidi_driver); | ||
621 | #endif | ||
622 | |||
623 | #ifdef CONFIG_DRM_EXYNOS_FIMD | 722 | #ifdef CONFIG_DRM_EXYNOS_FIMD |
624 | platform_driver_unregister(&fimd_driver); | 723 | platform_driver_unregister(&fimd_driver); |
625 | #endif | 724 | #endif |
@@ -631,6 +730,59 @@ static void __exit exynos_drm_exit(void) | |||
631 | #ifdef CONFIG_DRM_EXYNOS_DP | 730 | #ifdef CONFIG_DRM_EXYNOS_DP |
632 | platform_driver_unregister(&dp_driver); | 731 | platform_driver_unregister(&dp_driver); |
633 | #endif | 732 | #endif |
733 | component_master_del(&pdev->dev, &exynos_drm_ops); | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static struct platform_driver exynos_drm_platform_driver = { | ||
738 | .probe = exynos_drm_platform_probe, | ||
739 | .remove = exynos_drm_platform_remove, | ||
740 | .driver = { | ||
741 | .owner = THIS_MODULE, | ||
742 | .name = "exynos-drm", | ||
743 | .pm = &exynos_drm_pm_ops, | ||
744 | }, | ||
745 | }; | ||
746 | |||
747 | static int exynos_drm_init(void) | ||
748 | { | ||
749 | int ret; | ||
750 | |||
751 | exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, | ||
752 | NULL, 0); | ||
753 | if (IS_ERR(exynos_drm_pdev)) | ||
754 | return PTR_ERR(exynos_drm_pdev); | ||
755 | |||
756 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
757 | ret = exynos_drm_probe_vidi(); | ||
758 | if (ret < 0) | ||
759 | goto err_unregister_pd; | ||
760 | #endif | ||
761 | |||
762 | ret = platform_driver_register(&exynos_drm_platform_driver); | ||
763 | if (ret) | ||
764 | goto err_remove_vidi; | ||
765 | |||
766 | return 0; | ||
767 | |||
768 | err_unregister_pd: | ||
769 | platform_device_unregister(exynos_drm_pdev); | ||
770 | |||
771 | err_remove_vidi: | ||
772 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
773 | exynos_drm_remove_vidi(); | ||
774 | #endif | ||
775 | |||
776 | return ret; | ||
777 | } | ||
778 | |||
779 | static void exynos_drm_exit(void) | ||
780 | { | ||
781 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
782 | exynos_drm_remove_vidi(); | ||
783 | #endif | ||
784 | platform_device_unregister(exynos_drm_pdev); | ||
785 | platform_driver_unregister(&exynos_drm_platform_driver); | ||
634 | } | 786 | } |
635 | 787 | ||
636 | module_init(exynos_drm_init); | 788 | module_init(exynos_drm_init); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index ce3e6a30deaa..36535f398848 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -42,6 +42,13 @@ struct drm_connector; | |||
42 | 42 | ||
43 | extern unsigned int drm_vblank_offdelay; | 43 | extern unsigned int drm_vblank_offdelay; |
44 | 44 | ||
45 | /* This enumerates device type. */ | ||
46 | enum exynos_drm_device_type { | ||
47 | EXYNOS_DEVICE_TYPE_NONE, | ||
48 | EXYNOS_DEVICE_TYPE_CRTC, | ||
49 | EXYNOS_DEVICE_TYPE_CONNECTOR, | ||
50 | }; | ||
51 | |||
45 | /* this enumerates display type. */ | 52 | /* this enumerates display type. */ |
46 | enum exynos_drm_output_type { | 53 | enum exynos_drm_output_type { |
47 | EXYNOS_DISPLAY_TYPE_NONE, | 54 | EXYNOS_DISPLAY_TYPE_NONE, |
@@ -122,7 +129,6 @@ struct exynos_drm_overlay { | |||
122 | * Exynos DRM Display Structure. | 129 | * Exynos DRM Display Structure. |
123 | * - this structure is common to analog tv, digital tv and lcd panel. | 130 | * - this structure is common to analog tv, digital tv and lcd panel. |
124 | * | 131 | * |
125 | * @initialize: initializes the display with drm_dev | ||
126 | * @remove: cleans up the display for removal | 132 | * @remove: cleans up the display for removal |
127 | * @mode_fixup: fix mode data comparing to hw specific display mode. | 133 | * @mode_fixup: fix mode data comparing to hw specific display mode. |
128 | * @mode_set: convert drm_display_mode to hw specific display mode and | 134 | * @mode_set: convert drm_display_mode to hw specific display mode and |
@@ -133,8 +139,6 @@ struct exynos_drm_overlay { | |||
133 | */ | 139 | */ |
134 | struct exynos_drm_display; | 140 | struct exynos_drm_display; |
135 | struct exynos_drm_display_ops { | 141 | struct exynos_drm_display_ops { |
136 | int (*initialize)(struct exynos_drm_display *display, | ||
137 | struct drm_device *drm_dev); | ||
138 | int (*create_connector)(struct exynos_drm_display *display, | 142 | int (*create_connector)(struct exynos_drm_display *display, |
139 | struct drm_encoder *encoder); | 143 | struct drm_encoder *encoder); |
140 | void (*remove)(struct exynos_drm_display *display); | 144 | void (*remove)(struct exynos_drm_display *display); |
@@ -172,8 +176,6 @@ struct exynos_drm_display { | |||
172 | /* | 176 | /* |
173 | * Exynos drm manager ops | 177 | * Exynos drm manager ops |
174 | * | 178 | * |
175 | * @initialize: initializes the manager with drm_dev | ||
176 | * @remove: cleans up the manager for removal | ||
177 | * @dpms: control device power. | 179 | * @dpms: control device power. |
178 | * @mode_fixup: fix mode data before applying it | 180 | * @mode_fixup: fix mode data before applying it |
179 | * @mode_set: set the given mode to the manager | 181 | * @mode_set: set the given mode to the manager |
@@ -189,9 +191,6 @@ struct exynos_drm_display { | |||
189 | */ | 191 | */ |
190 | struct exynos_drm_manager; | 192 | struct exynos_drm_manager; |
191 | struct exynos_drm_manager_ops { | 193 | struct exynos_drm_manager_ops { |
192 | int (*initialize)(struct exynos_drm_manager *mgr, | ||
193 | struct drm_device *drm_dev, int pipe); | ||
194 | void (*remove)(struct exynos_drm_manager *mgr); | ||
195 | void (*dpms)(struct exynos_drm_manager *mgr, int mode); | 194 | void (*dpms)(struct exynos_drm_manager *mgr, int mode); |
196 | bool (*mode_fixup)(struct exynos_drm_manager *mgr, | 195 | bool (*mode_fixup)(struct exynos_drm_manager *mgr, |
197 | const struct drm_display_mode *mode, | 196 | const struct drm_display_mode *mode, |
@@ -215,6 +214,7 @@ struct exynos_drm_manager_ops { | |||
215 | * @list: the list entry for this manager | 214 | * @list: the list entry for this manager |
216 | * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. | 215 | * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. |
217 | * @drm_dev: pointer to the drm device | 216 | * @drm_dev: pointer to the drm device |
217 | * @crtc: crtc object. | ||
218 | * @pipe: the pipe number for this crtc/manager | 218 | * @pipe: the pipe number for this crtc/manager |
219 | * @ops: pointer to callbacks for exynos drm specific functionality | 219 | * @ops: pointer to callbacks for exynos drm specific functionality |
220 | * @ctx: A pointer to the manager's implementation specific context | 220 | * @ctx: A pointer to the manager's implementation specific context |
@@ -223,6 +223,7 @@ struct exynos_drm_manager { | |||
223 | struct list_head list; | 223 | struct list_head list; |
224 | enum exynos_drm_output_type type; | 224 | enum exynos_drm_output_type type; |
225 | struct drm_device *drm_dev; | 225 | struct drm_device *drm_dev; |
226 | struct drm_crtc *crtc; | ||
226 | int pipe; | 227 | int pipe; |
227 | struct exynos_drm_manager_ops *ops; | 228 | struct exynos_drm_manager_ops *ops; |
228 | void *ctx; | 229 | void *ctx; |
@@ -254,6 +255,7 @@ struct drm_exynos_file_private { | |||
254 | * otherwise default one. | 255 | * otherwise default one. |
255 | * @da_space_size: size of device address space. | 256 | * @da_space_size: size of device address space. |
256 | * if 0 then default value is used for it. | 257 | * if 0 then default value is used for it. |
258 | * @pipe: the pipe number for this crtc/manager. | ||
257 | */ | 259 | */ |
258 | struct exynos_drm_private { | 260 | struct exynos_drm_private { |
259 | struct drm_fb_helper *fb_helper; | 261 | struct drm_fb_helper *fb_helper; |
@@ -271,6 +273,8 @@ struct exynos_drm_private { | |||
271 | 273 | ||
272 | unsigned long da_start; | 274 | unsigned long da_start; |
273 | unsigned long da_space_size; | 275 | unsigned long da_space_size; |
276 | |||
277 | unsigned int pipe; | ||
274 | }; | 278 | }; |
275 | 279 | ||
276 | /* | 280 | /* |
@@ -281,11 +285,11 @@ struct exynos_drm_private { | |||
281 | * @drm_dev: pointer to drm_device and this pointer would be set | 285 | * @drm_dev: pointer to drm_device and this pointer would be set |
282 | * when sub driver calls exynos_drm_subdrv_register(). | 286 | * when sub driver calls exynos_drm_subdrv_register(). |
283 | * @manager: subdrv has its own manager to control a hardware appropriately | 287 | * @manager: subdrv has its own manager to control a hardware appropriately |
284 | * and we can access a hardware drawing on this manager. | 288 | * and we can access a hardware drawing on this manager. |
285 | * @probe: this callback would be called by exynos drm driver after | 289 | * @probe: this callback would be called by exynos drm driver after |
286 | * subdrv is registered to it. | 290 | * subdrv is registered to it. |
287 | * @remove: this callback is used to release resources created | 291 | * @remove: this callback is used to release resources created |
288 | * by probe callback. | 292 | * by probe callback. |
289 | * @open: this would be called with drm device file open. | 293 | * @open: this would be called with drm device file open. |
290 | * @close: this would be called with drm device file close. | 294 | * @close: this would be called with drm device file close. |
291 | */ | 295 | */ |
@@ -302,39 +306,14 @@ struct exynos_drm_subdrv { | |||
302 | struct drm_file *file); | 306 | struct drm_file *file); |
303 | }; | 307 | }; |
304 | 308 | ||
305 | /* | 309 | /* This function would be called by non kms drivers such as g2d and ipp. */ |
306 | * this function calls a probe callback registered to sub driver list and | ||
307 | * create its own encoder and connector and then set drm_device object | ||
308 | * to global one. | ||
309 | */ | ||
310 | int exynos_drm_device_register(struct drm_device *dev); | ||
311 | /* | ||
312 | * this function calls a remove callback registered to sub driver list and | ||
313 | * destroy its own encoder and connetor. | ||
314 | */ | ||
315 | int exynos_drm_device_unregister(struct drm_device *dev); | ||
316 | |||
317 | int exynos_drm_initialize_managers(struct drm_device *dev); | ||
318 | void exynos_drm_remove_managers(struct drm_device *dev); | ||
319 | int exynos_drm_initialize_displays(struct drm_device *dev); | ||
320 | void exynos_drm_remove_displays(struct drm_device *dev); | ||
321 | |||
322 | int exynos_drm_manager_register(struct exynos_drm_manager *manager); | ||
323 | int exynos_drm_manager_unregister(struct exynos_drm_manager *manager); | ||
324 | int exynos_drm_display_register(struct exynos_drm_display *display); | ||
325 | int exynos_drm_display_unregister(struct exynos_drm_display *display); | ||
326 | |||
327 | /* | ||
328 | * this function would be called by sub drivers such as display controller | ||
329 | * or hdmi driver to register this sub driver object to exynos drm driver | ||
330 | * and when a sub driver is registered to exynos drm driver a probe callback | ||
331 | * of the sub driver is called and creates its own encoder and connector. | ||
332 | */ | ||
333 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); | 310 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); |
334 | 311 | ||
335 | /* this function removes subdrv list from exynos drm driver */ | 312 | /* this function removes subdrv list from exynos drm driver */ |
336 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); | 313 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); |
337 | 314 | ||
315 | int exynos_drm_device_subdrv_probe(struct drm_device *dev); | ||
316 | int exynos_drm_device_subdrv_remove(struct drm_device *dev); | ||
338 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); | 317 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); |
339 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); | 318 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); |
340 | 319 | ||
@@ -360,18 +339,40 @@ int exynos_platform_device_ipp_register(void); | |||
360 | void exynos_platform_device_ipp_unregister(void); | 339 | void exynos_platform_device_ipp_unregister(void); |
361 | 340 | ||
362 | #ifdef CONFIG_DRM_EXYNOS_DPI | 341 | #ifdef CONFIG_DRM_EXYNOS_DPI |
363 | int exynos_dpi_probe(struct device *dev); | 342 | struct exynos_drm_display * exynos_dpi_probe(struct device *dev); |
364 | int exynos_dpi_remove(struct device *dev); | 343 | int exynos_dpi_remove(struct device *dev); |
365 | #else | 344 | #else |
366 | static inline int exynos_dpi_probe(struct device *dev) { return 0; } | 345 | static inline struct exynos_drm_display * |
346 | exynos_dpi_probe(struct device *dev) { return 0; } | ||
367 | static inline int exynos_dpi_remove(struct device *dev) { return 0; } | 347 | static inline int exynos_dpi_remove(struct device *dev) { return 0; } |
368 | #endif | 348 | #endif |
369 | 349 | ||
350 | /* | ||
351 | * this function registers exynos drm vidi platform device/driver. | ||
352 | */ | ||
353 | int exynos_drm_probe_vidi(void); | ||
354 | |||
355 | /* | ||
356 | * this function unregister exynos drm vidi platform device/driver. | ||
357 | */ | ||
358 | void exynos_drm_remove_vidi(void); | ||
359 | |||
360 | /* This function creates a encoder and a connector, and initializes them. */ | ||
361 | int exynos_drm_create_enc_conn(struct drm_device *dev, | ||
362 | struct exynos_drm_display *display); | ||
363 | |||
364 | int exynos_drm_component_add(struct device *dev, | ||
365 | enum exynos_drm_device_type dev_type, | ||
366 | enum exynos_drm_output_type out_type); | ||
367 | |||
368 | void exynos_drm_component_del(struct device *dev, | ||
369 | enum exynos_drm_device_type dev_type); | ||
370 | |||
371 | extern struct platform_driver fimd_driver; | ||
370 | extern struct platform_driver dp_driver; | 372 | extern struct platform_driver dp_driver; |
371 | extern struct platform_driver dsi_driver; | 373 | extern struct platform_driver dsi_driver; |
372 | extern struct platform_driver fimd_driver; | ||
373 | extern struct platform_driver hdmi_driver; | ||
374 | extern struct platform_driver mixer_driver; | 374 | extern struct platform_driver mixer_driver; |
375 | extern struct platform_driver hdmi_driver; | ||
375 | extern struct platform_driver exynos_drm_common_hdmi_driver; | 376 | extern struct platform_driver exynos_drm_common_hdmi_driver; |
376 | extern struct platform_driver vidi_driver; | 377 | extern struct platform_driver vidi_driver; |
377 | extern struct platform_driver g2d_driver; | 378 | extern struct platform_driver g2d_driver; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 4ac438187568..6302aa64f6c1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/irq.h> | 19 | #include <linux/irq.h> |
20 | #include <linux/phy/phy.h> | 20 | #include <linux/phy/phy.h> |
21 | #include <linux/regulator/consumer.h> | 21 | #include <linux/regulator/consumer.h> |
22 | #include <linux/component.h> | ||
22 | 23 | ||
23 | #include <video/mipi_display.h> | 24 | #include <video/mipi_display.h> |
24 | #include <video/videomode.h> | 25 | #include <video/videomode.h> |
@@ -1378,16 +1379,60 @@ end: | |||
1378 | return ret; | 1379 | return ret; |
1379 | } | 1380 | } |
1380 | 1381 | ||
1382 | static int exynos_dsi_bind(struct device *dev, struct device *master, | ||
1383 | void *data) | ||
1384 | { | ||
1385 | struct drm_device *drm_dev = data; | ||
1386 | struct exynos_dsi *dsi; | ||
1387 | int ret; | ||
1388 | |||
1389 | ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display); | ||
1390 | if (ret) { | ||
1391 | DRM_ERROR("Encoder create [%d] failed with %d\n", | ||
1392 | exynos_dsi_display.type, ret); | ||
1393 | return ret; | ||
1394 | } | ||
1395 | |||
1396 | dsi = exynos_dsi_display.ctx; | ||
1397 | |||
1398 | return mipi_dsi_host_register(&dsi->dsi_host); | ||
1399 | } | ||
1400 | |||
1401 | static void exynos_dsi_unbind(struct device *dev, struct device *master, | ||
1402 | void *data) | ||
1403 | { | ||
1404 | struct exynos_dsi *dsi = exynos_dsi_display.ctx; | ||
1405 | struct drm_encoder *encoder = dsi->encoder; | ||
1406 | |||
1407 | exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF); | ||
1408 | |||
1409 | mipi_dsi_host_unregister(&dsi->dsi_host); | ||
1410 | |||
1411 | encoder->funcs->destroy(encoder); | ||
1412 | drm_connector_cleanup(&dsi->connector); | ||
1413 | } | ||
1414 | |||
1415 | static const struct component_ops exynos_dsi_component_ops = { | ||
1416 | .bind = exynos_dsi_bind, | ||
1417 | .unbind = exynos_dsi_unbind, | ||
1418 | }; | ||
1419 | |||
1381 | static int exynos_dsi_probe(struct platform_device *pdev) | 1420 | static int exynos_dsi_probe(struct platform_device *pdev) |
1382 | { | 1421 | { |
1383 | struct resource *res; | 1422 | struct resource *res; |
1384 | struct exynos_dsi *dsi; | 1423 | struct exynos_dsi *dsi; |
1385 | int ret; | 1424 | int ret; |
1386 | 1425 | ||
1426 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, | ||
1427 | exynos_dsi_display.type); | ||
1428 | if (ret) | ||
1429 | return ret; | ||
1430 | |||
1387 | dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); | 1431 | dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); |
1388 | if (!dsi) { | 1432 | if (!dsi) { |
1389 | dev_err(&pdev->dev, "failed to allocate dsi object.\n"); | 1433 | dev_err(&pdev->dev, "failed to allocate dsi object.\n"); |
1390 | return -ENOMEM; | 1434 | ret = -ENOMEM; |
1435 | goto err_del_component; | ||
1391 | } | 1436 | } |
1392 | 1437 | ||
1393 | init_completion(&dsi->completed); | 1438 | init_completion(&dsi->completed); |
@@ -1401,7 +1446,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
1401 | 1446 | ||
1402 | ret = exynos_dsi_parse_dt(dsi); | 1447 | ret = exynos_dsi_parse_dt(dsi); |
1403 | if (ret) | 1448 | if (ret) |
1404 | return ret; | 1449 | goto err_del_component; |
1405 | 1450 | ||
1406 | dsi->supplies[0].supply = "vddcore"; | 1451 | dsi->supplies[0].supply = "vddcore"; |
1407 | dsi->supplies[1].supply = "vddio"; | 1452 | dsi->supplies[1].supply = "vddio"; |
@@ -1415,32 +1460,37 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
1415 | dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk"); | 1460 | dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk"); |
1416 | if (IS_ERR(dsi->pll_clk)) { | 1461 | if (IS_ERR(dsi->pll_clk)) { |
1417 | dev_info(&pdev->dev, "failed to get dsi pll input clock\n"); | 1462 | dev_info(&pdev->dev, "failed to get dsi pll input clock\n"); |
1418 | return -EPROBE_DEFER; | 1463 | ret = PTR_ERR(dsi->pll_clk); |
1464 | goto err_del_component; | ||
1419 | } | 1465 | } |
1420 | 1466 | ||
1421 | dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); | 1467 | dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); |
1422 | if (IS_ERR(dsi->bus_clk)) { | 1468 | if (IS_ERR(dsi->bus_clk)) { |
1423 | dev_info(&pdev->dev, "failed to get dsi bus clock\n"); | 1469 | dev_info(&pdev->dev, "failed to get dsi bus clock\n"); |
1424 | return -EPROBE_DEFER; | 1470 | ret = PTR_ERR(dsi->bus_clk); |
1471 | goto err_del_component; | ||
1425 | } | 1472 | } |
1426 | 1473 | ||
1427 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1474 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1428 | dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); | 1475 | dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); |
1429 | if (IS_ERR(dsi->reg_base)) { | 1476 | if (IS_ERR(dsi->reg_base)) { |
1430 | dev_err(&pdev->dev, "failed to remap io region\n"); | 1477 | dev_err(&pdev->dev, "failed to remap io region\n"); |
1431 | return PTR_ERR(dsi->reg_base); | 1478 | ret = PTR_ERR(dsi->reg_base); |
1479 | goto err_del_component; | ||
1432 | } | 1480 | } |
1433 | 1481 | ||
1434 | dsi->phy = devm_phy_get(&pdev->dev, "dsim"); | 1482 | dsi->phy = devm_phy_get(&pdev->dev, "dsim"); |
1435 | if (IS_ERR(dsi->phy)) { | 1483 | if (IS_ERR(dsi->phy)) { |
1436 | dev_info(&pdev->dev, "failed to get dsim phy\n"); | 1484 | dev_info(&pdev->dev, "failed to get dsim phy\n"); |
1437 | return -EPROBE_DEFER; | 1485 | ret = PTR_ERR(dsi->phy); |
1486 | goto err_del_component; | ||
1438 | } | 1487 | } |
1439 | 1488 | ||
1440 | dsi->irq = platform_get_irq(pdev, 0); | 1489 | dsi->irq = platform_get_irq(pdev, 0); |
1441 | if (dsi->irq < 0) { | 1490 | if (dsi->irq < 0) { |
1442 | dev_err(&pdev->dev, "failed to request dsi irq resource\n"); | 1491 | dev_err(&pdev->dev, "failed to request dsi irq resource\n"); |
1443 | return dsi->irq; | 1492 | ret = dsi->irq; |
1493 | goto err_del_component; | ||
1444 | } | 1494 | } |
1445 | 1495 | ||
1446 | irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); | 1496 | irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); |
@@ -1449,58 +1499,31 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
1449 | dev_name(&pdev->dev), dsi); | 1499 | dev_name(&pdev->dev), dsi); |
1450 | if (ret) { | 1500 | if (ret) { |
1451 | dev_err(&pdev->dev, "failed to request dsi irq\n"); | 1501 | dev_err(&pdev->dev, "failed to request dsi irq\n"); |
1452 | return ret; | 1502 | goto err_del_component; |
1453 | } | 1503 | } |
1454 | 1504 | ||
1455 | exynos_dsi_display.ctx = dsi; | 1505 | exynos_dsi_display.ctx = dsi; |
1456 | 1506 | ||
1457 | platform_set_drvdata(pdev, &exynos_dsi_display); | 1507 | platform_set_drvdata(pdev, &exynos_dsi_display); |
1458 | exynos_drm_display_register(&exynos_dsi_display); | ||
1459 | |||
1460 | return mipi_dsi_host_register(&dsi->dsi_host); | ||
1461 | } | ||
1462 | |||
1463 | static int exynos_dsi_remove(struct platform_device *pdev) | ||
1464 | { | ||
1465 | struct exynos_dsi *dsi = exynos_dsi_display.ctx; | ||
1466 | |||
1467 | exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF); | ||
1468 | |||
1469 | exynos_drm_display_unregister(&exynos_dsi_display); | ||
1470 | mipi_dsi_host_unregister(&dsi->dsi_host); | ||
1471 | |||
1472 | return 0; | ||
1473 | } | ||
1474 | 1508 | ||
1475 | #if CONFIG_PM_SLEEP | 1509 | ret = component_add(&pdev->dev, &exynos_dsi_component_ops); |
1476 | static int exynos_dsi_resume(struct device *dev) | 1510 | if (ret) |
1477 | { | 1511 | goto err_del_component; |
1478 | struct exynos_dsi *dsi = exynos_dsi_display.ctx; | ||
1479 | 1512 | ||
1480 | if (dsi->state & DSIM_STATE_ENABLED) { | 1513 | return ret; |
1481 | dsi->state &= ~DSIM_STATE_ENABLED; | ||
1482 | exynos_dsi_enable(dsi); | ||
1483 | } | ||
1484 | 1514 | ||
1485 | return 0; | 1515 | err_del_component: |
1516 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
1517 | return ret; | ||
1486 | } | 1518 | } |
1487 | 1519 | ||
1488 | static int exynos_dsi_suspend(struct device *dev) | 1520 | static int exynos_dsi_remove(struct platform_device *pdev) |
1489 | { | 1521 | { |
1490 | struct exynos_dsi *dsi = exynos_dsi_display.ctx; | 1522 | component_del(&pdev->dev, &exynos_dsi_component_ops); |
1491 | 1523 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | |
1492 | if (dsi->state & DSIM_STATE_ENABLED) { | ||
1493 | exynos_dsi_disable(dsi); | ||
1494 | dsi->state |= DSIM_STATE_ENABLED; | ||
1495 | } | ||
1496 | 1524 | ||
1497 | return 0; | 1525 | return 0; |
1498 | } | 1526 | } |
1499 | #endif | ||
1500 | |||
1501 | static const struct dev_pm_ops exynos_dsi_pm_ops = { | ||
1502 | SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume) | ||
1503 | }; | ||
1504 | 1527 | ||
1505 | static struct of_device_id exynos_dsi_of_match[] = { | 1528 | static struct of_device_id exynos_dsi_of_match[] = { |
1506 | { .compatible = "samsung,exynos4210-mipi-dsi" }, | 1529 | { .compatible = "samsung,exynos4210-mipi-dsi" }, |
@@ -1513,7 +1536,6 @@ struct platform_driver dsi_driver = { | |||
1513 | .driver = { | 1536 | .driver = { |
1514 | .name = "exynos-dsi", | 1537 | .name = "exynos-dsi", |
1515 | .owner = THIS_MODULE, | 1538 | .owner = THIS_MODULE, |
1516 | .pm = &exynos_dsi_pm_ops, | ||
1517 | .of_match_table = exynos_dsi_of_match, | 1539 | .of_match_table = exynos_dsi_of_match, |
1518 | }, | 1540 | }, |
1519 | }; | 1541 | }; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index addbf7536da4..14bbaa33b477 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c | |||
@@ -121,16 +121,8 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, | |||
121 | offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); | 121 | offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); |
122 | offset += fbi->var.yoffset * fb->pitches[0]; | 122 | offset += fbi->var.yoffset * fb->pitches[0]; |
123 | 123 | ||
124 | dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr; | ||
125 | fbi->screen_base = buffer->kvaddr + offset; | 124 | fbi->screen_base = buffer->kvaddr + offset; |
126 | if (is_drm_iommu_supported(dev)) | ||
127 | fbi->fix.smem_start = (unsigned long) | ||
128 | (page_to_phys(sg_page(buffer->sgt->sgl)) + offset); | ||
129 | else | ||
130 | fbi->fix.smem_start = (unsigned long)buffer->dma_addr; | ||
131 | |||
132 | fbi->screen_size = size; | 125 | fbi->screen_size = size; |
133 | fbi->fix.smem_len = size; | ||
134 | 126 | ||
135 | return 0; | 127 | return 0; |
136 | } | 128 | } |
@@ -237,7 +229,7 @@ static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { | |||
237 | .fb_probe = exynos_drm_fbdev_create, | 229 | .fb_probe = exynos_drm_fbdev_create, |
238 | }; | 230 | }; |
239 | 231 | ||
240 | bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev) | 232 | static bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev) |
241 | { | 233 | { |
242 | struct drm_connector *connector; | 234 | struct drm_connector *connector; |
243 | bool ret = false; | 235 | bool ret = false; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 30d76b2ff9c2..831dde9034c6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
20 | #include <linux/of.h> | 20 | #include <linux/of.h> |
21 | #include <linux/spinlock.h> | ||
21 | 22 | ||
22 | #include <drm/drmP.h> | 23 | #include <drm/drmP.h> |
23 | #include <drm/exynos_drm.h> | 24 | #include <drm/exynos_drm.h> |
@@ -57,7 +58,6 @@ | |||
57 | #define FIMC_SHFACTOR 10 | 58 | #define FIMC_SHFACTOR 10 |
58 | #define FIMC_BUF_STOP 1 | 59 | #define FIMC_BUF_STOP 1 |
59 | #define FIMC_BUF_START 2 | 60 | #define FIMC_BUF_START 2 |
60 | #define FIMC_REG_SZ 32 | ||
61 | #define FIMC_WIDTH_ITU_709 1280 | 61 | #define FIMC_WIDTH_ITU_709 1280 |
62 | #define FIMC_REFRESH_MAX 60 | 62 | #define FIMC_REFRESH_MAX 60 |
63 | #define FIMC_REFRESH_MIN 12 | 63 | #define FIMC_REFRESH_MIN 12 |
@@ -69,9 +69,6 @@ | |||
69 | #define get_fimc_context(dev) platform_get_drvdata(to_platform_device(dev)) | 69 | #define get_fimc_context(dev) platform_get_drvdata(to_platform_device(dev)) |
70 | #define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\ | 70 | #define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\ |
71 | struct fimc_context, ippdrv); | 71 | struct fimc_context, ippdrv); |
72 | #define fimc_read(offset) readl(ctx->regs + (offset)) | ||
73 | #define fimc_write(cfg, offset) writel(cfg, ctx->regs + (offset)) | ||
74 | |||
75 | enum fimc_wb { | 72 | enum fimc_wb { |
76 | FIMC_WB_NONE, | 73 | FIMC_WB_NONE, |
77 | FIMC_WB_A, | 74 | FIMC_WB_A, |
@@ -161,7 +158,7 @@ struct fimc_context { | |||
161 | struct exynos_drm_ippdrv ippdrv; | 158 | struct exynos_drm_ippdrv ippdrv; |
162 | struct resource *regs_res; | 159 | struct resource *regs_res; |
163 | void __iomem *regs; | 160 | void __iomem *regs; |
164 | struct mutex lock; | 161 | spinlock_t lock; |
165 | struct clk *clocks[FIMC_CLKS_MAX]; | 162 | struct clk *clocks[FIMC_CLKS_MAX]; |
166 | u32 clk_frequency; | 163 | u32 clk_frequency; |
167 | struct regmap *sysreg; | 164 | struct regmap *sysreg; |
@@ -172,39 +169,53 @@ struct fimc_context { | |||
172 | bool suspended; | 169 | bool suspended; |
173 | }; | 170 | }; |
174 | 171 | ||
172 | static u32 fimc_read(struct fimc_context *ctx, u32 reg) | ||
173 | { | ||
174 | return readl(ctx->regs + reg); | ||
175 | } | ||
176 | |||
177 | static void fimc_write(struct fimc_context *ctx, u32 val, u32 reg) | ||
178 | { | ||
179 | writel(val, ctx->regs + reg); | ||
180 | } | ||
181 | |||
182 | static void fimc_set_bits(struct fimc_context *ctx, u32 reg, u32 bits) | ||
183 | { | ||
184 | void __iomem *r = ctx->regs + reg; | ||
185 | |||
186 | writel(readl(r) | bits, r); | ||
187 | } | ||
188 | |||
189 | static void fimc_clear_bits(struct fimc_context *ctx, u32 reg, u32 bits) | ||
190 | { | ||
191 | void __iomem *r = ctx->regs + reg; | ||
192 | |||
193 | writel(readl(r) & ~bits, r); | ||
194 | } | ||
195 | |||
175 | static void fimc_sw_reset(struct fimc_context *ctx) | 196 | static void fimc_sw_reset(struct fimc_context *ctx) |
176 | { | 197 | { |
177 | u32 cfg; | 198 | u32 cfg; |
178 | 199 | ||
179 | /* stop dma operation */ | 200 | /* stop dma operation */ |
180 | cfg = fimc_read(EXYNOS_CISTATUS); | 201 | cfg = fimc_read(ctx, EXYNOS_CISTATUS); |
181 | if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) { | 202 | if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) |
182 | cfg = fimc_read(EXYNOS_MSCTRL); | 203 | fimc_clear_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); |
183 | cfg &= ~EXYNOS_MSCTRL_ENVID; | ||
184 | fimc_write(cfg, EXYNOS_MSCTRL); | ||
185 | } | ||
186 | 204 | ||
187 | cfg = fimc_read(EXYNOS_CISRCFMT); | 205 | fimc_set_bits(ctx, EXYNOS_CISRCFMT, EXYNOS_CISRCFMT_ITU601_8BIT); |
188 | cfg |= EXYNOS_CISRCFMT_ITU601_8BIT; | ||
189 | fimc_write(cfg, EXYNOS_CISRCFMT); | ||
190 | 206 | ||
191 | /* disable image capture */ | 207 | /* disable image capture */ |
192 | cfg = fimc_read(EXYNOS_CIIMGCPT); | 208 | fimc_clear_bits(ctx, EXYNOS_CIIMGCPT, |
193 | cfg &= ~(EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); | 209 | EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); |
194 | fimc_write(cfg, EXYNOS_CIIMGCPT); | ||
195 | 210 | ||
196 | /* s/w reset */ | 211 | /* s/w reset */ |
197 | cfg = fimc_read(EXYNOS_CIGCTRL); | 212 | fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST); |
198 | cfg |= (EXYNOS_CIGCTRL_SWRST); | ||
199 | fimc_write(cfg, EXYNOS_CIGCTRL); | ||
200 | 213 | ||
201 | /* s/w reset complete */ | 214 | /* s/w reset complete */ |
202 | cfg = fimc_read(EXYNOS_CIGCTRL); | 215 | fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST); |
203 | cfg &= ~EXYNOS_CIGCTRL_SWRST; | ||
204 | fimc_write(cfg, EXYNOS_CIGCTRL); | ||
205 | 216 | ||
206 | /* reset sequence */ | 217 | /* reset sequence */ |
207 | fimc_write(0x0, EXYNOS_CIFCNTSEQ); | 218 | fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ); |
208 | } | 219 | } |
209 | 220 | ||
210 | static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) | 221 | static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) |
@@ -220,7 +231,7 @@ static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) | |||
220 | 231 | ||
221 | DRM_DEBUG_KMS("wb[%d]\n", wb); | 232 | DRM_DEBUG_KMS("wb[%d]\n", wb); |
222 | 233 | ||
223 | cfg = fimc_read(EXYNOS_CIGCTRL); | 234 | cfg = fimc_read(ctx, EXYNOS_CIGCTRL); |
224 | cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK | | 235 | cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK | |
225 | EXYNOS_CIGCTRL_SELCAM_ITU_MASK | | 236 | EXYNOS_CIGCTRL_SELCAM_ITU_MASK | |
226 | EXYNOS_CIGCTRL_SELCAM_MIPI_MASK | | 237 | EXYNOS_CIGCTRL_SELCAM_MIPI_MASK | |
@@ -246,7 +257,7 @@ static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) | |||
246 | break; | 257 | break; |
247 | } | 258 | } |
248 | 259 | ||
249 | fimc_write(cfg, EXYNOS_CIGCTRL); | 260 | fimc_write(ctx, cfg, EXYNOS_CIGCTRL); |
250 | } | 261 | } |
251 | 262 | ||
252 | static void fimc_set_polarity(struct fimc_context *ctx, | 263 | static void fimc_set_polarity(struct fimc_context *ctx, |
@@ -259,7 +270,7 @@ static void fimc_set_polarity(struct fimc_context *ctx, | |||
259 | DRM_DEBUG_KMS("inv_href[%d]inv_hsync[%d]\n", | 270 | DRM_DEBUG_KMS("inv_href[%d]inv_hsync[%d]\n", |
260 | pol->inv_href, pol->inv_hsync); | 271 | pol->inv_href, pol->inv_hsync); |
261 | 272 | ||
262 | cfg = fimc_read(EXYNOS_CIGCTRL); | 273 | cfg = fimc_read(ctx, EXYNOS_CIGCTRL); |
263 | cfg &= ~(EXYNOS_CIGCTRL_INVPOLPCLK | EXYNOS_CIGCTRL_INVPOLVSYNC | | 274 | cfg &= ~(EXYNOS_CIGCTRL_INVPOLPCLK | EXYNOS_CIGCTRL_INVPOLVSYNC | |
264 | EXYNOS_CIGCTRL_INVPOLHREF | EXYNOS_CIGCTRL_INVPOLHSYNC); | 275 | EXYNOS_CIGCTRL_INVPOLHREF | EXYNOS_CIGCTRL_INVPOLHSYNC); |
265 | 276 | ||
@@ -272,7 +283,7 @@ static void fimc_set_polarity(struct fimc_context *ctx, | |||
272 | if (pol->inv_hsync) | 283 | if (pol->inv_hsync) |
273 | cfg |= EXYNOS_CIGCTRL_INVPOLHSYNC; | 284 | cfg |= EXYNOS_CIGCTRL_INVPOLHSYNC; |
274 | 285 | ||
275 | fimc_write(cfg, EXYNOS_CIGCTRL); | 286 | fimc_write(ctx, cfg, EXYNOS_CIGCTRL); |
276 | } | 287 | } |
277 | 288 | ||
278 | static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable) | 289 | static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable) |
@@ -281,70 +292,54 @@ static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable) | |||
281 | 292 | ||
282 | DRM_DEBUG_KMS("enable[%d]\n", enable); | 293 | DRM_DEBUG_KMS("enable[%d]\n", enable); |
283 | 294 | ||
284 | cfg = fimc_read(EXYNOS_CIGCTRL); | 295 | cfg = fimc_read(ctx, EXYNOS_CIGCTRL); |
285 | if (enable) | 296 | if (enable) |
286 | cfg |= EXYNOS_CIGCTRL_CAM_JPEG; | 297 | cfg |= EXYNOS_CIGCTRL_CAM_JPEG; |
287 | else | 298 | else |
288 | cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG; | 299 | cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG; |
289 | 300 | ||
290 | fimc_write(cfg, EXYNOS_CIGCTRL); | 301 | fimc_write(ctx, cfg, EXYNOS_CIGCTRL); |
291 | } | 302 | } |
292 | 303 | ||
293 | static void fimc_handle_irq(struct fimc_context *ctx, bool enable, | 304 | static void fimc_mask_irq(struct fimc_context *ctx, bool enable) |
294 | bool overflow, bool level) | ||
295 | { | 305 | { |
296 | u32 cfg; | 306 | u32 cfg; |
297 | 307 | ||
298 | DRM_DEBUG_KMS("enable[%d]overflow[%d]level[%d]\n", | 308 | DRM_DEBUG_KMS("enable[%d]\n", enable); |
299 | enable, overflow, level); | ||
300 | 309 | ||
301 | cfg = fimc_read(EXYNOS_CIGCTRL); | 310 | cfg = fimc_read(ctx, EXYNOS_CIGCTRL); |
302 | if (enable) { | 311 | if (enable) { |
303 | cfg &= ~(EXYNOS_CIGCTRL_IRQ_OVFEN | EXYNOS_CIGCTRL_IRQ_LEVEL); | 312 | cfg &= ~EXYNOS_CIGCTRL_IRQ_OVFEN; |
304 | cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE; | 313 | cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE | EXYNOS_CIGCTRL_IRQ_LEVEL; |
305 | if (overflow) | ||
306 | cfg |= EXYNOS_CIGCTRL_IRQ_OVFEN; | ||
307 | if (level) | ||
308 | cfg |= EXYNOS_CIGCTRL_IRQ_LEVEL; | ||
309 | } else | 314 | } else |
310 | cfg &= ~(EXYNOS_CIGCTRL_IRQ_OVFEN | EXYNOS_CIGCTRL_IRQ_ENABLE); | 315 | cfg &= ~EXYNOS_CIGCTRL_IRQ_ENABLE; |
311 | 316 | fimc_write(ctx, cfg, EXYNOS_CIGCTRL); | |
312 | fimc_write(cfg, EXYNOS_CIGCTRL); | ||
313 | } | 317 | } |
314 | 318 | ||
315 | static void fimc_clear_irq(struct fimc_context *ctx) | 319 | static void fimc_clear_irq(struct fimc_context *ctx) |
316 | { | 320 | { |
317 | u32 cfg; | 321 | fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_CLR); |
318 | |||
319 | cfg = fimc_read(EXYNOS_CIGCTRL); | ||
320 | cfg |= EXYNOS_CIGCTRL_IRQ_CLR; | ||
321 | fimc_write(cfg, EXYNOS_CIGCTRL); | ||
322 | } | 322 | } |
323 | 323 | ||
324 | static bool fimc_check_ovf(struct fimc_context *ctx) | 324 | static bool fimc_check_ovf(struct fimc_context *ctx) |
325 | { | 325 | { |
326 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 326 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; |
327 | u32 cfg, status, flag; | 327 | u32 status, flag; |
328 | 328 | ||
329 | status = fimc_read(EXYNOS_CISTATUS); | 329 | status = fimc_read(ctx, EXYNOS_CISTATUS); |
330 | flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB | | 330 | flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB | |
331 | EXYNOS_CISTATUS_OVFICR; | 331 | EXYNOS_CISTATUS_OVFICR; |
332 | 332 | ||
333 | DRM_DEBUG_KMS("flag[0x%x]\n", flag); | 333 | DRM_DEBUG_KMS("flag[0x%x]\n", flag); |
334 | 334 | ||
335 | if (status & flag) { | 335 | if (status & flag) { |
336 | cfg = fimc_read(EXYNOS_CIWDOFST); | 336 | fimc_set_bits(ctx, EXYNOS_CIWDOFST, |
337 | cfg |= (EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB | | 337 | EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB | |
338 | EXYNOS_CIWDOFST_CLROVFICR); | 338 | EXYNOS_CIWDOFST_CLROVFICR); |
339 | 339 | fimc_clear_bits(ctx, EXYNOS_CIWDOFST, | |
340 | fimc_write(cfg, EXYNOS_CIWDOFST); | 340 | EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB | |
341 | |||
342 | cfg = fimc_read(EXYNOS_CIWDOFST); | ||
343 | cfg &= ~(EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB | | ||
344 | EXYNOS_CIWDOFST_CLROVFICR); | 341 | EXYNOS_CIWDOFST_CLROVFICR); |
345 | 342 | ||
346 | fimc_write(cfg, EXYNOS_CIWDOFST); | ||
347 | |||
348 | dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n", | 343 | dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n", |
349 | ctx->id, status); | 344 | ctx->id, status); |
350 | return true; | 345 | return true; |
@@ -357,7 +352,7 @@ static bool fimc_check_frame_end(struct fimc_context *ctx) | |||
357 | { | 352 | { |
358 | u32 cfg; | 353 | u32 cfg; |
359 | 354 | ||
360 | cfg = fimc_read(EXYNOS_CISTATUS); | 355 | cfg = fimc_read(ctx, EXYNOS_CISTATUS); |
361 | 356 | ||
362 | DRM_DEBUG_KMS("cfg[0x%x]\n", cfg); | 357 | DRM_DEBUG_KMS("cfg[0x%x]\n", cfg); |
363 | 358 | ||
@@ -365,7 +360,7 @@ static bool fimc_check_frame_end(struct fimc_context *ctx) | |||
365 | return false; | 360 | return false; |
366 | 361 | ||
367 | cfg &= ~(EXYNOS_CISTATUS_FRAMEEND); | 362 | cfg &= ~(EXYNOS_CISTATUS_FRAMEEND); |
368 | fimc_write(cfg, EXYNOS_CISTATUS); | 363 | fimc_write(ctx, cfg, EXYNOS_CISTATUS); |
369 | 364 | ||
370 | return true; | 365 | return true; |
371 | } | 366 | } |
@@ -375,7 +370,7 @@ static int fimc_get_buf_id(struct fimc_context *ctx) | |||
375 | u32 cfg; | 370 | u32 cfg; |
376 | int frame_cnt, buf_id; | 371 | int frame_cnt, buf_id; |
377 | 372 | ||
378 | cfg = fimc_read(EXYNOS_CISTATUS2); | 373 | cfg = fimc_read(ctx, EXYNOS_CISTATUS2); |
379 | frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg); | 374 | frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg); |
380 | 375 | ||
381 | if (frame_cnt == 0) | 376 | if (frame_cnt == 0) |
@@ -402,13 +397,13 @@ static void fimc_handle_lastend(struct fimc_context *ctx, bool enable) | |||
402 | 397 | ||
403 | DRM_DEBUG_KMS("enable[%d]\n", enable); | 398 | DRM_DEBUG_KMS("enable[%d]\n", enable); |
404 | 399 | ||
405 | cfg = fimc_read(EXYNOS_CIOCTRL); | 400 | cfg = fimc_read(ctx, EXYNOS_CIOCTRL); |
406 | if (enable) | 401 | if (enable) |
407 | cfg |= EXYNOS_CIOCTRL_LASTENDEN; | 402 | cfg |= EXYNOS_CIOCTRL_LASTENDEN; |
408 | else | 403 | else |
409 | cfg &= ~EXYNOS_CIOCTRL_LASTENDEN; | 404 | cfg &= ~EXYNOS_CIOCTRL_LASTENDEN; |
410 | 405 | ||
411 | fimc_write(cfg, EXYNOS_CIOCTRL); | 406 | fimc_write(ctx, cfg, EXYNOS_CIOCTRL); |
412 | } | 407 | } |
413 | 408 | ||
414 | 409 | ||
@@ -420,18 +415,18 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) | |||
420 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 415 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); |
421 | 416 | ||
422 | /* RGB */ | 417 | /* RGB */ |
423 | cfg = fimc_read(EXYNOS_CISCCTRL); | 418 | cfg = fimc_read(ctx, EXYNOS_CISCCTRL); |
424 | cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK; | 419 | cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK; |
425 | 420 | ||
426 | switch (fmt) { | 421 | switch (fmt) { |
427 | case DRM_FORMAT_RGB565: | 422 | case DRM_FORMAT_RGB565: |
428 | cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565; | 423 | cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565; |
429 | fimc_write(cfg, EXYNOS_CISCCTRL); | 424 | fimc_write(ctx, cfg, EXYNOS_CISCCTRL); |
430 | return 0; | 425 | return 0; |
431 | case DRM_FORMAT_RGB888: | 426 | case DRM_FORMAT_RGB888: |
432 | case DRM_FORMAT_XRGB8888: | 427 | case DRM_FORMAT_XRGB8888: |
433 | cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888; | 428 | cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888; |
434 | fimc_write(cfg, EXYNOS_CISCCTRL); | 429 | fimc_write(ctx, cfg, EXYNOS_CISCCTRL); |
435 | return 0; | 430 | return 0; |
436 | default: | 431 | default: |
437 | /* bypass */ | 432 | /* bypass */ |
@@ -439,7 +434,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) | |||
439 | } | 434 | } |
440 | 435 | ||
441 | /* YUV */ | 436 | /* YUV */ |
442 | cfg = fimc_read(EXYNOS_MSCTRL); | 437 | cfg = fimc_read(ctx, EXYNOS_MSCTRL); |
443 | cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK | | 438 | cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK | |
444 | EXYNOS_MSCTRL_C_INT_IN_2PLANE | | 439 | EXYNOS_MSCTRL_C_INT_IN_2PLANE | |
445 | EXYNOS_MSCTRL_ORDER422_YCBYCR); | 440 | EXYNOS_MSCTRL_ORDER422_YCBYCR); |
@@ -479,7 +474,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) | |||
479 | return -EINVAL; | 474 | return -EINVAL; |
480 | } | 475 | } |
481 | 476 | ||
482 | fimc_write(cfg, EXYNOS_MSCTRL); | 477 | fimc_write(ctx, cfg, EXYNOS_MSCTRL); |
483 | 478 | ||
484 | return 0; | 479 | return 0; |
485 | } | 480 | } |
@@ -492,7 +487,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) | |||
492 | 487 | ||
493 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 488 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); |
494 | 489 | ||
495 | cfg = fimc_read(EXYNOS_MSCTRL); | 490 | cfg = fimc_read(ctx, EXYNOS_MSCTRL); |
496 | cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB; | 491 | cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB; |
497 | 492 | ||
498 | switch (fmt) { | 493 | switch (fmt) { |
@@ -527,9 +522,9 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) | |||
527 | return -EINVAL; | 522 | return -EINVAL; |
528 | } | 523 | } |
529 | 524 | ||
530 | fimc_write(cfg, EXYNOS_MSCTRL); | 525 | fimc_write(ctx, cfg, EXYNOS_MSCTRL); |
531 | 526 | ||
532 | cfg = fimc_read(EXYNOS_CIDMAPARAM); | 527 | cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM); |
533 | cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK; | 528 | cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK; |
534 | 529 | ||
535 | if (fmt == DRM_FORMAT_NV12MT) | 530 | if (fmt == DRM_FORMAT_NV12MT) |
@@ -537,7 +532,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) | |||
537 | else | 532 | else |
538 | cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR; | 533 | cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR; |
539 | 534 | ||
540 | fimc_write(cfg, EXYNOS_CIDMAPARAM); | 535 | fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM); |
541 | 536 | ||
542 | return fimc_src_set_fmt_order(ctx, fmt); | 537 | return fimc_src_set_fmt_order(ctx, fmt); |
543 | } | 538 | } |
@@ -552,11 +547,11 @@ static int fimc_src_set_transf(struct device *dev, | |||
552 | 547 | ||
553 | DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip); | 548 | DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip); |
554 | 549 | ||
555 | cfg1 = fimc_read(EXYNOS_MSCTRL); | 550 | cfg1 = fimc_read(ctx, EXYNOS_MSCTRL); |
556 | cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR | | 551 | cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR | |
557 | EXYNOS_MSCTRL_FLIP_Y_MIRROR); | 552 | EXYNOS_MSCTRL_FLIP_Y_MIRROR); |
558 | 553 | ||
559 | cfg2 = fimc_read(EXYNOS_CITRGFMT); | 554 | cfg2 = fimc_read(ctx, EXYNOS_CITRGFMT); |
560 | cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE; | 555 | cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE; |
561 | 556 | ||
562 | switch (degree) { | 557 | switch (degree) { |
@@ -595,8 +590,8 @@ static int fimc_src_set_transf(struct device *dev, | |||
595 | return -EINVAL; | 590 | return -EINVAL; |
596 | } | 591 | } |
597 | 592 | ||
598 | fimc_write(cfg1, EXYNOS_MSCTRL); | 593 | fimc_write(ctx, cfg1, EXYNOS_MSCTRL); |
599 | fimc_write(cfg2, EXYNOS_CITRGFMT); | 594 | fimc_write(ctx, cfg2, EXYNOS_CITRGFMT); |
600 | *swap = (cfg2 & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) ? 1 : 0; | 595 | *swap = (cfg2 & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) ? 1 : 0; |
601 | 596 | ||
602 | return 0; | 597 | return 0; |
@@ -621,17 +616,17 @@ static int fimc_set_window(struct fimc_context *ctx, | |||
621 | * set window offset 1, 2 size | 616 | * set window offset 1, 2 size |
622 | * check figure 43-21 in user manual | 617 | * check figure 43-21 in user manual |
623 | */ | 618 | */ |
624 | cfg = fimc_read(EXYNOS_CIWDOFST); | 619 | cfg = fimc_read(ctx, EXYNOS_CIWDOFST); |
625 | cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK | | 620 | cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK | |
626 | EXYNOS_CIWDOFST_WINVEROFST_MASK); | 621 | EXYNOS_CIWDOFST_WINVEROFST_MASK); |
627 | cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) | | 622 | cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) | |
628 | EXYNOS_CIWDOFST_WINVEROFST(v1)); | 623 | EXYNOS_CIWDOFST_WINVEROFST(v1)); |
629 | cfg |= EXYNOS_CIWDOFST_WINOFSEN; | 624 | cfg |= EXYNOS_CIWDOFST_WINOFSEN; |
630 | fimc_write(cfg, EXYNOS_CIWDOFST); | 625 | fimc_write(ctx, cfg, EXYNOS_CIWDOFST); |
631 | 626 | ||
632 | cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) | | 627 | cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) | |
633 | EXYNOS_CIWDOFST2_WINVEROFST2(v2)); | 628 | EXYNOS_CIWDOFST2_WINVEROFST2(v2)); |
634 | fimc_write(cfg, EXYNOS_CIWDOFST2); | 629 | fimc_write(ctx, cfg, EXYNOS_CIWDOFST2); |
635 | 630 | ||
636 | return 0; | 631 | return 0; |
637 | } | 632 | } |
@@ -651,7 +646,7 @@ static int fimc_src_set_size(struct device *dev, int swap, | |||
651 | cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) | | 646 | cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) | |
652 | EXYNOS_ORGISIZE_VERTICAL(img_sz.vsize)); | 647 | EXYNOS_ORGISIZE_VERTICAL(img_sz.vsize)); |
653 | 648 | ||
654 | fimc_write(cfg, EXYNOS_ORGISIZE); | 649 | fimc_write(ctx, cfg, EXYNOS_ORGISIZE); |
655 | 650 | ||
656 | DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h); | 651 | DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h); |
657 | 652 | ||
@@ -663,12 +658,12 @@ static int fimc_src_set_size(struct device *dev, int swap, | |||
663 | } | 658 | } |
664 | 659 | ||
665 | /* set input DMA image size */ | 660 | /* set input DMA image size */ |
666 | cfg = fimc_read(EXYNOS_CIREAL_ISIZE); | 661 | cfg = fimc_read(ctx, EXYNOS_CIREAL_ISIZE); |
667 | cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK | | 662 | cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK | |
668 | EXYNOS_CIREAL_ISIZE_WIDTH_MASK); | 663 | EXYNOS_CIREAL_ISIZE_WIDTH_MASK); |
669 | cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(img_pos.w) | | 664 | cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(img_pos.w) | |
670 | EXYNOS_CIREAL_ISIZE_HEIGHT(img_pos.h)); | 665 | EXYNOS_CIREAL_ISIZE_HEIGHT(img_pos.h)); |
671 | fimc_write(cfg, EXYNOS_CIREAL_ISIZE); | 666 | fimc_write(ctx, cfg, EXYNOS_CIREAL_ISIZE); |
672 | 667 | ||
673 | /* | 668 | /* |
674 | * set input FIFO image size | 669 | * set input FIFO image size |
@@ -677,18 +672,18 @@ static int fimc_src_set_size(struct device *dev, int swap, | |||
677 | cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | | 672 | cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | |
678 | EXYNOS_CISRCFMT_SOURCEHSIZE(img_sz.hsize) | | 673 | EXYNOS_CISRCFMT_SOURCEHSIZE(img_sz.hsize) | |
679 | EXYNOS_CISRCFMT_SOURCEVSIZE(img_sz.vsize)); | 674 | EXYNOS_CISRCFMT_SOURCEVSIZE(img_sz.vsize)); |
680 | fimc_write(cfg, EXYNOS_CISRCFMT); | 675 | fimc_write(ctx, cfg, EXYNOS_CISRCFMT); |
681 | 676 | ||
682 | /* offset Y(RGB), Cb, Cr */ | 677 | /* offset Y(RGB), Cb, Cr */ |
683 | cfg = (EXYNOS_CIIYOFF_HORIZONTAL(img_pos.x) | | 678 | cfg = (EXYNOS_CIIYOFF_HORIZONTAL(img_pos.x) | |
684 | EXYNOS_CIIYOFF_VERTICAL(img_pos.y)); | 679 | EXYNOS_CIIYOFF_VERTICAL(img_pos.y)); |
685 | fimc_write(cfg, EXYNOS_CIIYOFF); | 680 | fimc_write(ctx, cfg, EXYNOS_CIIYOFF); |
686 | cfg = (EXYNOS_CIICBOFF_HORIZONTAL(img_pos.x) | | 681 | cfg = (EXYNOS_CIICBOFF_HORIZONTAL(img_pos.x) | |
687 | EXYNOS_CIICBOFF_VERTICAL(img_pos.y)); | 682 | EXYNOS_CIICBOFF_VERTICAL(img_pos.y)); |
688 | fimc_write(cfg, EXYNOS_CIICBOFF); | 683 | fimc_write(ctx, cfg, EXYNOS_CIICBOFF); |
689 | cfg = (EXYNOS_CIICROFF_HORIZONTAL(img_pos.x) | | 684 | cfg = (EXYNOS_CIICROFF_HORIZONTAL(img_pos.x) | |
690 | EXYNOS_CIICROFF_VERTICAL(img_pos.y)); | 685 | EXYNOS_CIICROFF_VERTICAL(img_pos.y)); |
691 | fimc_write(cfg, EXYNOS_CIICROFF); | 686 | fimc_write(ctx, cfg, EXYNOS_CIICROFF); |
692 | 687 | ||
693 | return fimc_set_window(ctx, &img_pos, &img_sz); | 688 | return fimc_set_window(ctx, &img_pos, &img_sz); |
694 | } | 689 | } |
@@ -722,25 +717,25 @@ static int fimc_src_set_addr(struct device *dev, | |||
722 | switch (buf_type) { | 717 | switch (buf_type) { |
723 | case IPP_BUF_ENQUEUE: | 718 | case IPP_BUF_ENQUEUE: |
724 | config = &property->config[EXYNOS_DRM_OPS_SRC]; | 719 | config = &property->config[EXYNOS_DRM_OPS_SRC]; |
725 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y], | 720 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y], |
726 | EXYNOS_CIIYSA(buf_id)); | 721 | EXYNOS_CIIYSA(buf_id)); |
727 | 722 | ||
728 | if (config->fmt == DRM_FORMAT_YVU420) { | 723 | if (config->fmt == DRM_FORMAT_YVU420) { |
729 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR], | 724 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], |
730 | EXYNOS_CIICBSA(buf_id)); | 725 | EXYNOS_CIICBSA(buf_id)); |
731 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB], | 726 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], |
732 | EXYNOS_CIICRSA(buf_id)); | 727 | EXYNOS_CIICRSA(buf_id)); |
733 | } else { | 728 | } else { |
734 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB], | 729 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], |
735 | EXYNOS_CIICBSA(buf_id)); | 730 | EXYNOS_CIICBSA(buf_id)); |
736 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR], | 731 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], |
737 | EXYNOS_CIICRSA(buf_id)); | 732 | EXYNOS_CIICRSA(buf_id)); |
738 | } | 733 | } |
739 | break; | 734 | break; |
740 | case IPP_BUF_DEQUEUE: | 735 | case IPP_BUF_DEQUEUE: |
741 | fimc_write(0x0, EXYNOS_CIIYSA(buf_id)); | 736 | fimc_write(ctx, 0x0, EXYNOS_CIIYSA(buf_id)); |
742 | fimc_write(0x0, EXYNOS_CIICBSA(buf_id)); | 737 | fimc_write(ctx, 0x0, EXYNOS_CIICBSA(buf_id)); |
743 | fimc_write(0x0, EXYNOS_CIICRSA(buf_id)); | 738 | fimc_write(ctx, 0x0, EXYNOS_CIICRSA(buf_id)); |
744 | break; | 739 | break; |
745 | default: | 740 | default: |
746 | /* bypass */ | 741 | /* bypass */ |
@@ -765,22 +760,22 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) | |||
765 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 760 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); |
766 | 761 | ||
767 | /* RGB */ | 762 | /* RGB */ |
768 | cfg = fimc_read(EXYNOS_CISCCTRL); | 763 | cfg = fimc_read(ctx, EXYNOS_CISCCTRL); |
769 | cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK; | 764 | cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK; |
770 | 765 | ||
771 | switch (fmt) { | 766 | switch (fmt) { |
772 | case DRM_FORMAT_RGB565: | 767 | case DRM_FORMAT_RGB565: |
773 | cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565; | 768 | cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565; |
774 | fimc_write(cfg, EXYNOS_CISCCTRL); | 769 | fimc_write(ctx, cfg, EXYNOS_CISCCTRL); |
775 | return 0; | 770 | return 0; |
776 | case DRM_FORMAT_RGB888: | 771 | case DRM_FORMAT_RGB888: |
777 | cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888; | 772 | cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888; |
778 | fimc_write(cfg, EXYNOS_CISCCTRL); | 773 | fimc_write(ctx, cfg, EXYNOS_CISCCTRL); |
779 | return 0; | 774 | return 0; |
780 | case DRM_FORMAT_XRGB8888: | 775 | case DRM_FORMAT_XRGB8888: |
781 | cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 | | 776 | cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 | |
782 | EXYNOS_CISCCTRL_EXTRGB_EXTENSION); | 777 | EXYNOS_CISCCTRL_EXTRGB_EXTENSION); |
783 | fimc_write(cfg, EXYNOS_CISCCTRL); | 778 | fimc_write(ctx, cfg, EXYNOS_CISCCTRL); |
784 | break; | 779 | break; |
785 | default: | 780 | default: |
786 | /* bypass */ | 781 | /* bypass */ |
@@ -788,7 +783,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) | |||
788 | } | 783 | } |
789 | 784 | ||
790 | /* YUV */ | 785 | /* YUV */ |
791 | cfg = fimc_read(EXYNOS_CIOCTRL); | 786 | cfg = fimc_read(ctx, EXYNOS_CIOCTRL); |
792 | cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK | | 787 | cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK | |
793 | EXYNOS_CIOCTRL_ORDER422_MASK | | 788 | EXYNOS_CIOCTRL_ORDER422_MASK | |
794 | EXYNOS_CIOCTRL_YCBCR_PLANE_MASK); | 789 | EXYNOS_CIOCTRL_YCBCR_PLANE_MASK); |
@@ -830,7 +825,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) | |||
830 | return -EINVAL; | 825 | return -EINVAL; |
831 | } | 826 | } |
832 | 827 | ||
833 | fimc_write(cfg, EXYNOS_CIOCTRL); | 828 | fimc_write(ctx, cfg, EXYNOS_CIOCTRL); |
834 | 829 | ||
835 | return 0; | 830 | return 0; |
836 | } | 831 | } |
@@ -843,16 +838,16 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) | |||
843 | 838 | ||
844 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 839 | DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); |
845 | 840 | ||
846 | cfg = fimc_read(EXYNOS_CIEXTEN); | 841 | cfg = fimc_read(ctx, EXYNOS_CIEXTEN); |
847 | 842 | ||
848 | if (fmt == DRM_FORMAT_AYUV) { | 843 | if (fmt == DRM_FORMAT_AYUV) { |
849 | cfg |= EXYNOS_CIEXTEN_YUV444_OUT; | 844 | cfg |= EXYNOS_CIEXTEN_YUV444_OUT; |
850 | fimc_write(cfg, EXYNOS_CIEXTEN); | 845 | fimc_write(ctx, cfg, EXYNOS_CIEXTEN); |
851 | } else { | 846 | } else { |
852 | cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT; | 847 | cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT; |
853 | fimc_write(cfg, EXYNOS_CIEXTEN); | 848 | fimc_write(ctx, cfg, EXYNOS_CIEXTEN); |
854 | 849 | ||
855 | cfg = fimc_read(EXYNOS_CITRGFMT); | 850 | cfg = fimc_read(ctx, EXYNOS_CITRGFMT); |
856 | cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK; | 851 | cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK; |
857 | 852 | ||
858 | switch (fmt) { | 853 | switch (fmt) { |
@@ -885,10 +880,10 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) | |||
885 | return -EINVAL; | 880 | return -EINVAL; |
886 | } | 881 | } |
887 | 882 | ||
888 | fimc_write(cfg, EXYNOS_CITRGFMT); | 883 | fimc_write(ctx, cfg, EXYNOS_CITRGFMT); |
889 | } | 884 | } |
890 | 885 | ||
891 | cfg = fimc_read(EXYNOS_CIDMAPARAM); | 886 | cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM); |
892 | cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK; | 887 | cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK; |
893 | 888 | ||
894 | if (fmt == DRM_FORMAT_NV12MT) | 889 | if (fmt == DRM_FORMAT_NV12MT) |
@@ -896,7 +891,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) | |||
896 | else | 891 | else |
897 | cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR; | 892 | cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR; |
898 | 893 | ||
899 | fimc_write(cfg, EXYNOS_CIDMAPARAM); | 894 | fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM); |
900 | 895 | ||
901 | return fimc_dst_set_fmt_order(ctx, fmt); | 896 | return fimc_dst_set_fmt_order(ctx, fmt); |
902 | } | 897 | } |
@@ -911,7 +906,7 @@ static int fimc_dst_set_transf(struct device *dev, | |||
911 | 906 | ||
912 | DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip); | 907 | DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip); |
913 | 908 | ||
914 | cfg = fimc_read(EXYNOS_CITRGFMT); | 909 | cfg = fimc_read(ctx, EXYNOS_CITRGFMT); |
915 | cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK; | 910 | cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK; |
916 | cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE; | 911 | cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE; |
917 | 912 | ||
@@ -951,53 +946,23 @@ static int fimc_dst_set_transf(struct device *dev, | |||
951 | return -EINVAL; | 946 | return -EINVAL; |
952 | } | 947 | } |
953 | 948 | ||
954 | fimc_write(cfg, EXYNOS_CITRGFMT); | 949 | fimc_write(ctx, cfg, EXYNOS_CITRGFMT); |
955 | *swap = (cfg & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) ? 1 : 0; | 950 | *swap = (cfg & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) ? 1 : 0; |
956 | 951 | ||
957 | return 0; | 952 | return 0; |
958 | } | 953 | } |
959 | 954 | ||
960 | static int fimc_get_ratio_shift(u32 src, u32 dst, u32 *ratio, u32 *shift) | ||
961 | { | ||
962 | DRM_DEBUG_KMS("src[%d]dst[%d]\n", src, dst); | ||
963 | |||
964 | if (src >= dst * 64) { | ||
965 | DRM_ERROR("failed to make ratio and shift.\n"); | ||
966 | return -EINVAL; | ||
967 | } else if (src >= dst * 32) { | ||
968 | *ratio = 32; | ||
969 | *shift = 5; | ||
970 | } else if (src >= dst * 16) { | ||
971 | *ratio = 16; | ||
972 | *shift = 4; | ||
973 | } else if (src >= dst * 8) { | ||
974 | *ratio = 8; | ||
975 | *shift = 3; | ||
976 | } else if (src >= dst * 4) { | ||
977 | *ratio = 4; | ||
978 | *shift = 2; | ||
979 | } else if (src >= dst * 2) { | ||
980 | *ratio = 2; | ||
981 | *shift = 1; | ||
982 | } else { | ||
983 | *ratio = 1; | ||
984 | *shift = 0; | ||
985 | } | ||
986 | |||
987 | return 0; | ||
988 | } | ||
989 | |||
990 | static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, | 955 | static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, |
991 | struct drm_exynos_pos *src, struct drm_exynos_pos *dst) | 956 | struct drm_exynos_pos *src, struct drm_exynos_pos *dst) |
992 | { | 957 | { |
993 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 958 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; |
994 | u32 cfg, cfg_ext, shfactor; | 959 | u32 cfg, cfg_ext, shfactor; |
995 | u32 pre_dst_width, pre_dst_height; | 960 | u32 pre_dst_width, pre_dst_height; |
996 | u32 pre_hratio, hfactor, pre_vratio, vfactor; | 961 | u32 hfactor, vfactor; |
997 | int ret = 0; | 962 | int ret = 0; |
998 | u32 src_w, src_h, dst_w, dst_h; | 963 | u32 src_w, src_h, dst_w, dst_h; |
999 | 964 | ||
1000 | cfg_ext = fimc_read(EXYNOS_CITRGFMT); | 965 | cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT); |
1001 | if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) { | 966 | if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) { |
1002 | src_w = src->h; | 967 | src_w = src->h; |
1003 | src_h = src->w; | 968 | src_h = src->w; |
@@ -1014,24 +979,24 @@ static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, | |||
1014 | dst_h = dst->h; | 979 | dst_h = dst->h; |
1015 | } | 980 | } |
1016 | 981 | ||
1017 | ret = fimc_get_ratio_shift(src_w, dst_w, &pre_hratio, &hfactor); | 982 | /* fimc_ippdrv_check_property assures that dividers are not null */ |
1018 | if (ret) { | 983 | hfactor = fls(src_w / dst_w / 2); |
984 | if (hfactor > FIMC_SHFACTOR / 2) { | ||
1019 | dev_err(ippdrv->dev, "failed to get ratio horizontal.\n"); | 985 | dev_err(ippdrv->dev, "failed to get ratio horizontal.\n"); |
1020 | return ret; | 986 | return -EINVAL; |
1021 | } | 987 | } |
1022 | 988 | ||
1023 | ret = fimc_get_ratio_shift(src_h, dst_h, &pre_vratio, &vfactor); | 989 | vfactor = fls(src_h / dst_h / 2); |
1024 | if (ret) { | 990 | if (vfactor > FIMC_SHFACTOR / 2) { |
1025 | dev_err(ippdrv->dev, "failed to get ratio vertical.\n"); | 991 | dev_err(ippdrv->dev, "failed to get ratio vertical.\n"); |
1026 | return ret; | 992 | return -EINVAL; |
1027 | } | 993 | } |
1028 | 994 | ||
1029 | pre_dst_width = src_w / pre_hratio; | 995 | pre_dst_width = src_w >> hfactor; |
1030 | pre_dst_height = src_h / pre_vratio; | 996 | pre_dst_height = src_h >> vfactor; |
1031 | DRM_DEBUG_KMS("pre_dst_width[%d]pre_dst_height[%d]\n", | 997 | DRM_DEBUG_KMS("pre_dst_width[%d]pre_dst_height[%d]\n", |
1032 | pre_dst_width, pre_dst_height); | 998 | pre_dst_width, pre_dst_height); |
1033 | DRM_DEBUG_KMS("pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n", | 999 | DRM_DEBUG_KMS("hfactor[%d]vfactor[%d]\n", hfactor, vfactor); |
1034 | pre_hratio, hfactor, pre_vratio, vfactor); | ||
1035 | 1000 | ||
1036 | sc->hratio = (src_w << 14) / (dst_w << hfactor); | 1001 | sc->hratio = (src_w << 14) / (dst_w << hfactor); |
1037 | sc->vratio = (src_h << 14) / (dst_h << vfactor); | 1002 | sc->vratio = (src_h << 14) / (dst_h << vfactor); |
@@ -1044,13 +1009,13 @@ static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, | |||
1044 | DRM_DEBUG_KMS("shfactor[%d]\n", shfactor); | 1009 | DRM_DEBUG_KMS("shfactor[%d]\n", shfactor); |
1045 | 1010 | ||
1046 | cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) | | 1011 | cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) | |
1047 | EXYNOS_CISCPRERATIO_PREHORRATIO(pre_hratio) | | 1012 | EXYNOS_CISCPRERATIO_PREHORRATIO(1 << hfactor) | |
1048 | EXYNOS_CISCPRERATIO_PREVERRATIO(pre_vratio)); | 1013 | EXYNOS_CISCPRERATIO_PREVERRATIO(1 << vfactor)); |
1049 | fimc_write(cfg, EXYNOS_CISCPRERATIO); | 1014 | fimc_write(ctx, cfg, EXYNOS_CISCPRERATIO); |
1050 | 1015 | ||
1051 | cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) | | 1016 | cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) | |
1052 | EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height)); | 1017 | EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height)); |
1053 | fimc_write(cfg, EXYNOS_CISCPREDST); | 1018 | fimc_write(ctx, cfg, EXYNOS_CISCPREDST); |
1054 | 1019 | ||
1055 | return ret; | 1020 | return ret; |
1056 | } | 1021 | } |
@@ -1064,7 +1029,7 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc) | |||
1064 | DRM_DEBUG_KMS("hratio[%d]vratio[%d]\n", | 1029 | DRM_DEBUG_KMS("hratio[%d]vratio[%d]\n", |
1065 | sc->hratio, sc->vratio); | 1030 | sc->hratio, sc->vratio); |
1066 | 1031 | ||
1067 | cfg = fimc_read(EXYNOS_CISCCTRL); | 1032 | cfg = fimc_read(ctx, EXYNOS_CISCCTRL); |
1068 | cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS | | 1033 | cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS | |
1069 | EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V | | 1034 | EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V | |
1070 | EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK | | 1035 | EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK | |
@@ -1084,14 +1049,14 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc) | |||
1084 | 1049 | ||
1085 | cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) | | 1050 | cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) | |
1086 | EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6))); | 1051 | EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6))); |
1087 | fimc_write(cfg, EXYNOS_CISCCTRL); | 1052 | fimc_write(ctx, cfg, EXYNOS_CISCCTRL); |
1088 | 1053 | ||
1089 | cfg_ext = fimc_read(EXYNOS_CIEXTEN); | 1054 | cfg_ext = fimc_read(ctx, EXYNOS_CIEXTEN); |
1090 | cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK; | 1055 | cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK; |
1091 | cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK; | 1056 | cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK; |
1092 | cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) | | 1057 | cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) | |
1093 | EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio)); | 1058 | EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio)); |
1094 | fimc_write(cfg_ext, EXYNOS_CIEXTEN); | 1059 | fimc_write(ctx, cfg_ext, EXYNOS_CIEXTEN); |
1095 | } | 1060 | } |
1096 | 1061 | ||
1097 | static int fimc_dst_set_size(struct device *dev, int swap, | 1062 | static int fimc_dst_set_size(struct device *dev, int swap, |
@@ -1109,12 +1074,12 @@ static int fimc_dst_set_size(struct device *dev, int swap, | |||
1109 | cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) | | 1074 | cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) | |
1110 | EXYNOS_ORGOSIZE_VERTICAL(img_sz.vsize)); | 1075 | EXYNOS_ORGOSIZE_VERTICAL(img_sz.vsize)); |
1111 | 1076 | ||
1112 | fimc_write(cfg, EXYNOS_ORGOSIZE); | 1077 | fimc_write(ctx, cfg, EXYNOS_ORGOSIZE); |
1113 | 1078 | ||
1114 | DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h); | 1079 | DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h); |
1115 | 1080 | ||
1116 | /* CSC ITU */ | 1081 | /* CSC ITU */ |
1117 | cfg = fimc_read(EXYNOS_CIGCTRL); | 1082 | cfg = fimc_read(ctx, EXYNOS_CIGCTRL); |
1118 | cfg &= ~EXYNOS_CIGCTRL_CSC_MASK; | 1083 | cfg &= ~EXYNOS_CIGCTRL_CSC_MASK; |
1119 | 1084 | ||
1120 | if (sz->hsize >= FIMC_WIDTH_ITU_709) | 1085 | if (sz->hsize >= FIMC_WIDTH_ITU_709) |
@@ -1122,7 +1087,7 @@ static int fimc_dst_set_size(struct device *dev, int swap, | |||
1122 | else | 1087 | else |
1123 | cfg |= EXYNOS_CIGCTRL_CSC_ITU601; | 1088 | cfg |= EXYNOS_CIGCTRL_CSC_ITU601; |
1124 | 1089 | ||
1125 | fimc_write(cfg, EXYNOS_CIGCTRL); | 1090 | fimc_write(ctx, cfg, EXYNOS_CIGCTRL); |
1126 | 1091 | ||
1127 | if (swap) { | 1092 | if (swap) { |
1128 | img_pos.w = pos->h; | 1093 | img_pos.w = pos->h; |
@@ -1132,41 +1097,38 @@ static int fimc_dst_set_size(struct device *dev, int swap, | |||
1132 | } | 1097 | } |
1133 | 1098 | ||
1134 | /* target image size */ | 1099 | /* target image size */ |
1135 | cfg = fimc_read(EXYNOS_CITRGFMT); | 1100 | cfg = fimc_read(ctx, EXYNOS_CITRGFMT); |
1136 | cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK | | 1101 | cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK | |
1137 | EXYNOS_CITRGFMT_TARGETV_MASK); | 1102 | EXYNOS_CITRGFMT_TARGETV_MASK); |
1138 | cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(img_pos.w) | | 1103 | cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(img_pos.w) | |
1139 | EXYNOS_CITRGFMT_TARGETVSIZE(img_pos.h)); | 1104 | EXYNOS_CITRGFMT_TARGETVSIZE(img_pos.h)); |
1140 | fimc_write(cfg, EXYNOS_CITRGFMT); | 1105 | fimc_write(ctx, cfg, EXYNOS_CITRGFMT); |
1141 | 1106 | ||
1142 | /* target area */ | 1107 | /* target area */ |
1143 | cfg = EXYNOS_CITAREA_TARGET_AREA(img_pos.w * img_pos.h); | 1108 | cfg = EXYNOS_CITAREA_TARGET_AREA(img_pos.w * img_pos.h); |
1144 | fimc_write(cfg, EXYNOS_CITAREA); | 1109 | fimc_write(ctx, cfg, EXYNOS_CITAREA); |
1145 | 1110 | ||
1146 | /* offset Y(RGB), Cb, Cr */ | 1111 | /* offset Y(RGB), Cb, Cr */ |
1147 | cfg = (EXYNOS_CIOYOFF_HORIZONTAL(img_pos.x) | | 1112 | cfg = (EXYNOS_CIOYOFF_HORIZONTAL(img_pos.x) | |
1148 | EXYNOS_CIOYOFF_VERTICAL(img_pos.y)); | 1113 | EXYNOS_CIOYOFF_VERTICAL(img_pos.y)); |
1149 | fimc_write(cfg, EXYNOS_CIOYOFF); | 1114 | fimc_write(ctx, cfg, EXYNOS_CIOYOFF); |
1150 | cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(img_pos.x) | | 1115 | cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(img_pos.x) | |
1151 | EXYNOS_CIOCBOFF_VERTICAL(img_pos.y)); | 1116 | EXYNOS_CIOCBOFF_VERTICAL(img_pos.y)); |
1152 | fimc_write(cfg, EXYNOS_CIOCBOFF); | 1117 | fimc_write(ctx, cfg, EXYNOS_CIOCBOFF); |
1153 | cfg = (EXYNOS_CIOCROFF_HORIZONTAL(img_pos.x) | | 1118 | cfg = (EXYNOS_CIOCROFF_HORIZONTAL(img_pos.x) | |
1154 | EXYNOS_CIOCROFF_VERTICAL(img_pos.y)); | 1119 | EXYNOS_CIOCROFF_VERTICAL(img_pos.y)); |
1155 | fimc_write(cfg, EXYNOS_CIOCROFF); | 1120 | fimc_write(ctx, cfg, EXYNOS_CIOCROFF); |
1156 | 1121 | ||
1157 | return 0; | 1122 | return 0; |
1158 | } | 1123 | } |
1159 | 1124 | ||
1160 | static int fimc_dst_get_buf_seq(struct fimc_context *ctx) | 1125 | static int fimc_dst_get_buf_count(struct fimc_context *ctx) |
1161 | { | 1126 | { |
1162 | u32 cfg, i, buf_num = 0; | 1127 | u32 cfg, buf_num; |
1163 | u32 mask = 0x00000001; | ||
1164 | 1128 | ||
1165 | cfg = fimc_read(EXYNOS_CIFCNTSEQ); | 1129 | cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ); |
1166 | 1130 | ||
1167 | for (i = 0; i < FIMC_REG_SZ; i++) | 1131 | buf_num = hweight32(cfg); |
1168 | if (cfg & (mask << i)) | ||
1169 | buf_num++; | ||
1170 | 1132 | ||
1171 | DRM_DEBUG_KMS("buf_num[%d]\n", buf_num); | 1133 | DRM_DEBUG_KMS("buf_num[%d]\n", buf_num); |
1172 | 1134 | ||
@@ -1181,13 +1143,14 @@ static int fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id, | |||
1181 | u32 cfg; | 1143 | u32 cfg; |
1182 | u32 mask = 0x00000001 << buf_id; | 1144 | u32 mask = 0x00000001 << buf_id; |
1183 | int ret = 0; | 1145 | int ret = 0; |
1146 | unsigned long flags; | ||
1184 | 1147 | ||
1185 | DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type); | 1148 | DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type); |
1186 | 1149 | ||
1187 | mutex_lock(&ctx->lock); | 1150 | spin_lock_irqsave(&ctx->lock, flags); |
1188 | 1151 | ||
1189 | /* mask register set */ | 1152 | /* mask register set */ |
1190 | cfg = fimc_read(EXYNOS_CIFCNTSEQ); | 1153 | cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ); |
1191 | 1154 | ||
1192 | switch (buf_type) { | 1155 | switch (buf_type) { |
1193 | case IPP_BUF_ENQUEUE: | 1156 | case IPP_BUF_ENQUEUE: |
@@ -1205,20 +1168,20 @@ static int fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id, | |||
1205 | /* sequence id */ | 1168 | /* sequence id */ |
1206 | cfg &= ~mask; | 1169 | cfg &= ~mask; |
1207 | cfg |= (enable << buf_id); | 1170 | cfg |= (enable << buf_id); |
1208 | fimc_write(cfg, EXYNOS_CIFCNTSEQ); | 1171 | fimc_write(ctx, cfg, EXYNOS_CIFCNTSEQ); |
1209 | 1172 | ||
1210 | /* interrupt enable */ | 1173 | /* interrupt enable */ |
1211 | if (buf_type == IPP_BUF_ENQUEUE && | 1174 | if (buf_type == IPP_BUF_ENQUEUE && |
1212 | fimc_dst_get_buf_seq(ctx) >= FIMC_BUF_START) | 1175 | fimc_dst_get_buf_count(ctx) >= FIMC_BUF_START) |
1213 | fimc_handle_irq(ctx, true, false, true); | 1176 | fimc_mask_irq(ctx, true); |
1214 | 1177 | ||
1215 | /* interrupt disable */ | 1178 | /* interrupt disable */ |
1216 | if (buf_type == IPP_BUF_DEQUEUE && | 1179 | if (buf_type == IPP_BUF_DEQUEUE && |
1217 | fimc_dst_get_buf_seq(ctx) <= FIMC_BUF_STOP) | 1180 | fimc_dst_get_buf_count(ctx) <= FIMC_BUF_STOP) |
1218 | fimc_handle_irq(ctx, false, false, true); | 1181 | fimc_mask_irq(ctx, false); |
1219 | 1182 | ||
1220 | err_unlock: | 1183 | err_unlock: |
1221 | mutex_unlock(&ctx->lock); | 1184 | spin_unlock_irqrestore(&ctx->lock, flags); |
1222 | return ret; | 1185 | return ret; |
1223 | } | 1186 | } |
1224 | 1187 | ||
@@ -1252,25 +1215,25 @@ static int fimc_dst_set_addr(struct device *dev, | |||
1252 | case IPP_BUF_ENQUEUE: | 1215 | case IPP_BUF_ENQUEUE: |
1253 | config = &property->config[EXYNOS_DRM_OPS_DST]; | 1216 | config = &property->config[EXYNOS_DRM_OPS_DST]; |
1254 | 1217 | ||
1255 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y], | 1218 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y], |
1256 | EXYNOS_CIOYSA(buf_id)); | 1219 | EXYNOS_CIOYSA(buf_id)); |
1257 | 1220 | ||
1258 | if (config->fmt == DRM_FORMAT_YVU420) { | 1221 | if (config->fmt == DRM_FORMAT_YVU420) { |
1259 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR], | 1222 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], |
1260 | EXYNOS_CIOCBSA(buf_id)); | 1223 | EXYNOS_CIOCBSA(buf_id)); |
1261 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB], | 1224 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], |
1262 | EXYNOS_CIOCRSA(buf_id)); | 1225 | EXYNOS_CIOCRSA(buf_id)); |
1263 | } else { | 1226 | } else { |
1264 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB], | 1227 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], |
1265 | EXYNOS_CIOCBSA(buf_id)); | 1228 | EXYNOS_CIOCBSA(buf_id)); |
1266 | fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR], | 1229 | fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], |
1267 | EXYNOS_CIOCRSA(buf_id)); | 1230 | EXYNOS_CIOCRSA(buf_id)); |
1268 | } | 1231 | } |
1269 | break; | 1232 | break; |
1270 | case IPP_BUF_DEQUEUE: | 1233 | case IPP_BUF_DEQUEUE: |
1271 | fimc_write(0x0, EXYNOS_CIOYSA(buf_id)); | 1234 | fimc_write(ctx, 0x0, EXYNOS_CIOYSA(buf_id)); |
1272 | fimc_write(0x0, EXYNOS_CIOCBSA(buf_id)); | 1235 | fimc_write(ctx, 0x0, EXYNOS_CIOCBSA(buf_id)); |
1273 | fimc_write(0x0, EXYNOS_CIOCRSA(buf_id)); | 1236 | fimc_write(ctx, 0x0, EXYNOS_CIOCRSA(buf_id)); |
1274 | break; | 1237 | break; |
1275 | default: | 1238 | default: |
1276 | /* bypass */ | 1239 | /* bypass */ |
@@ -1342,11 +1305,7 @@ static irqreturn_t fimc_irq_handler(int irq, void *dev_id) | |||
1342 | 1305 | ||
1343 | static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | 1306 | static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) |
1344 | { | 1307 | { |
1345 | struct drm_exynos_ipp_prop_list *prop_list; | 1308 | struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list; |
1346 | |||
1347 | prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL); | ||
1348 | if (!prop_list) | ||
1349 | return -ENOMEM; | ||
1350 | 1309 | ||
1351 | prop_list->version = 1; | 1310 | prop_list->version = 1; |
1352 | prop_list->writeback = 1; | 1311 | prop_list->writeback = 1; |
@@ -1371,8 +1330,6 @@ static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | |||
1371 | prop_list->scale_min.hsize = FIMC_SCALE_MIN; | 1330 | prop_list->scale_min.hsize = FIMC_SCALE_MIN; |
1372 | prop_list->scale_min.vsize = FIMC_SCALE_MIN; | 1331 | prop_list->scale_min.vsize = FIMC_SCALE_MIN; |
1373 | 1332 | ||
1374 | ippdrv->prop_list = prop_list; | ||
1375 | |||
1376 | return 0; | 1333 | return 0; |
1377 | } | 1334 | } |
1378 | 1335 | ||
@@ -1395,7 +1352,7 @@ static int fimc_ippdrv_check_property(struct device *dev, | |||
1395 | { | 1352 | { |
1396 | struct fimc_context *ctx = get_fimc_context(dev); | 1353 | struct fimc_context *ctx = get_fimc_context(dev); |
1397 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 1354 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; |
1398 | struct drm_exynos_ipp_prop_list *pp = ippdrv->prop_list; | 1355 | struct drm_exynos_ipp_prop_list *pp = &ippdrv->prop_list; |
1399 | struct drm_exynos_ipp_config *config; | 1356 | struct drm_exynos_ipp_config *config; |
1400 | struct drm_exynos_pos *pos; | 1357 | struct drm_exynos_pos *pos; |
1401 | struct drm_exynos_sz *sz; | 1358 | struct drm_exynos_sz *sz; |
@@ -1508,15 +1465,15 @@ static void fimc_clear_addr(struct fimc_context *ctx) | |||
1508 | int i; | 1465 | int i; |
1509 | 1466 | ||
1510 | for (i = 0; i < FIMC_MAX_SRC; i++) { | 1467 | for (i = 0; i < FIMC_MAX_SRC; i++) { |
1511 | fimc_write(0, EXYNOS_CIIYSA(i)); | 1468 | fimc_write(ctx, 0, EXYNOS_CIIYSA(i)); |
1512 | fimc_write(0, EXYNOS_CIICBSA(i)); | 1469 | fimc_write(ctx, 0, EXYNOS_CIICBSA(i)); |
1513 | fimc_write(0, EXYNOS_CIICRSA(i)); | 1470 | fimc_write(ctx, 0, EXYNOS_CIICRSA(i)); |
1514 | } | 1471 | } |
1515 | 1472 | ||
1516 | for (i = 0; i < FIMC_MAX_DST; i++) { | 1473 | for (i = 0; i < FIMC_MAX_DST; i++) { |
1517 | fimc_write(0, EXYNOS_CIOYSA(i)); | 1474 | fimc_write(ctx, 0, EXYNOS_CIOYSA(i)); |
1518 | fimc_write(0, EXYNOS_CIOCBSA(i)); | 1475 | fimc_write(ctx, 0, EXYNOS_CIOCBSA(i)); |
1519 | fimc_write(0, EXYNOS_CIOCRSA(i)); | 1476 | fimc_write(ctx, 0, EXYNOS_CIOCRSA(i)); |
1520 | } | 1477 | } |
1521 | } | 1478 | } |
1522 | 1479 | ||
@@ -1556,7 +1513,7 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) | |||
1556 | 1513 | ||
1557 | property = &c_node->property; | 1514 | property = &c_node->property; |
1558 | 1515 | ||
1559 | fimc_handle_irq(ctx, true, false, true); | 1516 | fimc_mask_irq(ctx, true); |
1560 | 1517 | ||
1561 | for_each_ipp_ops(i) { | 1518 | for_each_ipp_ops(i) { |
1562 | config = &property->config[i]; | 1519 | config = &property->config[i]; |
@@ -1582,10 +1539,10 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) | |||
1582 | fimc_handle_lastend(ctx, false); | 1539 | fimc_handle_lastend(ctx, false); |
1583 | 1540 | ||
1584 | /* setup dma */ | 1541 | /* setup dma */ |
1585 | cfg0 = fimc_read(EXYNOS_MSCTRL); | 1542 | cfg0 = fimc_read(ctx, EXYNOS_MSCTRL); |
1586 | cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK; | 1543 | cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK; |
1587 | cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY; | 1544 | cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY; |
1588 | fimc_write(cfg0, EXYNOS_MSCTRL); | 1545 | fimc_write(ctx, cfg0, EXYNOS_MSCTRL); |
1589 | break; | 1546 | break; |
1590 | case IPP_CMD_WB: | 1547 | case IPP_CMD_WB: |
1591 | fimc_set_type_ctrl(ctx, FIMC_WB_A); | 1548 | fimc_set_type_ctrl(ctx, FIMC_WB_A); |
@@ -1610,41 +1567,33 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) | |||
1610 | } | 1567 | } |
1611 | 1568 | ||
1612 | /* Reset status */ | 1569 | /* Reset status */ |
1613 | fimc_write(0x0, EXYNOS_CISTATUS); | 1570 | fimc_write(ctx, 0x0, EXYNOS_CISTATUS); |
1614 | 1571 | ||
1615 | cfg0 = fimc_read(EXYNOS_CIIMGCPT); | 1572 | cfg0 = fimc_read(ctx, EXYNOS_CIIMGCPT); |
1616 | cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC; | 1573 | cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC; |
1617 | cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC; | 1574 | cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC; |
1618 | 1575 | ||
1619 | /* Scaler */ | 1576 | /* Scaler */ |
1620 | cfg1 = fimc_read(EXYNOS_CISCCTRL); | 1577 | cfg1 = fimc_read(ctx, EXYNOS_CISCCTRL); |
1621 | cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK; | 1578 | cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK; |
1622 | cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE | | 1579 | cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE | |
1623 | EXYNOS_CISCCTRL_SCALERSTART); | 1580 | EXYNOS_CISCCTRL_SCALERSTART); |
1624 | 1581 | ||
1625 | fimc_write(cfg1, EXYNOS_CISCCTRL); | 1582 | fimc_write(ctx, cfg1, EXYNOS_CISCCTRL); |
1626 | 1583 | ||
1627 | /* Enable image capture*/ | 1584 | /* Enable image capture*/ |
1628 | cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN; | 1585 | cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN; |
1629 | fimc_write(cfg0, EXYNOS_CIIMGCPT); | 1586 | fimc_write(ctx, cfg0, EXYNOS_CIIMGCPT); |
1630 | 1587 | ||
1631 | /* Disable frame end irq */ | 1588 | /* Disable frame end irq */ |
1632 | cfg0 = fimc_read(EXYNOS_CIGCTRL); | 1589 | fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE); |
1633 | cfg0 &= ~EXYNOS_CIGCTRL_IRQ_END_DISABLE; | ||
1634 | fimc_write(cfg0, EXYNOS_CIGCTRL); | ||
1635 | 1590 | ||
1636 | cfg0 = fimc_read(EXYNOS_CIOCTRL); | 1591 | fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK); |
1637 | cfg0 &= ~EXYNOS_CIOCTRL_WEAVE_MASK; | ||
1638 | fimc_write(cfg0, EXYNOS_CIOCTRL); | ||
1639 | 1592 | ||
1640 | if (cmd == IPP_CMD_M2M) { | 1593 | if (cmd == IPP_CMD_M2M) { |
1641 | cfg0 = fimc_read(EXYNOS_MSCTRL); | 1594 | fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); |
1642 | cfg0 |= EXYNOS_MSCTRL_ENVID; | ||
1643 | fimc_write(cfg0, EXYNOS_MSCTRL); | ||
1644 | 1595 | ||
1645 | cfg0 = fimc_read(EXYNOS_MSCTRL); | 1596 | fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); |
1646 | cfg0 |= EXYNOS_MSCTRL_ENVID; | ||
1647 | fimc_write(cfg0, EXYNOS_MSCTRL); | ||
1648 | } | 1597 | } |
1649 | 1598 | ||
1650 | return 0; | 1599 | return 0; |
@@ -1661,10 +1610,10 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) | |||
1661 | switch (cmd) { | 1610 | switch (cmd) { |
1662 | case IPP_CMD_M2M: | 1611 | case IPP_CMD_M2M: |
1663 | /* Source clear */ | 1612 | /* Source clear */ |
1664 | cfg = fimc_read(EXYNOS_MSCTRL); | 1613 | cfg = fimc_read(ctx, EXYNOS_MSCTRL); |
1665 | cfg &= ~EXYNOS_MSCTRL_INPUT_MASK; | 1614 | cfg &= ~EXYNOS_MSCTRL_INPUT_MASK; |
1666 | cfg &= ~EXYNOS_MSCTRL_ENVID; | 1615 | cfg &= ~EXYNOS_MSCTRL_ENVID; |
1667 | fimc_write(cfg, EXYNOS_MSCTRL); | 1616 | fimc_write(ctx, cfg, EXYNOS_MSCTRL); |
1668 | break; | 1617 | break; |
1669 | case IPP_CMD_WB: | 1618 | case IPP_CMD_WB: |
1670 | exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb); | 1619 | exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb); |
@@ -1675,25 +1624,20 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) | |||
1675 | break; | 1624 | break; |
1676 | } | 1625 | } |
1677 | 1626 | ||
1678 | fimc_handle_irq(ctx, false, false, true); | 1627 | fimc_mask_irq(ctx, false); |
1679 | 1628 | ||
1680 | /* reset sequence */ | 1629 | /* reset sequence */ |
1681 | fimc_write(0x0, EXYNOS_CIFCNTSEQ); | 1630 | fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ); |
1682 | 1631 | ||
1683 | /* Scaler disable */ | 1632 | /* Scaler disable */ |
1684 | cfg = fimc_read(EXYNOS_CISCCTRL); | 1633 | fimc_clear_bits(ctx, EXYNOS_CISCCTRL, EXYNOS_CISCCTRL_SCALERSTART); |
1685 | cfg &= ~EXYNOS_CISCCTRL_SCALERSTART; | ||
1686 | fimc_write(cfg, EXYNOS_CISCCTRL); | ||
1687 | 1634 | ||
1688 | /* Disable image capture */ | 1635 | /* Disable image capture */ |
1689 | cfg = fimc_read(EXYNOS_CIIMGCPT); | 1636 | fimc_clear_bits(ctx, EXYNOS_CIIMGCPT, |
1690 | cfg &= ~(EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); | 1637 | EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); |
1691 | fimc_write(cfg, EXYNOS_CIIMGCPT); | ||
1692 | 1638 | ||
1693 | /* Enable frame end irq */ | 1639 | /* Enable frame end irq */ |
1694 | cfg = fimc_read(EXYNOS_CIGCTRL); | 1640 | fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE); |
1695 | cfg |= EXYNOS_CIGCTRL_IRQ_END_DISABLE; | ||
1696 | fimc_write(cfg, EXYNOS_CIGCTRL); | ||
1697 | } | 1641 | } |
1698 | 1642 | ||
1699 | static void fimc_put_clocks(struct fimc_context *ctx) | 1643 | static void fimc_put_clocks(struct fimc_context *ctx) |
@@ -1848,7 +1792,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1848 | 1792 | ||
1849 | DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv); | 1793 | DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv); |
1850 | 1794 | ||
1851 | mutex_init(&ctx->lock); | 1795 | spin_lock_init(&ctx->lock); |
1852 | platform_set_drvdata(pdev, ctx); | 1796 | platform_set_drvdata(pdev, ctx); |
1853 | 1797 | ||
1854 | pm_runtime_set_active(dev); | 1798 | pm_runtime_set_active(dev); |
@@ -1879,7 +1823,6 @@ static int fimc_remove(struct platform_device *pdev) | |||
1879 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 1823 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; |
1880 | 1824 | ||
1881 | exynos_drm_ippdrv_unregister(ippdrv); | 1825 | exynos_drm_ippdrv_unregister(ippdrv); |
1882 | mutex_destroy(&ctx->lock); | ||
1883 | 1826 | ||
1884 | fimc_put_clocks(ctx); | 1827 | fimc_put_clocks(ctx); |
1885 | pm_runtime_set_suspended(dev); | 1828 | pm_runtime_set_suspended(dev); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 40fd6ccfcd6f..bb45ab2e7384 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
21 | #include <linux/pm_runtime.h> | 21 | #include <linux/pm_runtime.h> |
22 | #include <linux/component.h> | ||
22 | 23 | ||
23 | #include <video/of_display_timing.h> | 24 | #include <video/of_display_timing.h> |
24 | #include <video/of_videomode.h> | 25 | #include <video/of_videomode.h> |
@@ -38,6 +39,7 @@ | |||
38 | */ | 39 | */ |
39 | 40 | ||
40 | #define FIMD_DEFAULT_FRAMERATE 60 | 41 | #define FIMD_DEFAULT_FRAMERATE 60 |
42 | #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 | ||
41 | 43 | ||
42 | /* position control register for hardware window 0, 2 ~ 4.*/ | 44 | /* position control register for hardware window 0, 2 ~ 4.*/ |
43 | #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) | 45 | #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) |
@@ -122,6 +124,7 @@ struct fimd_context { | |||
122 | 124 | ||
123 | struct exynos_drm_panel_info panel; | 125 | struct exynos_drm_panel_info panel; |
124 | struct fimd_driver_data *driver_data; | 126 | struct fimd_driver_data *driver_data; |
127 | struct exynos_drm_display *display; | ||
125 | }; | 128 | }; |
126 | 129 | ||
127 | static const struct of_device_id fimd_driver_dt_match[] = { | 130 | static const struct of_device_id fimd_driver_dt_match[] = { |
@@ -143,13 +146,57 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( | |||
143 | return (struct fimd_driver_data *)of_id->data; | 146 | return (struct fimd_driver_data *)of_id->data; |
144 | } | 147 | } |
145 | 148 | ||
149 | static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) | ||
150 | { | ||
151 | struct fimd_context *ctx = mgr->ctx; | ||
152 | |||
153 | if (ctx->suspended) | ||
154 | return; | ||
155 | |||
156 | atomic_set(&ctx->wait_vsync_event, 1); | ||
157 | |||
158 | /* | ||
159 | * wait for FIMD to signal VSYNC interrupt or return after | ||
160 | * timeout which is set to 50ms (refresh rate of 20). | ||
161 | */ | ||
162 | if (!wait_event_timeout(ctx->wait_vsync_queue, | ||
163 | !atomic_read(&ctx->wait_vsync_event), | ||
164 | HZ/20)) | ||
165 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | ||
166 | } | ||
167 | |||
168 | |||
169 | static void fimd_clear_channel(struct exynos_drm_manager *mgr) | ||
170 | { | ||
171 | struct fimd_context *ctx = mgr->ctx; | ||
172 | int win, ch_enabled = 0; | ||
173 | |||
174 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
175 | |||
176 | /* Check if any channel is enabled. */ | ||
177 | for (win = 0; win < WINDOWS_NR; win++) { | ||
178 | u32 val = readl(ctx->regs + SHADOWCON); | ||
179 | if (val & SHADOWCON_CHx_ENABLE(win)) { | ||
180 | val &= ~SHADOWCON_CHx_ENABLE(win); | ||
181 | writel(val, ctx->regs + SHADOWCON); | ||
182 | ch_enabled = 1; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /* Wait for vsync, as disable channel takes effect at next vsync */ | ||
187 | if (ch_enabled) | ||
188 | fimd_wait_for_vblank(mgr); | ||
189 | } | ||
190 | |||
146 | static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, | 191 | static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, |
147 | struct drm_device *drm_dev, int pipe) | 192 | struct drm_device *drm_dev) |
148 | { | 193 | { |
149 | struct fimd_context *ctx = mgr->ctx; | 194 | struct fimd_context *ctx = mgr->ctx; |
195 | struct exynos_drm_private *priv; | ||
196 | priv = drm_dev->dev_private; | ||
150 | 197 | ||
151 | ctx->drm_dev = drm_dev; | 198 | mgr->drm_dev = ctx->drm_dev = drm_dev; |
152 | ctx->pipe = pipe; | 199 | mgr->pipe = ctx->pipe = priv->pipe++; |
153 | 200 | ||
154 | /* | 201 | /* |
155 | * enable drm irq mode. | 202 | * enable drm irq mode. |
@@ -169,8 +216,14 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, | |||
169 | drm_dev->vblank_disable_allowed = true; | 216 | drm_dev->vblank_disable_allowed = true; |
170 | 217 | ||
171 | /* attach this sub driver to iommu mapping if supported. */ | 218 | /* attach this sub driver to iommu mapping if supported. */ |
172 | if (is_drm_iommu_supported(ctx->drm_dev)) | 219 | if (is_drm_iommu_supported(ctx->drm_dev)) { |
220 | /* | ||
221 | * If any channel is already active, iommu will throw | ||
222 | * a PAGE FAULT when enabled. So clear any channel if enabled. | ||
223 | */ | ||
224 | fimd_clear_channel(mgr); | ||
173 | drm_iommu_attach_device(ctx->drm_dev, ctx->dev); | 225 | drm_iommu_attach_device(ctx->drm_dev, ctx->dev); |
226 | } | ||
174 | 227 | ||
175 | return 0; | 228 | return 0; |
176 | } | 229 | } |
@@ -324,25 +377,6 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr) | |||
324 | } | 377 | } |
325 | } | 378 | } |
326 | 379 | ||
327 | static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) | ||
328 | { | ||
329 | struct fimd_context *ctx = mgr->ctx; | ||
330 | |||
331 | if (ctx->suspended) | ||
332 | return; | ||
333 | |||
334 | atomic_set(&ctx->wait_vsync_event, 1); | ||
335 | |||
336 | /* | ||
337 | * wait for FIMD to signal VSYNC interrupt or return after | ||
338 | * timeout which is set to 50ms (refresh rate of 20). | ||
339 | */ | ||
340 | if (!wait_event_timeout(ctx->wait_vsync_queue, | ||
341 | !atomic_read(&ctx->wait_vsync_event), | ||
342 | HZ/20)) | ||
343 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | ||
344 | } | ||
345 | |||
346 | static void fimd_win_mode_set(struct exynos_drm_manager *mgr, | 380 | static void fimd_win_mode_set(struct exynos_drm_manager *mgr, |
347 | struct exynos_drm_overlay *overlay) | 381 | struct exynos_drm_overlay *overlay) |
348 | { | 382 | { |
@@ -446,6 +480,19 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) | |||
446 | 480 | ||
447 | DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); | 481 | DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); |
448 | 482 | ||
483 | /* | ||
484 | * In case of exynos, setting dma-burst to 16Word causes permanent | ||
485 | * tearing for very small buffers, e.g. cursor buffer. Burst Mode | ||
486 | * switching which is based on overlay size is not recommended as | ||
487 | * overlay size varies alot towards the end of the screen and rapid | ||
488 | * movement causes unstable DMA which results into iommu crash/tear. | ||
489 | */ | ||
490 | |||
491 | if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { | ||
492 | val &= ~WINCONx_BURSTLEN_MASK; | ||
493 | val |= WINCONx_BURSTLEN_4WORD; | ||
494 | } | ||
495 | |||
449 | writel(val, ctx->regs + WINCON(win)); | 496 | writel(val, ctx->regs + WINCON(win)); |
450 | } | 497 | } |
451 | 498 | ||
@@ -656,19 +703,6 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) | |||
656 | win_data->enabled = false; | 703 | win_data->enabled = false; |
657 | } | 704 | } |
658 | 705 | ||
659 | static void fimd_clear_win(struct fimd_context *ctx, int win) | ||
660 | { | ||
661 | writel(0, ctx->regs + WINCON(win)); | ||
662 | writel(0, ctx->regs + VIDOSD_A(win)); | ||
663 | writel(0, ctx->regs + VIDOSD_B(win)); | ||
664 | writel(0, ctx->regs + VIDOSD_C(win)); | ||
665 | |||
666 | if (win == 1 || win == 2) | ||
667 | writel(0, ctx->regs + VIDOSD_D(win)); | ||
668 | |||
669 | fimd_shadow_protect_win(ctx, win, false); | ||
670 | } | ||
671 | |||
672 | static void fimd_window_suspend(struct exynos_drm_manager *mgr) | 706 | static void fimd_window_suspend(struct exynos_drm_manager *mgr) |
673 | { | 707 | { |
674 | struct fimd_context *ctx = mgr->ctx; | 708 | struct fimd_context *ctx = mgr->ctx; |
@@ -803,8 +837,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) | |||
803 | } | 837 | } |
804 | 838 | ||
805 | static struct exynos_drm_manager_ops fimd_manager_ops = { | 839 | static struct exynos_drm_manager_ops fimd_manager_ops = { |
806 | .initialize = fimd_mgr_initialize, | ||
807 | .remove = fimd_mgr_remove, | ||
808 | .dpms = fimd_dpms, | 840 | .dpms = fimd_dpms, |
809 | .mode_fixup = fimd_mode_fixup, | 841 | .mode_fixup = fimd_mode_fixup, |
810 | .mode_set = fimd_mode_set, | 842 | .mode_set = fimd_mode_set, |
@@ -849,20 +881,64 @@ out: | |||
849 | return IRQ_HANDLED; | 881 | return IRQ_HANDLED; |
850 | } | 882 | } |
851 | 883 | ||
884 | static int fimd_bind(struct device *dev, struct device *master, void *data) | ||
885 | { | ||
886 | struct fimd_context *ctx = fimd_manager.ctx; | ||
887 | struct drm_device *drm_dev = data; | ||
888 | |||
889 | fimd_mgr_initialize(&fimd_manager, drm_dev); | ||
890 | exynos_drm_crtc_create(&fimd_manager); | ||
891 | if (ctx->display) | ||
892 | exynos_drm_create_enc_conn(drm_dev, ctx->display); | ||
893 | |||
894 | return 0; | ||
895 | |||
896 | } | ||
897 | |||
898 | static void fimd_unbind(struct device *dev, struct device *master, | ||
899 | void *data) | ||
900 | { | ||
901 | struct exynos_drm_manager *mgr = dev_get_drvdata(dev); | ||
902 | struct fimd_context *ctx = fimd_manager.ctx; | ||
903 | struct drm_crtc *crtc = mgr->crtc; | ||
904 | |||
905 | fimd_dpms(mgr, DRM_MODE_DPMS_OFF); | ||
906 | |||
907 | if (ctx->display) | ||
908 | exynos_dpi_remove(dev); | ||
909 | |||
910 | fimd_mgr_remove(mgr); | ||
911 | |||
912 | crtc->funcs->destroy(crtc); | ||
913 | } | ||
914 | |||
915 | static const struct component_ops fimd_component_ops = { | ||
916 | .bind = fimd_bind, | ||
917 | .unbind = fimd_unbind, | ||
918 | }; | ||
919 | |||
852 | static int fimd_probe(struct platform_device *pdev) | 920 | static int fimd_probe(struct platform_device *pdev) |
853 | { | 921 | { |
854 | struct device *dev = &pdev->dev; | 922 | struct device *dev = &pdev->dev; |
855 | struct fimd_context *ctx; | 923 | struct fimd_context *ctx; |
856 | struct resource *res; | 924 | struct resource *res; |
857 | int win; | ||
858 | int ret = -EINVAL; | 925 | int ret = -EINVAL; |
859 | 926 | ||
860 | if (!dev->of_node) | 927 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, |
861 | return -ENODEV; | 928 | fimd_manager.type); |
929 | if (ret) | ||
930 | return ret; | ||
931 | |||
932 | if (!dev->of_node) { | ||
933 | ret = -ENODEV; | ||
934 | goto err_del_component; | ||
935 | } | ||
862 | 936 | ||
863 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | 937 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); |
864 | if (!ctx) | 938 | if (!ctx) { |
865 | return -ENOMEM; | 939 | ret = -ENOMEM; |
940 | goto err_del_component; | ||
941 | } | ||
866 | 942 | ||
867 | ctx->dev = dev; | 943 | ctx->dev = dev; |
868 | ctx->suspended = true; | 944 | ctx->suspended = true; |
@@ -875,32 +951,37 @@ static int fimd_probe(struct platform_device *pdev) | |||
875 | ctx->bus_clk = devm_clk_get(dev, "fimd"); | 951 | ctx->bus_clk = devm_clk_get(dev, "fimd"); |
876 | if (IS_ERR(ctx->bus_clk)) { | 952 | if (IS_ERR(ctx->bus_clk)) { |
877 | dev_err(dev, "failed to get bus clock\n"); | 953 | dev_err(dev, "failed to get bus clock\n"); |
878 | return PTR_ERR(ctx->bus_clk); | 954 | ret = PTR_ERR(ctx->bus_clk); |
955 | goto err_del_component; | ||
879 | } | 956 | } |
880 | 957 | ||
881 | ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); | 958 | ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); |
882 | if (IS_ERR(ctx->lcd_clk)) { | 959 | if (IS_ERR(ctx->lcd_clk)) { |
883 | dev_err(dev, "failed to get lcd clock\n"); | 960 | dev_err(dev, "failed to get lcd clock\n"); |
884 | return PTR_ERR(ctx->lcd_clk); | 961 | ret = PTR_ERR(ctx->lcd_clk); |
962 | goto err_del_component; | ||
885 | } | 963 | } |
886 | 964 | ||
887 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 965 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
888 | 966 | ||
889 | ctx->regs = devm_ioremap_resource(dev, res); | 967 | ctx->regs = devm_ioremap_resource(dev, res); |
890 | if (IS_ERR(ctx->regs)) | 968 | if (IS_ERR(ctx->regs)) { |
891 | return PTR_ERR(ctx->regs); | 969 | ret = PTR_ERR(ctx->regs); |
970 | goto err_del_component; | ||
971 | } | ||
892 | 972 | ||
893 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); | 973 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); |
894 | if (!res) { | 974 | if (!res) { |
895 | dev_err(dev, "irq request failed.\n"); | 975 | dev_err(dev, "irq request failed.\n"); |
896 | return -ENXIO; | 976 | ret = -ENXIO; |
977 | goto err_del_component; | ||
897 | } | 978 | } |
898 | 979 | ||
899 | ret = devm_request_irq(dev, res->start, fimd_irq_handler, | 980 | ret = devm_request_irq(dev, res->start, fimd_irq_handler, |
900 | 0, "drm_fimd", ctx); | 981 | 0, "drm_fimd", ctx); |
901 | if (ret) { | 982 | if (ret) { |
902 | dev_err(dev, "irq request failed.\n"); | 983 | dev_err(dev, "irq request failed.\n"); |
903 | return ret; | 984 | goto err_del_component; |
904 | } | 985 | } |
905 | 986 | ||
906 | ctx->driver_data = drm_fimd_get_driver_data(pdev); | 987 | ctx->driver_data = drm_fimd_get_driver_data(pdev); |
@@ -910,30 +991,34 @@ static int fimd_probe(struct platform_device *pdev) | |||
910 | platform_set_drvdata(pdev, &fimd_manager); | 991 | platform_set_drvdata(pdev, &fimd_manager); |
911 | 992 | ||
912 | fimd_manager.ctx = ctx; | 993 | fimd_manager.ctx = ctx; |
913 | exynos_drm_manager_register(&fimd_manager); | ||
914 | 994 | ||
915 | exynos_dpi_probe(ctx->dev); | 995 | ctx->display = exynos_dpi_probe(dev); |
996 | if (IS_ERR(ctx->display)) | ||
997 | return PTR_ERR(ctx->display); | ||
916 | 998 | ||
917 | pm_runtime_enable(dev); | 999 | pm_runtime_enable(&pdev->dev); |
918 | 1000 | ||
919 | for (win = 0; win < WINDOWS_NR; win++) | 1001 | ret = component_add(&pdev->dev, &fimd_component_ops); |
920 | fimd_clear_win(ctx, win); | 1002 | if (ret) |
1003 | goto err_disable_pm_runtime; | ||
921 | 1004 | ||
922 | return 0; | 1005 | return ret; |
1006 | |||
1007 | err_disable_pm_runtime: | ||
1008 | pm_runtime_disable(&pdev->dev); | ||
1009 | |||
1010 | err_del_component: | ||
1011 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); | ||
1012 | return ret; | ||
923 | } | 1013 | } |
924 | 1014 | ||
925 | static int fimd_remove(struct platform_device *pdev) | 1015 | static int fimd_remove(struct platform_device *pdev) |
926 | { | 1016 | { |
927 | struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); | ||
928 | |||
929 | exynos_dpi_remove(&pdev->dev); | ||
930 | |||
931 | exynos_drm_manager_unregister(&fimd_manager); | ||
932 | |||
933 | fimd_dpms(mgr, DRM_MODE_DPMS_OFF); | ||
934 | |||
935 | pm_runtime_disable(&pdev->dev); | 1017 | pm_runtime_disable(&pdev->dev); |
936 | 1018 | ||
1019 | component_del(&pdev->dev, &fimd_component_ops); | ||
1020 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); | ||
1021 | |||
937 | return 0; | 1022 | return 0; |
938 | } | 1023 | } |
939 | 1024 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 42d2904d88c7..163a054922cb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
@@ -612,22 +612,20 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, | |||
612 | args->pitch = args->width * ((args->bpp + 7) / 8); | 612 | args->pitch = args->width * ((args->bpp + 7) / 8); |
613 | args->size = args->pitch * args->height; | 613 | args->size = args->pitch * args->height; |
614 | 614 | ||
615 | exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG | | 615 | if (is_drm_iommu_supported(dev)) { |
616 | EXYNOS_BO_WC, args->size); | 616 | exynos_gem_obj = exynos_drm_gem_create(dev, |
617 | /* | 617 | EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC, |
618 | * If physically contiguous memory allocation fails and if IOMMU is | 618 | args->size); |
619 | * supported then try to get buffer from non physically contiguous | 619 | } else { |
620 | * memory area. | ||
621 | */ | ||
622 | if (IS_ERR(exynos_gem_obj) && is_drm_iommu_supported(dev)) { | ||
623 | dev_warn(dev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); | ||
624 | exynos_gem_obj = exynos_drm_gem_create(dev, | 620 | exynos_gem_obj = exynos_drm_gem_create(dev, |
625 | EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC, | 621 | EXYNOS_BO_CONTIG | EXYNOS_BO_WC, |
626 | args->size); | 622 | args->size); |
627 | } | 623 | } |
628 | 624 | ||
629 | if (IS_ERR(exynos_gem_obj)) | 625 | if (IS_ERR(exynos_gem_obj)) { |
626 | dev_warn(dev->dev, "FB allocation failed.\n"); | ||
630 | return PTR_ERR(exynos_gem_obj); | 627 | return PTR_ERR(exynos_gem_obj); |
628 | } | ||
631 | 629 | ||
632 | ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, | 630 | ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, |
633 | &args->handle); | 631 | &args->handle); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index fa75059a6104..9e3ff1672965 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c | |||
@@ -1335,11 +1335,7 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id) | |||
1335 | 1335 | ||
1336 | static int gsc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | 1336 | static int gsc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) |
1337 | { | 1337 | { |
1338 | struct drm_exynos_ipp_prop_list *prop_list; | 1338 | struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list; |
1339 | |||
1340 | prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL); | ||
1341 | if (!prop_list) | ||
1342 | return -ENOMEM; | ||
1343 | 1339 | ||
1344 | prop_list->version = 1; | 1340 | prop_list->version = 1; |
1345 | prop_list->writeback = 1; | 1341 | prop_list->writeback = 1; |
@@ -1363,8 +1359,6 @@ static int gsc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | |||
1363 | prop_list->scale_min.hsize = GSC_SCALE_MIN; | 1359 | prop_list->scale_min.hsize = GSC_SCALE_MIN; |
1364 | prop_list->scale_min.vsize = GSC_SCALE_MIN; | 1360 | prop_list->scale_min.vsize = GSC_SCALE_MIN; |
1365 | 1361 | ||
1366 | ippdrv->prop_list = prop_list; | ||
1367 | |||
1368 | return 0; | 1362 | return 0; |
1369 | } | 1363 | } |
1370 | 1364 | ||
@@ -1387,7 +1381,7 @@ static int gsc_ippdrv_check_property(struct device *dev, | |||
1387 | { | 1381 | { |
1388 | struct gsc_context *ctx = get_gsc_context(dev); | 1382 | struct gsc_context *ctx = get_gsc_context(dev); |
1389 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 1383 | struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; |
1390 | struct drm_exynos_ipp_prop_list *pp = ippdrv->prop_list; | 1384 | struct drm_exynos_ipp_prop_list *pp = &ippdrv->prop_list; |
1391 | struct drm_exynos_ipp_config *config; | 1385 | struct drm_exynos_ipp_config *config; |
1392 | struct drm_exynos_pos *pos; | 1386 | struct drm_exynos_pos *pos; |
1393 | struct drm_exynos_sz *sz; | 1387 | struct drm_exynos_sz *sz; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 09312b877470..603a79602f31 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c | |||
@@ -167,6 +167,13 @@ static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj, | |||
167 | return 0; | 167 | return 0; |
168 | } | 168 | } |
169 | 169 | ||
170 | static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) | ||
171 | { | ||
172 | mutex_lock(lock); | ||
173 | idr_remove(id_idr, id); | ||
174 | mutex_unlock(lock); | ||
175 | } | ||
176 | |||
170 | static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) | 177 | static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) |
171 | { | 178 | { |
172 | void *obj; | 179 | void *obj; |
@@ -276,11 +283,6 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id) | |||
276 | 283 | ||
277 | DRM_DEBUG_KMS("prop_id[%d]\n", prop_id); | 284 | DRM_DEBUG_KMS("prop_id[%d]\n", prop_id); |
278 | 285 | ||
279 | if (list_empty(&exynos_drm_ippdrv_list)) { | ||
280 | DRM_DEBUG_KMS("ippdrv_list is empty.\n"); | ||
281 | return ERR_PTR(-ENODEV); | ||
282 | } | ||
283 | |||
284 | /* | 286 | /* |
285 | * This case is search ipp driver by prop_id handle. | 287 | * This case is search ipp driver by prop_id handle. |
286 | * sometimes, ipp subsystem find driver by prop_id. | 288 | * sometimes, ipp subsystem find driver by prop_id. |
@@ -289,11 +291,14 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id) | |||
289 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 291 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
290 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv); | 292 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv); |
291 | 293 | ||
292 | if (!list_empty(&ippdrv->cmd_list)) { | 294 | mutex_lock(&ippdrv->cmd_lock); |
293 | list_for_each_entry(c_node, &ippdrv->cmd_list, list) | 295 | list_for_each_entry(c_node, &ippdrv->cmd_list, list) { |
294 | if (c_node->property.prop_id == prop_id) | 296 | if (c_node->property.prop_id == prop_id) { |
295 | return ippdrv; | 297 | mutex_unlock(&ippdrv->cmd_lock); |
298 | return ippdrv; | ||
299 | } | ||
296 | } | 300 | } |
301 | mutex_unlock(&ippdrv->cmd_lock); | ||
297 | } | 302 | } |
298 | 303 | ||
299 | return ERR_PTR(-ENODEV); | 304 | return ERR_PTR(-ENODEV); |
@@ -325,6 +330,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, | |||
325 | if (!prop_list->ipp_id) { | 330 | if (!prop_list->ipp_id) { |
326 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) | 331 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) |
327 | count++; | 332 | count++; |
333 | |||
328 | /* | 334 | /* |
329 | * Supports ippdrv list count for user application. | 335 | * Supports ippdrv list count for user application. |
330 | * First step user application getting ippdrv count. | 336 | * First step user application getting ippdrv count. |
@@ -346,7 +352,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, | |||
346 | return PTR_ERR(ippdrv); | 352 | return PTR_ERR(ippdrv); |
347 | } | 353 | } |
348 | 354 | ||
349 | prop_list = ippdrv->prop_list; | 355 | *prop_list = ippdrv->prop_list; |
350 | } | 356 | } |
351 | 357 | ||
352 | return 0; | 358 | return 0; |
@@ -386,9 +392,11 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property) | |||
386 | * when we find this command no using prop_id. | 392 | * when we find this command no using prop_id. |
387 | * return property information set in this command node. | 393 | * return property information set in this command node. |
388 | */ | 394 | */ |
395 | mutex_lock(&ippdrv->cmd_lock); | ||
389 | list_for_each_entry(c_node, &ippdrv->cmd_list, list) { | 396 | list_for_each_entry(c_node, &ippdrv->cmd_list, list) { |
390 | if ((c_node->property.prop_id == prop_id) && | 397 | if ((c_node->property.prop_id == prop_id) && |
391 | (c_node->state == IPP_STATE_STOP)) { | 398 | (c_node->state == IPP_STATE_STOP)) { |
399 | mutex_unlock(&ippdrv->cmd_lock); | ||
392 | DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n", | 400 | DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n", |
393 | property->cmd, (int)ippdrv); | 401 | property->cmd, (int)ippdrv); |
394 | 402 | ||
@@ -396,6 +404,7 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property) | |||
396 | return 0; | 404 | return 0; |
397 | } | 405 | } |
398 | } | 406 | } |
407 | mutex_unlock(&ippdrv->cmd_lock); | ||
399 | 408 | ||
400 | DRM_ERROR("failed to search property.\n"); | 409 | DRM_ERROR("failed to search property.\n"); |
401 | 410 | ||
@@ -499,7 +508,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, | |||
499 | c_node->start_work = ipp_create_cmd_work(); | 508 | c_node->start_work = ipp_create_cmd_work(); |
500 | if (IS_ERR(c_node->start_work)) { | 509 | if (IS_ERR(c_node->start_work)) { |
501 | DRM_ERROR("failed to create start work.\n"); | 510 | DRM_ERROR("failed to create start work.\n"); |
502 | goto err_clear; | 511 | goto err_remove_id; |
503 | } | 512 | } |
504 | 513 | ||
505 | c_node->stop_work = ipp_create_cmd_work(); | 514 | c_node->stop_work = ipp_create_cmd_work(); |
@@ -514,7 +523,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, | |||
514 | goto err_free_stop; | 523 | goto err_free_stop; |
515 | } | 524 | } |
516 | 525 | ||
517 | mutex_init(&c_node->cmd_lock); | 526 | mutex_init(&c_node->lock); |
518 | mutex_init(&c_node->mem_lock); | 527 | mutex_init(&c_node->mem_lock); |
519 | mutex_init(&c_node->event_lock); | 528 | mutex_init(&c_node->event_lock); |
520 | 529 | ||
@@ -526,7 +535,9 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, | |||
526 | 535 | ||
527 | INIT_LIST_HEAD(&c_node->event_list); | 536 | INIT_LIST_HEAD(&c_node->event_list); |
528 | list_splice_init(&priv->event_list, &c_node->event_list); | 537 | list_splice_init(&priv->event_list, &c_node->event_list); |
538 | mutex_lock(&ippdrv->cmd_lock); | ||
529 | list_add_tail(&c_node->list, &ippdrv->cmd_list); | 539 | list_add_tail(&c_node->list, &ippdrv->cmd_list); |
540 | mutex_unlock(&ippdrv->cmd_lock); | ||
530 | 541 | ||
531 | /* make dedicated state without m2m */ | 542 | /* make dedicated state without m2m */ |
532 | if (!ipp_is_m2m_cmd(property->cmd)) | 543 | if (!ipp_is_m2m_cmd(property->cmd)) |
@@ -538,18 +549,24 @@ err_free_stop: | |||
538 | kfree(c_node->stop_work); | 549 | kfree(c_node->stop_work); |
539 | err_free_start: | 550 | err_free_start: |
540 | kfree(c_node->start_work); | 551 | kfree(c_node->start_work); |
552 | err_remove_id: | ||
553 | ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id); | ||
541 | err_clear: | 554 | err_clear: |
542 | kfree(c_node); | 555 | kfree(c_node); |
543 | return ret; | 556 | return ret; |
544 | } | 557 | } |
545 | 558 | ||
546 | static void ipp_clean_cmd_node(struct drm_exynos_ipp_cmd_node *c_node) | 559 | static void ipp_clean_cmd_node(struct ipp_context *ctx, |
560 | struct drm_exynos_ipp_cmd_node *c_node) | ||
547 | { | 561 | { |
548 | /* delete list */ | 562 | /* delete list */ |
549 | list_del(&c_node->list); | 563 | list_del(&c_node->list); |
550 | 564 | ||
565 | ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, | ||
566 | c_node->property.prop_id); | ||
567 | |||
551 | /* destroy mutex */ | 568 | /* destroy mutex */ |
552 | mutex_destroy(&c_node->cmd_lock); | 569 | mutex_destroy(&c_node->lock); |
553 | mutex_destroy(&c_node->mem_lock); | 570 | mutex_destroy(&c_node->mem_lock); |
554 | mutex_destroy(&c_node->event_lock); | 571 | mutex_destroy(&c_node->event_lock); |
555 | 572 | ||
@@ -567,17 +584,10 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) | |||
567 | struct list_head *head; | 584 | struct list_head *head; |
568 | int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, }; | 585 | int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, }; |
569 | 586 | ||
570 | mutex_lock(&c_node->mem_lock); | ||
571 | |||
572 | for_each_ipp_ops(i) { | 587 | for_each_ipp_ops(i) { |
573 | /* source/destination memory list */ | 588 | /* source/destination memory list */ |
574 | head = &c_node->mem_list[i]; | 589 | head = &c_node->mem_list[i]; |
575 | 590 | ||
576 | if (list_empty(head)) { | ||
577 | DRM_DEBUG_KMS("%s memory empty.\n", i ? "dst" : "src"); | ||
578 | continue; | ||
579 | } | ||
580 | |||
581 | /* find memory node entry */ | 591 | /* find memory node entry */ |
582 | list_for_each_entry(m_node, head, list) { | 592 | list_for_each_entry(m_node, head, list) { |
583 | DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n", | 593 | DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n", |
@@ -602,8 +612,6 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) | |||
602 | ret = max(count[EXYNOS_DRM_OPS_SRC], | 612 | ret = max(count[EXYNOS_DRM_OPS_SRC], |
603 | count[EXYNOS_DRM_OPS_DST]); | 613 | count[EXYNOS_DRM_OPS_DST]); |
604 | 614 | ||
605 | mutex_unlock(&c_node->mem_lock); | ||
606 | |||
607 | return ret; | 615 | return ret; |
608 | } | 616 | } |
609 | 617 | ||
@@ -646,16 +654,13 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv, | |||
646 | return -EFAULT; | 654 | return -EFAULT; |
647 | } | 655 | } |
648 | 656 | ||
649 | mutex_lock(&c_node->mem_lock); | ||
650 | |||
651 | DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); | 657 | DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); |
652 | 658 | ||
653 | /* get operations callback */ | 659 | /* get operations callback */ |
654 | ops = ippdrv->ops[m_node->ops_id]; | 660 | ops = ippdrv->ops[m_node->ops_id]; |
655 | if (!ops) { | 661 | if (!ops) { |
656 | DRM_ERROR("not support ops.\n"); | 662 | DRM_ERROR("not support ops.\n"); |
657 | ret = -EFAULT; | 663 | return -EFAULT; |
658 | goto err_unlock; | ||
659 | } | 664 | } |
660 | 665 | ||
661 | /* set address and enable irq */ | 666 | /* set address and enable irq */ |
@@ -664,12 +669,10 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv, | |||
664 | m_node->buf_id, IPP_BUF_ENQUEUE); | 669 | m_node->buf_id, IPP_BUF_ENQUEUE); |
665 | if (ret) { | 670 | if (ret) { |
666 | DRM_ERROR("failed to set addr.\n"); | 671 | DRM_ERROR("failed to set addr.\n"); |
667 | goto err_unlock; | 672 | return ret; |
668 | } | 673 | } |
669 | } | 674 | } |
670 | 675 | ||
671 | err_unlock: | ||
672 | mutex_unlock(&c_node->mem_lock); | ||
673 | return ret; | 676 | return ret; |
674 | } | 677 | } |
675 | 678 | ||
@@ -684,11 +687,9 @@ static struct drm_exynos_ipp_mem_node | |||
684 | void *addr; | 687 | void *addr; |
685 | int i; | 688 | int i; |
686 | 689 | ||
687 | mutex_lock(&c_node->mem_lock); | ||
688 | |||
689 | m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); | 690 | m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); |
690 | if (!m_node) | 691 | if (!m_node) |
691 | goto err_unlock; | 692 | return ERR_PTR(-ENOMEM); |
692 | 693 | ||
693 | /* clear base address for error handling */ | 694 | /* clear base address for error handling */ |
694 | memset(&buf_info, 0x0, sizeof(buf_info)); | 695 | memset(&buf_info, 0x0, sizeof(buf_info)); |
@@ -722,15 +723,14 @@ static struct drm_exynos_ipp_mem_node | |||
722 | 723 | ||
723 | m_node->filp = file; | 724 | m_node->filp = file; |
724 | m_node->buf_info = buf_info; | 725 | m_node->buf_info = buf_info; |
726 | mutex_lock(&c_node->mem_lock); | ||
725 | list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); | 727 | list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); |
726 | |||
727 | mutex_unlock(&c_node->mem_lock); | 728 | mutex_unlock(&c_node->mem_lock); |
729 | |||
728 | return m_node; | 730 | return m_node; |
729 | 731 | ||
730 | err_clear: | 732 | err_clear: |
731 | kfree(m_node); | 733 | kfree(m_node); |
732 | err_unlock: | ||
733 | mutex_unlock(&c_node->mem_lock); | ||
734 | return ERR_PTR(-EFAULT); | 734 | return ERR_PTR(-EFAULT); |
735 | } | 735 | } |
736 | 736 | ||
@@ -747,13 +747,6 @@ static int ipp_put_mem_node(struct drm_device *drm_dev, | |||
747 | return -EFAULT; | 747 | return -EFAULT; |
748 | } | 748 | } |
749 | 749 | ||
750 | if (list_empty(&m_node->list)) { | ||
751 | DRM_ERROR("empty memory node.\n"); | ||
752 | return -ENOMEM; | ||
753 | } | ||
754 | |||
755 | mutex_lock(&c_node->mem_lock); | ||
756 | |||
757 | DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); | 750 | DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); |
758 | 751 | ||
759 | /* put gem buffer */ | 752 | /* put gem buffer */ |
@@ -768,8 +761,6 @@ static int ipp_put_mem_node(struct drm_device *drm_dev, | |||
768 | list_del(&m_node->list); | 761 | list_del(&m_node->list); |
769 | kfree(m_node); | 762 | kfree(m_node); |
770 | 763 | ||
771 | mutex_unlock(&c_node->mem_lock); | ||
772 | |||
773 | return 0; | 764 | return 0; |
774 | } | 765 | } |
775 | 766 | ||
@@ -805,7 +796,9 @@ static int ipp_get_event(struct drm_device *drm_dev, | |||
805 | e->base.event = &e->event.base; | 796 | e->base.event = &e->event.base; |
806 | e->base.file_priv = file; | 797 | e->base.file_priv = file; |
807 | e->base.destroy = ipp_free_event; | 798 | e->base.destroy = ipp_free_event; |
799 | mutex_lock(&c_node->event_lock); | ||
808 | list_add_tail(&e->base.link, &c_node->event_list); | 800 | list_add_tail(&e->base.link, &c_node->event_list); |
801 | mutex_unlock(&c_node->event_lock); | ||
809 | 802 | ||
810 | return 0; | 803 | return 0; |
811 | } | 804 | } |
@@ -816,11 +809,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, | |||
816 | struct drm_exynos_ipp_send_event *e, *te; | 809 | struct drm_exynos_ipp_send_event *e, *te; |
817 | int count = 0; | 810 | int count = 0; |
818 | 811 | ||
819 | if (list_empty(&c_node->event_list)) { | 812 | mutex_lock(&c_node->event_lock); |
820 | DRM_DEBUG_KMS("event_list is empty.\n"); | ||
821 | return; | ||
822 | } | ||
823 | |||
824 | list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { | 813 | list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { |
825 | DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e); | 814 | DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e); |
826 | 815 | ||
@@ -841,9 +830,13 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, | |||
841 | /* delete list */ | 830 | /* delete list */ |
842 | list_del(&e->base.link); | 831 | list_del(&e->base.link); |
843 | kfree(e); | 832 | kfree(e); |
844 | return; | 833 | goto out_unlock; |
845 | } | 834 | } |
846 | } | 835 | } |
836 | |||
837 | out_unlock: | ||
838 | mutex_unlock(&c_node->event_lock); | ||
839 | return; | ||
847 | } | 840 | } |
848 | 841 | ||
849 | static void ipp_handle_cmd_work(struct device *dev, | 842 | static void ipp_handle_cmd_work(struct device *dev, |
@@ -887,7 +880,9 @@ static int ipp_queue_buf_with_run(struct device *dev, | |||
887 | return 0; | 880 | return 0; |
888 | } | 881 | } |
889 | 882 | ||
883 | mutex_lock(&c_node->mem_lock); | ||
890 | if (!ipp_check_mem_list(c_node)) { | 884 | if (!ipp_check_mem_list(c_node)) { |
885 | mutex_unlock(&c_node->mem_lock); | ||
891 | DRM_DEBUG_KMS("empty memory.\n"); | 886 | DRM_DEBUG_KMS("empty memory.\n"); |
892 | return 0; | 887 | return 0; |
893 | } | 888 | } |
@@ -904,10 +899,12 @@ static int ipp_queue_buf_with_run(struct device *dev, | |||
904 | } else { | 899 | } else { |
905 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); | 900 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); |
906 | if (ret) { | 901 | if (ret) { |
902 | mutex_unlock(&c_node->mem_lock); | ||
907 | DRM_ERROR("failed to set m node.\n"); | 903 | DRM_ERROR("failed to set m node.\n"); |
908 | return ret; | 904 | return ret; |
909 | } | 905 | } |
910 | } | 906 | } |
907 | mutex_unlock(&c_node->mem_lock); | ||
911 | 908 | ||
912 | return 0; | 909 | return 0; |
913 | } | 910 | } |
@@ -918,15 +915,15 @@ static void ipp_clean_queue_buf(struct drm_device *drm_dev, | |||
918 | { | 915 | { |
919 | struct drm_exynos_ipp_mem_node *m_node, *tm_node; | 916 | struct drm_exynos_ipp_mem_node *m_node, *tm_node; |
920 | 917 | ||
921 | if (!list_empty(&c_node->mem_list[qbuf->ops_id])) { | 918 | /* delete list */ |
922 | /* delete list */ | 919 | mutex_lock(&c_node->mem_lock); |
923 | list_for_each_entry_safe(m_node, tm_node, | 920 | list_for_each_entry_safe(m_node, tm_node, |
924 | &c_node->mem_list[qbuf->ops_id], list) { | 921 | &c_node->mem_list[qbuf->ops_id], list) { |
925 | if (m_node->buf_id == qbuf->buf_id && | 922 | if (m_node->buf_id == qbuf->buf_id && |
926 | m_node->ops_id == qbuf->ops_id) | 923 | m_node->ops_id == qbuf->ops_id) |
927 | ipp_put_mem_node(drm_dev, c_node, m_node); | 924 | ipp_put_mem_node(drm_dev, c_node, m_node); |
928 | } | ||
929 | } | 925 | } |
926 | mutex_unlock(&c_node->mem_lock); | ||
930 | } | 927 | } |
931 | 928 | ||
932 | int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, | 929 | int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, |
@@ -998,7 +995,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, | |||
998 | } | 995 | } |
999 | break; | 996 | break; |
1000 | case IPP_BUF_DEQUEUE: | 997 | case IPP_BUF_DEQUEUE: |
1001 | mutex_lock(&c_node->cmd_lock); | 998 | mutex_lock(&c_node->lock); |
1002 | 999 | ||
1003 | /* put event for destination buffer */ | 1000 | /* put event for destination buffer */ |
1004 | if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) | 1001 | if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) |
@@ -1006,7 +1003,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, | |||
1006 | 1003 | ||
1007 | ipp_clean_queue_buf(drm_dev, c_node, qbuf); | 1004 | ipp_clean_queue_buf(drm_dev, c_node, qbuf); |
1008 | 1005 | ||
1009 | mutex_unlock(&c_node->cmd_lock); | 1006 | mutex_unlock(&c_node->lock); |
1010 | break; | 1007 | break; |
1011 | default: | 1008 | default: |
1012 | DRM_ERROR("invalid buffer control.\n"); | 1009 | DRM_ERROR("invalid buffer control.\n"); |
@@ -1109,12 +1106,12 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, | |||
1109 | case IPP_CTRL_PLAY: | 1106 | case IPP_CTRL_PLAY: |
1110 | if (pm_runtime_suspended(ippdrv->dev)) | 1107 | if (pm_runtime_suspended(ippdrv->dev)) |
1111 | pm_runtime_get_sync(ippdrv->dev); | 1108 | pm_runtime_get_sync(ippdrv->dev); |
1109 | |||
1112 | c_node->state = IPP_STATE_START; | 1110 | c_node->state = IPP_STATE_START; |
1113 | 1111 | ||
1114 | cmd_work = c_node->start_work; | 1112 | cmd_work = c_node->start_work; |
1115 | cmd_work->ctrl = cmd_ctrl->ctrl; | 1113 | cmd_work->ctrl = cmd_ctrl->ctrl; |
1116 | ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); | 1114 | ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); |
1117 | c_node->state = IPP_STATE_START; | ||
1118 | break; | 1115 | break; |
1119 | case IPP_CTRL_STOP: | 1116 | case IPP_CTRL_STOP: |
1120 | cmd_work = c_node->stop_work; | 1117 | cmd_work = c_node->stop_work; |
@@ -1129,10 +1126,12 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, | |||
1129 | 1126 | ||
1130 | c_node->state = IPP_STATE_STOP; | 1127 | c_node->state = IPP_STATE_STOP; |
1131 | ippdrv->dedicated = false; | 1128 | ippdrv->dedicated = false; |
1132 | ipp_clean_cmd_node(c_node); | 1129 | mutex_lock(&ippdrv->cmd_lock); |
1130 | ipp_clean_cmd_node(ctx, c_node); | ||
1133 | 1131 | ||
1134 | if (list_empty(&ippdrv->cmd_list)) | 1132 | if (list_empty(&ippdrv->cmd_list)) |
1135 | pm_runtime_put_sync(ippdrv->dev); | 1133 | pm_runtime_put_sync(ippdrv->dev); |
1134 | mutex_unlock(&ippdrv->cmd_lock); | ||
1136 | break; | 1135 | break; |
1137 | case IPP_CTRL_PAUSE: | 1136 | case IPP_CTRL_PAUSE: |
1138 | cmd_work = c_node->stop_work; | 1137 | cmd_work = c_node->stop_work; |
@@ -1260,9 +1259,11 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1260 | /* store command info in ippdrv */ | 1259 | /* store command info in ippdrv */ |
1261 | ippdrv->c_node = c_node; | 1260 | ippdrv->c_node = c_node; |
1262 | 1261 | ||
1262 | mutex_lock(&c_node->mem_lock); | ||
1263 | if (!ipp_check_mem_list(c_node)) { | 1263 | if (!ipp_check_mem_list(c_node)) { |
1264 | DRM_DEBUG_KMS("empty memory.\n"); | 1264 | DRM_DEBUG_KMS("empty memory.\n"); |
1265 | return -ENOMEM; | 1265 | ret = -ENOMEM; |
1266 | goto err_unlock; | ||
1266 | } | 1267 | } |
1267 | 1268 | ||
1268 | /* set current property in ippdrv */ | 1269 | /* set current property in ippdrv */ |
@@ -1270,7 +1271,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1270 | if (ret) { | 1271 | if (ret) { |
1271 | DRM_ERROR("failed to set property.\n"); | 1272 | DRM_ERROR("failed to set property.\n"); |
1272 | ippdrv->c_node = NULL; | 1273 | ippdrv->c_node = NULL; |
1273 | return ret; | 1274 | goto err_unlock; |
1274 | } | 1275 | } |
1275 | 1276 | ||
1276 | /* check command */ | 1277 | /* check command */ |
@@ -1285,7 +1286,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1285 | if (!m_node) { | 1286 | if (!m_node) { |
1286 | DRM_ERROR("failed to get node.\n"); | 1287 | DRM_ERROR("failed to get node.\n"); |
1287 | ret = -EFAULT; | 1288 | ret = -EFAULT; |
1288 | return ret; | 1289 | goto err_unlock; |
1289 | } | 1290 | } |
1290 | 1291 | ||
1291 | DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node); | 1292 | DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node); |
@@ -1293,7 +1294,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1293 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); | 1294 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); |
1294 | if (ret) { | 1295 | if (ret) { |
1295 | DRM_ERROR("failed to set m node.\n"); | 1296 | DRM_ERROR("failed to set m node.\n"); |
1296 | return ret; | 1297 | goto err_unlock; |
1297 | } | 1298 | } |
1298 | } | 1299 | } |
1299 | break; | 1300 | break; |
@@ -1305,7 +1306,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1305 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); | 1306 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); |
1306 | if (ret) { | 1307 | if (ret) { |
1307 | DRM_ERROR("failed to set m node.\n"); | 1308 | DRM_ERROR("failed to set m node.\n"); |
1308 | return ret; | 1309 | goto err_unlock; |
1309 | } | 1310 | } |
1310 | } | 1311 | } |
1311 | break; | 1312 | break; |
@@ -1317,14 +1318,16 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1317 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); | 1318 | ret = ipp_set_mem_node(ippdrv, c_node, m_node); |
1318 | if (ret) { | 1319 | if (ret) { |
1319 | DRM_ERROR("failed to set m node.\n"); | 1320 | DRM_ERROR("failed to set m node.\n"); |
1320 | return ret; | 1321 | goto err_unlock; |
1321 | } | 1322 | } |
1322 | } | 1323 | } |
1323 | break; | 1324 | break; |
1324 | default: | 1325 | default: |
1325 | DRM_ERROR("invalid operations.\n"); | 1326 | DRM_ERROR("invalid operations.\n"); |
1326 | return -EINVAL; | 1327 | ret = -EINVAL; |
1328 | goto err_unlock; | ||
1327 | } | 1329 | } |
1330 | mutex_unlock(&c_node->mem_lock); | ||
1328 | 1331 | ||
1329 | DRM_DEBUG_KMS("cmd[%d]\n", property->cmd); | 1332 | DRM_DEBUG_KMS("cmd[%d]\n", property->cmd); |
1330 | 1333 | ||
@@ -1333,11 +1336,17 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1333 | ret = ippdrv->start(ippdrv->dev, property->cmd); | 1336 | ret = ippdrv->start(ippdrv->dev, property->cmd); |
1334 | if (ret) { | 1337 | if (ret) { |
1335 | DRM_ERROR("failed to start ops.\n"); | 1338 | DRM_ERROR("failed to start ops.\n"); |
1339 | ippdrv->c_node = NULL; | ||
1336 | return ret; | 1340 | return ret; |
1337 | } | 1341 | } |
1338 | } | 1342 | } |
1339 | 1343 | ||
1340 | return 0; | 1344 | return 0; |
1345 | |||
1346 | err_unlock: | ||
1347 | mutex_unlock(&c_node->mem_lock); | ||
1348 | ippdrv->c_node = NULL; | ||
1349 | return ret; | ||
1341 | } | 1350 | } |
1342 | 1351 | ||
1343 | static int ipp_stop_property(struct drm_device *drm_dev, | 1352 | static int ipp_stop_property(struct drm_device *drm_dev, |
@@ -1354,6 +1363,8 @@ static int ipp_stop_property(struct drm_device *drm_dev, | |||
1354 | /* put event */ | 1363 | /* put event */ |
1355 | ipp_put_event(c_node, NULL); | 1364 | ipp_put_event(c_node, NULL); |
1356 | 1365 | ||
1366 | mutex_lock(&c_node->mem_lock); | ||
1367 | |||
1357 | /* check command */ | 1368 | /* check command */ |
1358 | switch (property->cmd) { | 1369 | switch (property->cmd) { |
1359 | case IPP_CMD_M2M: | 1370 | case IPP_CMD_M2M: |
@@ -1361,11 +1372,6 @@ static int ipp_stop_property(struct drm_device *drm_dev, | |||
1361 | /* source/destination memory list */ | 1372 | /* source/destination memory list */ |
1362 | head = &c_node->mem_list[i]; | 1373 | head = &c_node->mem_list[i]; |
1363 | 1374 | ||
1364 | if (list_empty(head)) { | ||
1365 | DRM_DEBUG_KMS("mem_list is empty.\n"); | ||
1366 | break; | ||
1367 | } | ||
1368 | |||
1369 | list_for_each_entry_safe(m_node, tm_node, | 1375 | list_for_each_entry_safe(m_node, tm_node, |
1370 | head, list) { | 1376 | head, list) { |
1371 | ret = ipp_put_mem_node(drm_dev, c_node, | 1377 | ret = ipp_put_mem_node(drm_dev, c_node, |
@@ -1381,11 +1387,6 @@ static int ipp_stop_property(struct drm_device *drm_dev, | |||
1381 | /* destination memory list */ | 1387 | /* destination memory list */ |
1382 | head = &c_node->mem_list[EXYNOS_DRM_OPS_DST]; | 1388 | head = &c_node->mem_list[EXYNOS_DRM_OPS_DST]; |
1383 | 1389 | ||
1384 | if (list_empty(head)) { | ||
1385 | DRM_DEBUG_KMS("mem_list is empty.\n"); | ||
1386 | break; | ||
1387 | } | ||
1388 | |||
1389 | list_for_each_entry_safe(m_node, tm_node, head, list) { | 1390 | list_for_each_entry_safe(m_node, tm_node, head, list) { |
1390 | ret = ipp_put_mem_node(drm_dev, c_node, m_node); | 1391 | ret = ipp_put_mem_node(drm_dev, c_node, m_node); |
1391 | if (ret) { | 1392 | if (ret) { |
@@ -1398,11 +1399,6 @@ static int ipp_stop_property(struct drm_device *drm_dev, | |||
1398 | /* source memory list */ | 1399 | /* source memory list */ |
1399 | head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; | 1400 | head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; |
1400 | 1401 | ||
1401 | if (list_empty(head)) { | ||
1402 | DRM_DEBUG_KMS("mem_list is empty.\n"); | ||
1403 | break; | ||
1404 | } | ||
1405 | |||
1406 | list_for_each_entry_safe(m_node, tm_node, head, list) { | 1402 | list_for_each_entry_safe(m_node, tm_node, head, list) { |
1407 | ret = ipp_put_mem_node(drm_dev, c_node, m_node); | 1403 | ret = ipp_put_mem_node(drm_dev, c_node, m_node); |
1408 | if (ret) { | 1404 | if (ret) { |
@@ -1418,6 +1414,8 @@ static int ipp_stop_property(struct drm_device *drm_dev, | |||
1418 | } | 1414 | } |
1419 | 1415 | ||
1420 | err_clear: | 1416 | err_clear: |
1417 | mutex_unlock(&c_node->mem_lock); | ||
1418 | |||
1421 | /* stop operations */ | 1419 | /* stop operations */ |
1422 | if (ippdrv->stop) | 1420 | if (ippdrv->stop) |
1423 | ippdrv->stop(ippdrv->dev, property->cmd); | 1421 | ippdrv->stop(ippdrv->dev, property->cmd); |
@@ -1446,7 +1444,7 @@ void ipp_sched_cmd(struct work_struct *work) | |||
1446 | return; | 1444 | return; |
1447 | } | 1445 | } |
1448 | 1446 | ||
1449 | mutex_lock(&c_node->cmd_lock); | 1447 | mutex_lock(&c_node->lock); |
1450 | 1448 | ||
1451 | property = &c_node->property; | 1449 | property = &c_node->property; |
1452 | 1450 | ||
@@ -1494,7 +1492,7 @@ void ipp_sched_cmd(struct work_struct *work) | |||
1494 | DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl); | 1492 | DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl); |
1495 | 1493 | ||
1496 | err_unlock: | 1494 | err_unlock: |
1497 | mutex_unlock(&c_node->cmd_lock); | 1495 | mutex_unlock(&c_node->lock); |
1498 | } | 1496 | } |
1499 | 1497 | ||
1500 | static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | 1498 | static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, |
@@ -1524,14 +1522,18 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1524 | return -EINVAL; | 1522 | return -EINVAL; |
1525 | } | 1523 | } |
1526 | 1524 | ||
1525 | mutex_lock(&c_node->event_lock); | ||
1527 | if (list_empty(&c_node->event_list)) { | 1526 | if (list_empty(&c_node->event_list)) { |
1528 | DRM_DEBUG_KMS("event list is empty.\n"); | 1527 | DRM_DEBUG_KMS("event list is empty.\n"); |
1529 | return 0; | 1528 | ret = 0; |
1529 | goto err_event_unlock; | ||
1530 | } | 1530 | } |
1531 | 1531 | ||
1532 | mutex_lock(&c_node->mem_lock); | ||
1532 | if (!ipp_check_mem_list(c_node)) { | 1533 | if (!ipp_check_mem_list(c_node)) { |
1533 | DRM_DEBUG_KMS("empty memory.\n"); | 1534 | DRM_DEBUG_KMS("empty memory.\n"); |
1534 | return 0; | 1535 | ret = 0; |
1536 | goto err_mem_unlock; | ||
1535 | } | 1537 | } |
1536 | 1538 | ||
1537 | /* check command */ | 1539 | /* check command */ |
@@ -1545,7 +1547,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1545 | struct drm_exynos_ipp_mem_node, list); | 1547 | struct drm_exynos_ipp_mem_node, list); |
1546 | if (!m_node) { | 1548 | if (!m_node) { |
1547 | DRM_ERROR("empty memory node.\n"); | 1549 | DRM_ERROR("empty memory node.\n"); |
1548 | return -ENOMEM; | 1550 | ret = -ENOMEM; |
1551 | goto err_mem_unlock; | ||
1549 | } | 1552 | } |
1550 | 1553 | ||
1551 | tbuf_id[i] = m_node->buf_id; | 1554 | tbuf_id[i] = m_node->buf_id; |
@@ -1567,7 +1570,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1567 | m_node = ipp_find_mem_node(c_node, &qbuf); | 1570 | m_node = ipp_find_mem_node(c_node, &qbuf); |
1568 | if (!m_node) { | 1571 | if (!m_node) { |
1569 | DRM_ERROR("empty memory node.\n"); | 1572 | DRM_ERROR("empty memory node.\n"); |
1570 | return -ENOMEM; | 1573 | ret = -ENOMEM; |
1574 | goto err_mem_unlock; | ||
1571 | } | 1575 | } |
1572 | 1576 | ||
1573 | tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id; | 1577 | tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id; |
@@ -1584,7 +1588,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1584 | struct drm_exynos_ipp_mem_node, list); | 1588 | struct drm_exynos_ipp_mem_node, list); |
1585 | if (!m_node) { | 1589 | if (!m_node) { |
1586 | DRM_ERROR("empty memory node.\n"); | 1590 | DRM_ERROR("empty memory node.\n"); |
1587 | return -ENOMEM; | 1591 | ret = -ENOMEM; |
1592 | goto err_mem_unlock; | ||
1588 | } | 1593 | } |
1589 | 1594 | ||
1590 | tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; | 1595 | tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; |
@@ -1595,8 +1600,10 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1595 | break; | 1600 | break; |
1596 | default: | 1601 | default: |
1597 | DRM_ERROR("invalid operations.\n"); | 1602 | DRM_ERROR("invalid operations.\n"); |
1598 | return -EINVAL; | 1603 | ret = -EINVAL; |
1604 | goto err_mem_unlock; | ||
1599 | } | 1605 | } |
1606 | mutex_unlock(&c_node->mem_lock); | ||
1600 | 1607 | ||
1601 | if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST]) | 1608 | if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST]) |
1602 | DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n", | 1609 | DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n", |
@@ -1611,11 +1618,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1611 | e = list_first_entry(&c_node->event_list, | 1618 | e = list_first_entry(&c_node->event_list, |
1612 | struct drm_exynos_ipp_send_event, base.link); | 1619 | struct drm_exynos_ipp_send_event, base.link); |
1613 | 1620 | ||
1614 | if (!e) { | ||
1615 | DRM_ERROR("empty event.\n"); | ||
1616 | return -EINVAL; | ||
1617 | } | ||
1618 | |||
1619 | do_gettimeofday(&now); | 1621 | do_gettimeofday(&now); |
1620 | DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec); | 1622 | DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec); |
1621 | e->event.tv_sec = now.tv_sec; | 1623 | e->event.tv_sec = now.tv_sec; |
@@ -1630,11 +1632,18 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1630 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); | 1632 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); |
1631 | wake_up_interruptible(&e->base.file_priv->event_wait); | 1633 | wake_up_interruptible(&e->base.file_priv->event_wait); |
1632 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | 1634 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); |
1635 | mutex_unlock(&c_node->event_lock); | ||
1633 | 1636 | ||
1634 | DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n", | 1637 | DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n", |
1635 | property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]); | 1638 | property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]); |
1636 | 1639 | ||
1637 | return 0; | 1640 | return 0; |
1641 | |||
1642 | err_mem_unlock: | ||
1643 | mutex_unlock(&c_node->mem_lock); | ||
1644 | err_event_unlock: | ||
1645 | mutex_unlock(&c_node->event_lock); | ||
1646 | return ret; | ||
1638 | } | 1647 | } |
1639 | 1648 | ||
1640 | void ipp_sched_event(struct work_struct *work) | 1649 | void ipp_sched_event(struct work_struct *work) |
@@ -1676,8 +1685,6 @@ void ipp_sched_event(struct work_struct *work) | |||
1676 | goto err_completion; | 1685 | goto err_completion; |
1677 | } | 1686 | } |
1678 | 1687 | ||
1679 | mutex_lock(&c_node->event_lock); | ||
1680 | |||
1681 | ret = ipp_send_event(ippdrv, c_node, event_work->buf_id); | 1688 | ret = ipp_send_event(ippdrv, c_node, event_work->buf_id); |
1682 | if (ret) { | 1689 | if (ret) { |
1683 | DRM_ERROR("failed to send event.\n"); | 1690 | DRM_ERROR("failed to send event.\n"); |
@@ -1687,8 +1694,6 @@ void ipp_sched_event(struct work_struct *work) | |||
1687 | err_completion: | 1694 | err_completion: |
1688 | if (ipp_is_m2m_cmd(c_node->property.cmd)) | 1695 | if (ipp_is_m2m_cmd(c_node->property.cmd)) |
1689 | complete(&c_node->start_complete); | 1696 | complete(&c_node->start_complete); |
1690 | |||
1691 | mutex_unlock(&c_node->event_lock); | ||
1692 | } | 1697 | } |
1693 | 1698 | ||
1694 | static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | 1699 | static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) |
@@ -1699,23 +1704,21 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
1699 | 1704 | ||
1700 | /* get ipp driver entry */ | 1705 | /* get ipp driver entry */ |
1701 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 1706 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
1707 | u32 ipp_id; | ||
1708 | |||
1702 | ippdrv->drm_dev = drm_dev; | 1709 | ippdrv->drm_dev = drm_dev; |
1703 | 1710 | ||
1704 | ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv, | 1711 | ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv, |
1705 | &ippdrv->ipp_id); | 1712 | &ipp_id); |
1706 | if (ret) { | 1713 | if (ret || ipp_id == 0) { |
1707 | DRM_ERROR("failed to create id.\n"); | 1714 | DRM_ERROR("failed to create id.\n"); |
1708 | goto err_idr; | 1715 | goto err; |
1709 | } | 1716 | } |
1710 | 1717 | ||
1711 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n", | 1718 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n", |
1712 | count++, (int)ippdrv, ippdrv->ipp_id); | 1719 | count++, (int)ippdrv, ipp_id); |
1713 | 1720 | ||
1714 | if (ippdrv->ipp_id == 0) { | 1721 | ippdrv->prop_list.ipp_id = ipp_id; |
1715 | DRM_ERROR("failed to get ipp_id[%d]\n", | ||
1716 | ippdrv->ipp_id); | ||
1717 | goto err_idr; | ||
1718 | } | ||
1719 | 1722 | ||
1720 | /* store parent device for node */ | 1723 | /* store parent device for node */ |
1721 | ippdrv->parent_dev = dev; | 1724 | ippdrv->parent_dev = dev; |
@@ -1724,39 +1727,46 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
1724 | ippdrv->event_workq = ctx->event_workq; | 1727 | ippdrv->event_workq = ctx->event_workq; |
1725 | ippdrv->sched_event = ipp_sched_event; | 1728 | ippdrv->sched_event = ipp_sched_event; |
1726 | INIT_LIST_HEAD(&ippdrv->cmd_list); | 1729 | INIT_LIST_HEAD(&ippdrv->cmd_list); |
1730 | mutex_init(&ippdrv->cmd_lock); | ||
1727 | 1731 | ||
1728 | if (is_drm_iommu_supported(drm_dev)) { | 1732 | if (is_drm_iommu_supported(drm_dev)) { |
1729 | ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); | 1733 | ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); |
1730 | if (ret) { | 1734 | if (ret) { |
1731 | DRM_ERROR("failed to activate iommu\n"); | 1735 | DRM_ERROR("failed to activate iommu\n"); |
1732 | goto err_iommu; | 1736 | goto err; |
1733 | } | 1737 | } |
1734 | } | 1738 | } |
1735 | } | 1739 | } |
1736 | 1740 | ||
1737 | return 0; | 1741 | return 0; |
1738 | 1742 | ||
1739 | err_iommu: | 1743 | err: |
1740 | /* get ipp driver entry */ | 1744 | /* get ipp driver entry */ |
1741 | list_for_each_entry_reverse(ippdrv, &exynos_drm_ippdrv_list, drv_list) | 1745 | list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, |
1746 | drv_list) { | ||
1742 | if (is_drm_iommu_supported(drm_dev)) | 1747 | if (is_drm_iommu_supported(drm_dev)) |
1743 | drm_iommu_detach_device(drm_dev, ippdrv->dev); | 1748 | drm_iommu_detach_device(drm_dev, ippdrv->dev); |
1744 | 1749 | ||
1745 | err_idr: | 1750 | ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, |
1746 | idr_destroy(&ctx->ipp_idr); | 1751 | ippdrv->prop_list.ipp_id); |
1747 | idr_destroy(&ctx->prop_idr); | 1752 | } |
1753 | |||
1748 | return ret; | 1754 | return ret; |
1749 | } | 1755 | } |
1750 | 1756 | ||
1751 | static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) | 1757 | static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) |
1752 | { | 1758 | { |
1753 | struct exynos_drm_ippdrv *ippdrv; | 1759 | struct exynos_drm_ippdrv *ippdrv; |
1760 | struct ipp_context *ctx = get_ipp_context(dev); | ||
1754 | 1761 | ||
1755 | /* get ipp driver entry */ | 1762 | /* get ipp driver entry */ |
1756 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 1763 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
1757 | if (is_drm_iommu_supported(drm_dev)) | 1764 | if (is_drm_iommu_supported(drm_dev)) |
1758 | drm_iommu_detach_device(drm_dev, ippdrv->dev); | 1765 | drm_iommu_detach_device(drm_dev, ippdrv->dev); |
1759 | 1766 | ||
1767 | ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, | ||
1768 | ippdrv->prop_list.ipp_id); | ||
1769 | |||
1760 | ippdrv->drm_dev = NULL; | 1770 | ippdrv->drm_dev = NULL; |
1761 | exynos_drm_ippdrv_unregister(ippdrv); | 1771 | exynos_drm_ippdrv_unregister(ippdrv); |
1762 | } | 1772 | } |
@@ -1787,20 +1797,14 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, | |||
1787 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1797 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1788 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; | 1798 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; |
1789 | struct exynos_drm_ippdrv *ippdrv = NULL; | 1799 | struct exynos_drm_ippdrv *ippdrv = NULL; |
1800 | struct ipp_context *ctx = get_ipp_context(dev); | ||
1790 | struct drm_exynos_ipp_cmd_node *c_node, *tc_node; | 1801 | struct drm_exynos_ipp_cmd_node *c_node, *tc_node; |
1791 | int count = 0; | 1802 | int count = 0; |
1792 | 1803 | ||
1793 | DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv); | 1804 | DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv); |
1794 | 1805 | ||
1795 | if (list_empty(&exynos_drm_ippdrv_list)) { | ||
1796 | DRM_DEBUG_KMS("ippdrv_list is empty.\n"); | ||
1797 | goto err_clear; | ||
1798 | } | ||
1799 | |||
1800 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 1806 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
1801 | if (list_empty(&ippdrv->cmd_list)) | 1807 | mutex_lock(&ippdrv->cmd_lock); |
1802 | continue; | ||
1803 | |||
1804 | list_for_each_entry_safe(c_node, tc_node, | 1808 | list_for_each_entry_safe(c_node, tc_node, |
1805 | &ippdrv->cmd_list, list) { | 1809 | &ippdrv->cmd_list, list) { |
1806 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", | 1810 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", |
@@ -1820,14 +1824,14 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, | |||
1820 | } | 1824 | } |
1821 | 1825 | ||
1822 | ippdrv->dedicated = false; | 1826 | ippdrv->dedicated = false; |
1823 | ipp_clean_cmd_node(c_node); | 1827 | ipp_clean_cmd_node(ctx, c_node); |
1824 | if (list_empty(&ippdrv->cmd_list)) | 1828 | if (list_empty(&ippdrv->cmd_list)) |
1825 | pm_runtime_put_sync(ippdrv->dev); | 1829 | pm_runtime_put_sync(ippdrv->dev); |
1826 | } | 1830 | } |
1827 | } | 1831 | } |
1832 | mutex_unlock(&ippdrv->cmd_lock); | ||
1828 | } | 1833 | } |
1829 | 1834 | ||
1830 | err_clear: | ||
1831 | kfree(priv); | 1835 | kfree(priv); |
1832 | return; | 1836 | return; |
1833 | } | 1837 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h index ab1634befc05..7aaeaae757c2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.h | |||
@@ -52,7 +52,7 @@ struct drm_exynos_ipp_cmd_work { | |||
52 | * @list: list head to command queue information. | 52 | * @list: list head to command queue information. |
53 | * @event_list: list head of event. | 53 | * @event_list: list head of event. |
54 | * @mem_list: list head to source,destination memory queue information. | 54 | * @mem_list: list head to source,destination memory queue information. |
55 | * @cmd_lock: lock for synchronization of access to ioctl. | 55 | * @lock: lock for synchronization of access to ioctl. |
56 | * @mem_lock: lock for synchronization of access to memory nodes. | 56 | * @mem_lock: lock for synchronization of access to memory nodes. |
57 | * @event_lock: lock for synchronization of access to scheduled event. | 57 | * @event_lock: lock for synchronization of access to scheduled event. |
58 | * @start_complete: completion of start of command. | 58 | * @start_complete: completion of start of command. |
@@ -68,7 +68,7 @@ struct drm_exynos_ipp_cmd_node { | |||
68 | struct list_head list; | 68 | struct list_head list; |
69 | struct list_head event_list; | 69 | struct list_head event_list; |
70 | struct list_head mem_list[EXYNOS_DRM_OPS_MAX]; | 70 | struct list_head mem_list[EXYNOS_DRM_OPS_MAX]; |
71 | struct mutex cmd_lock; | 71 | struct mutex lock; |
72 | struct mutex mem_lock; | 72 | struct mutex mem_lock; |
73 | struct mutex event_lock; | 73 | struct mutex event_lock; |
74 | struct completion start_complete; | 74 | struct completion start_complete; |
@@ -83,7 +83,7 @@ struct drm_exynos_ipp_cmd_node { | |||
83 | /* | 83 | /* |
84 | * A structure of buffer information. | 84 | * A structure of buffer information. |
85 | * | 85 | * |
86 | * @gem_objs: Y, Cb, Cr each gem object. | 86 | * @handles: Y, Cb, Cr each gem object handle. |
87 | * @base: Y, Cb, Cr each planar address. | 87 | * @base: Y, Cb, Cr each planar address. |
88 | */ | 88 | */ |
89 | struct drm_exynos_ipp_buf_info { | 89 | struct drm_exynos_ipp_buf_info { |
@@ -142,12 +142,12 @@ struct exynos_drm_ipp_ops { | |||
142 | * @parent_dev: parent device information. | 142 | * @parent_dev: parent device information. |
143 | * @dev: platform device. | 143 | * @dev: platform device. |
144 | * @drm_dev: drm device. | 144 | * @drm_dev: drm device. |
145 | * @ipp_id: id of ipp driver. | ||
146 | * @dedicated: dedicated ipp device. | 145 | * @dedicated: dedicated ipp device. |
147 | * @ops: source, destination operations. | 146 | * @ops: source, destination operations. |
148 | * @event_workq: event work queue. | 147 | * @event_workq: event work queue. |
149 | * @c_node: current command information. | 148 | * @c_node: current command information. |
150 | * @cmd_list: list head for command information. | 149 | * @cmd_list: list head for command information. |
150 | * @cmd_lock: lock for synchronization of access to cmd_list. | ||
151 | * @prop_list: property informations of current ipp driver. | 151 | * @prop_list: property informations of current ipp driver. |
152 | * @check_property: check property about format, size, buffer. | 152 | * @check_property: check property about format, size, buffer. |
153 | * @reset: reset ipp block. | 153 | * @reset: reset ipp block. |
@@ -160,13 +160,13 @@ struct exynos_drm_ippdrv { | |||
160 | struct device *parent_dev; | 160 | struct device *parent_dev; |
161 | struct device *dev; | 161 | struct device *dev; |
162 | struct drm_device *drm_dev; | 162 | struct drm_device *drm_dev; |
163 | u32 ipp_id; | ||
164 | bool dedicated; | 163 | bool dedicated; |
165 | struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX]; | 164 | struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX]; |
166 | struct workqueue_struct *event_workq; | 165 | struct workqueue_struct *event_workq; |
167 | struct drm_exynos_ipp_cmd_node *c_node; | 166 | struct drm_exynos_ipp_cmd_node *c_node; |
168 | struct list_head cmd_list; | 167 | struct list_head cmd_list; |
169 | struct drm_exynos_ipp_prop_list *prop_list; | 168 | struct mutex cmd_lock; |
169 | struct drm_exynos_ipp_prop_list prop_list; | ||
170 | 170 | ||
171 | int (*check_property)(struct device *dev, | 171 | int (*check_property)(struct device *dev, |
172 | struct drm_exynos_ipp_property *property); | 172 | struct drm_exynos_ipp_property *property); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index 7b901688defa..f01fbb6dc1f0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c | |||
@@ -158,8 +158,9 @@ static irqreturn_t rotator_irq_handler(int irq, void *arg) | |||
158 | rot->cur_buf_id[EXYNOS_DRM_OPS_DST]; | 158 | rot->cur_buf_id[EXYNOS_DRM_OPS_DST]; |
159 | queue_work(ippdrv->event_workq, | 159 | queue_work(ippdrv->event_workq, |
160 | (struct work_struct *)event_work); | 160 | (struct work_struct *)event_work); |
161 | } else | 161 | } else { |
162 | DRM_ERROR("the SFR is set illegally\n"); | 162 | DRM_ERROR("the SFR is set illegally\n"); |
163 | } | ||
163 | 164 | ||
164 | return IRQ_HANDLED; | 165 | return IRQ_HANDLED; |
165 | } | 166 | } |
@@ -469,11 +470,7 @@ static struct exynos_drm_ipp_ops rot_dst_ops = { | |||
469 | 470 | ||
470 | static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | 471 | static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv) |
471 | { | 472 | { |
472 | struct drm_exynos_ipp_prop_list *prop_list; | 473 | struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list; |
473 | |||
474 | prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL); | ||
475 | if (!prop_list) | ||
476 | return -ENOMEM; | ||
477 | 474 | ||
478 | prop_list->version = 1; | 475 | prop_list->version = 1; |
479 | prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) | | 476 | prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) | |
@@ -486,8 +483,6 @@ static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | |||
486 | prop_list->crop = 0; | 483 | prop_list->crop = 0; |
487 | prop_list->scale = 0; | 484 | prop_list->scale = 0; |
488 | 485 | ||
489 | ippdrv->prop_list = prop_list; | ||
490 | |||
491 | return 0; | 486 | return 0; |
492 | } | 487 | } |
493 | 488 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 3fa987df906a..2fb8705d6461 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
@@ -51,6 +51,7 @@ struct vidi_context { | |||
51 | struct drm_crtc *crtc; | 51 | struct drm_crtc *crtc; |
52 | struct drm_encoder *encoder; | 52 | struct drm_encoder *encoder; |
53 | struct drm_connector connector; | 53 | struct drm_connector connector; |
54 | struct exynos_drm_subdrv subdrv; | ||
54 | struct vidi_win_data win_data[WINDOWS_NR]; | 55 | struct vidi_win_data win_data[WINDOWS_NR]; |
55 | struct edid *raw_edid; | 56 | struct edid *raw_edid; |
56 | unsigned int clkdiv; | 57 | unsigned int clkdiv; |
@@ -294,14 +295,13 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) | |||
294 | } | 295 | } |
295 | 296 | ||
296 | static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, | 297 | static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, |
297 | struct drm_device *drm_dev, int pipe) | 298 | struct drm_device *drm_dev) |
298 | { | 299 | { |
299 | struct vidi_context *ctx = mgr->ctx; | 300 | struct vidi_context *ctx = mgr->ctx; |
301 | struct exynos_drm_private *priv = drm_dev->dev_private; | ||
300 | 302 | ||
301 | DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe); | 303 | mgr->drm_dev = ctx->drm_dev = drm_dev; |
302 | 304 | mgr->pipe = ctx->pipe = priv->pipe++; | |
303 | ctx->drm_dev = drm_dev; | ||
304 | ctx->pipe = pipe; | ||
305 | 305 | ||
306 | /* | 306 | /* |
307 | * enable drm irq mode. | 307 | * enable drm irq mode. |
@@ -324,7 +324,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, | |||
324 | } | 324 | } |
325 | 325 | ||
326 | static struct exynos_drm_manager_ops vidi_manager_ops = { | 326 | static struct exynos_drm_manager_ops vidi_manager_ops = { |
327 | .initialize = vidi_mgr_initialize, | ||
328 | .dpms = vidi_dpms, | 327 | .dpms = vidi_dpms, |
329 | .commit = vidi_commit, | 328 | .commit = vidi_commit, |
330 | .enable_vblank = vidi_enable_vblank, | 329 | .enable_vblank = vidi_enable_vblank, |
@@ -579,13 +578,38 @@ static struct exynos_drm_display vidi_display = { | |||
579 | .ops = &vidi_display_ops, | 578 | .ops = &vidi_display_ops, |
580 | }; | 579 | }; |
581 | 580 | ||
581 | static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | ||
582 | { | ||
583 | struct exynos_drm_manager *mgr = get_vidi_mgr(dev); | ||
584 | struct vidi_context *ctx = mgr->ctx; | ||
585 | struct drm_crtc *crtc = ctx->crtc; | ||
586 | int ret; | ||
587 | |||
588 | vidi_mgr_initialize(mgr, drm_dev); | ||
589 | |||
590 | ret = exynos_drm_crtc_create(&vidi_manager); | ||
591 | if (ret) { | ||
592 | DRM_ERROR("failed to create crtc.\n"); | ||
593 | return ret; | ||
594 | } | ||
595 | |||
596 | ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display); | ||
597 | if (ret) { | ||
598 | crtc->funcs->destroy(crtc); | ||
599 | DRM_ERROR("failed to create encoder and connector.\n"); | ||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
582 | static int vidi_probe(struct platform_device *pdev) | 606 | static int vidi_probe(struct platform_device *pdev) |
583 | { | 607 | { |
584 | struct device *dev = &pdev->dev; | 608 | struct exynos_drm_subdrv *subdrv; |
585 | struct vidi_context *ctx; | 609 | struct vidi_context *ctx; |
586 | int ret; | 610 | int ret; |
587 | 611 | ||
588 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | 612 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
589 | if (!ctx) | 613 | if (!ctx) |
590 | return -ENOMEM; | 614 | return -ENOMEM; |
591 | 615 | ||
@@ -600,28 +624,43 @@ static int vidi_probe(struct platform_device *pdev) | |||
600 | 624 | ||
601 | platform_set_drvdata(pdev, &vidi_manager); | 625 | platform_set_drvdata(pdev, &vidi_manager); |
602 | 626 | ||
603 | ret = device_create_file(dev, &dev_attr_connection); | 627 | subdrv = &ctx->subdrv; |
604 | if (ret < 0) | 628 | subdrv->dev = &pdev->dev; |
605 | DRM_INFO("failed to create connection sysfs.\n"); | 629 | subdrv->probe = vidi_subdrv_probe; |
606 | 630 | ||
607 | exynos_drm_manager_register(&vidi_manager); | 631 | ret = exynos_drm_subdrv_register(subdrv); |
608 | exynos_drm_display_register(&vidi_display); | 632 | if (ret < 0) { |
633 | dev_err(&pdev->dev, "failed to register drm vidi device\n"); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | ret = device_create_file(&pdev->dev, &dev_attr_connection); | ||
638 | if (ret < 0) { | ||
639 | exynos_drm_subdrv_unregister(subdrv); | ||
640 | DRM_INFO("failed to create connection sysfs.\n"); | ||
641 | } | ||
609 | 642 | ||
610 | return 0; | 643 | return 0; |
611 | } | 644 | } |
612 | 645 | ||
613 | static int vidi_remove(struct platform_device *pdev) | 646 | static int vidi_remove(struct platform_device *pdev) |
614 | { | 647 | { |
615 | struct vidi_context *ctx = platform_get_drvdata(pdev); | 648 | struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); |
616 | 649 | struct vidi_context *ctx = mgr->ctx; | |
617 | exynos_drm_display_unregister(&vidi_display); | 650 | struct drm_encoder *encoder = ctx->encoder; |
618 | exynos_drm_manager_unregister(&vidi_manager); | 651 | struct drm_crtc *crtc = mgr->crtc; |
619 | 652 | ||
620 | if (ctx->raw_edid != (struct edid *)fake_edid_info) { | 653 | if (ctx->raw_edid != (struct edid *)fake_edid_info) { |
621 | kfree(ctx->raw_edid); | 654 | kfree(ctx->raw_edid); |
622 | ctx->raw_edid = NULL; | 655 | ctx->raw_edid = NULL; |
656 | |||
657 | return -EINVAL; | ||
623 | } | 658 | } |
624 | 659 | ||
660 | crtc->funcs->destroy(crtc); | ||
661 | encoder->funcs->destroy(encoder); | ||
662 | drm_connector_cleanup(&ctx->connector); | ||
663 | |||
625 | return 0; | 664 | return 0; |
626 | } | 665 | } |
627 | 666 | ||
@@ -633,3 +672,31 @@ struct platform_driver vidi_driver = { | |||
633 | .owner = THIS_MODULE, | 672 | .owner = THIS_MODULE, |
634 | }, | 673 | }, |
635 | }; | 674 | }; |
675 | |||
676 | int exynos_drm_probe_vidi(void) | ||
677 | { | ||
678 | struct platform_device *pdev; | ||
679 | int ret; | ||
680 | |||
681 | pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0); | ||
682 | if (IS_ERR(pdev)) | ||
683 | return PTR_ERR(pdev); | ||
684 | |||
685 | ret = platform_driver_register(&vidi_driver); | ||
686 | if (ret) { | ||
687 | platform_device_unregister(pdev); | ||
688 | return ret; | ||
689 | } | ||
690 | |||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | void exynos_drm_remove_vidi(void) | ||
695 | { | ||
696 | struct vidi_context *ctx = vidi_manager.ctx; | ||
697 | struct exynos_drm_subdrv *subdrv = &ctx->subdrv; | ||
698 | struct platform_device *pdev = to_platform_device(subdrv->dev); | ||
699 | |||
700 | platform_driver_unregister(&vidi_driver); | ||
701 | platform_device_unregister(pdev); | ||
702 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 9a6d652a3ef2..c104d0c9b385 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -33,13 +33,17 @@ | |||
33 | #include <linux/regulator/consumer.h> | 33 | #include <linux/regulator/consumer.h> |
34 | #include <linux/io.h> | 34 | #include <linux/io.h> |
35 | #include <linux/of.h> | 35 | #include <linux/of.h> |
36 | #include <linux/i2c.h> | 36 | #include <linux/of_address.h> |
37 | #include <linux/of_gpio.h> | 37 | #include <linux/of_gpio.h> |
38 | #include <linux/hdmi.h> | 38 | #include <linux/hdmi.h> |
39 | #include <linux/component.h> | ||
40 | #include <linux/mfd/syscon.h> | ||
41 | #include <linux/regmap.h> | ||
39 | 42 | ||
40 | #include <drm/exynos_drm.h> | 43 | #include <drm/exynos_drm.h> |
41 | 44 | ||
42 | #include "exynos_drm_drv.h" | 45 | #include "exynos_drm_drv.h" |
46 | #include "exynos_drm_crtc.h" | ||
43 | #include "exynos_mixer.h" | 47 | #include "exynos_mixer.h" |
44 | 48 | ||
45 | #include <linux/gpio.h> | 49 | #include <linux/gpio.h> |
@@ -48,6 +52,8 @@ | |||
48 | #define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev)) | 52 | #define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev)) |
49 | #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) | 53 | #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) |
50 | 54 | ||
55 | #define HOTPLUG_DEBOUNCE_MS 1100 | ||
56 | |||
51 | /* AVI header and aspect ratio */ | 57 | /* AVI header and aspect ratio */ |
52 | #define HDMI_AVI_VERSION 0x02 | 58 | #define HDMI_AVI_VERSION 0x02 |
53 | #define HDMI_AVI_LENGTH 0x0D | 59 | #define HDMI_AVI_LENGTH 0x0D |
@@ -66,6 +72,8 @@ enum hdmi_type { | |||
66 | 72 | ||
67 | struct hdmi_driver_data { | 73 | struct hdmi_driver_data { |
68 | unsigned int type; | 74 | unsigned int type; |
75 | const struct hdmiphy_config *phy_confs; | ||
76 | unsigned int phy_conf_count; | ||
69 | unsigned int is_apb_phy:1; | 77 | unsigned int is_apb_phy:1; |
70 | }; | 78 | }; |
71 | 79 | ||
@@ -74,7 +82,6 @@ struct hdmi_resources { | |||
74 | struct clk *sclk_hdmi; | 82 | struct clk *sclk_hdmi; |
75 | struct clk *sclk_pixel; | 83 | struct clk *sclk_pixel; |
76 | struct clk *sclk_hdmiphy; | 84 | struct clk *sclk_hdmiphy; |
77 | struct clk *hdmiphy; | ||
78 | struct clk *mout_hdmi; | 85 | struct clk *mout_hdmi; |
79 | struct regulator_bulk_data *regul_bulk; | 86 | struct regulator_bulk_data *regul_bulk; |
80 | int regul_count; | 87 | int regul_count; |
@@ -185,17 +192,23 @@ struct hdmi_context { | |||
185 | 192 | ||
186 | void __iomem *regs; | 193 | void __iomem *regs; |
187 | int irq; | 194 | int irq; |
195 | struct delayed_work hotplug_work; | ||
188 | 196 | ||
189 | struct i2c_adapter *ddc_adpt; | 197 | struct i2c_adapter *ddc_adpt; |
190 | struct i2c_client *hdmiphy_port; | 198 | struct i2c_client *hdmiphy_port; |
191 | 199 | ||
192 | /* current hdmiphy conf regs */ | 200 | /* current hdmiphy conf regs */ |
201 | struct drm_display_mode current_mode; | ||
193 | struct hdmi_conf_regs mode_conf; | 202 | struct hdmi_conf_regs mode_conf; |
194 | 203 | ||
195 | struct hdmi_resources res; | 204 | struct hdmi_resources res; |
196 | 205 | ||
197 | int hpd_gpio; | 206 | int hpd_gpio; |
207 | void __iomem *regs_hdmiphy; | ||
208 | const struct hdmiphy_config *phy_confs; | ||
209 | unsigned int phy_conf_count; | ||
198 | 210 | ||
211 | struct regmap *pmureg; | ||
199 | enum hdmi_type type; | 212 | enum hdmi_type type; |
200 | }; | 213 | }; |
201 | 214 | ||
@@ -204,14 +217,6 @@ struct hdmiphy_config { | |||
204 | u8 conf[32]; | 217 | u8 conf[32]; |
205 | }; | 218 | }; |
206 | 219 | ||
207 | struct hdmi_driver_data exynos4212_hdmi_driver_data = { | ||
208 | .type = HDMI_TYPE14, | ||
209 | }; | ||
210 | |||
211 | struct hdmi_driver_data exynos5_hdmi_driver_data = { | ||
212 | .type = HDMI_TYPE14, | ||
213 | }; | ||
214 | |||
215 | /* list of phy config settings */ | 220 | /* list of phy config settings */ |
216 | static const struct hdmiphy_config hdmiphy_v13_configs[] = { | 221 | static const struct hdmiphy_config hdmiphy_v13_configs[] = { |
217 | { | 222 | { |
@@ -319,18 +324,18 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { | |||
319 | { | 324 | { |
320 | .pixel_clock = 71000000, | 325 | .pixel_clock = 71000000, |
321 | .conf = { | 326 | .conf = { |
322 | 0x01, 0x91, 0x1e, 0x15, 0x40, 0x3c, 0xce, 0x08, | 327 | 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08, |
323 | 0x04, 0x20, 0xb2, 0xd8, 0x45, 0xa0, 0xac, 0x80, | 328 | 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80, |
324 | 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, | 329 | 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, |
325 | 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | 330 | 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, |
326 | }, | 331 | }, |
327 | }, | 332 | }, |
328 | { | 333 | { |
329 | .pixel_clock = 73250000, | 334 | .pixel_clock = 73250000, |
330 | .conf = { | 335 | .conf = { |
331 | 0x01, 0xd1, 0x1f, 0x15, 0x40, 0x18, 0xe9, 0x08, | 336 | 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08, |
332 | 0x02, 0xa0, 0xb7, 0xd8, 0x45, 0xa0, 0xac, 0x80, | 337 | 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80, |
333 | 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, | 338 | 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, |
334 | 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | 339 | 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, |
335 | }, | 340 | }, |
336 | }, | 341 | }, |
@@ -362,15 +367,6 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { | |||
362 | }, | 367 | }, |
363 | }, | 368 | }, |
364 | { | 369 | { |
365 | .pixel_clock = 88750000, | ||
366 | .conf = { | ||
367 | 0x01, 0x91, 0x25, 0x17, 0x40, 0x30, 0xfe, 0x08, | ||
368 | 0x06, 0x20, 0xde, 0xd8, 0x45, 0xa0, 0xac, 0x80, | ||
369 | 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, | ||
370 | 0x54, 0x8a, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
371 | }, | ||
372 | }, | ||
373 | { | ||
374 | .pixel_clock = 106500000, | 370 | .pixel_clock = 106500000, |
375 | .conf = { | 371 | .conf = { |
376 | 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08, | 372 | 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08, |
@@ -391,18 +387,18 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { | |||
391 | { | 387 | { |
392 | .pixel_clock = 115500000, | 388 | .pixel_clock = 115500000, |
393 | .conf = { | 389 | .conf = { |
394 | 0x01, 0xd1, 0x30, 0x1a, 0x40, 0x40, 0x10, 0x04, | 390 | 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08, |
395 | 0x04, 0xa0, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80, | 391 | 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80, |
396 | 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, | 392 | 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, |
397 | 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, | 393 | 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, |
398 | }, | 394 | }, |
399 | }, | 395 | }, |
400 | { | 396 | { |
401 | .pixel_clock = 119000000, | 397 | .pixel_clock = 119000000, |
402 | .conf = { | 398 | .conf = { |
403 | 0x01, 0x91, 0x32, 0x14, 0x40, 0x60, 0xd8, 0x08, | 399 | 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08, |
404 | 0x06, 0x20, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80, | 400 | 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80, |
405 | 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, | 401 | 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, |
406 | 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, | 402 | 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, |
407 | }, | 403 | }, |
408 | }, | 404 | }, |
@@ -426,6 +422,183 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { | |||
426 | }, | 422 | }, |
427 | }; | 423 | }; |
428 | 424 | ||
425 | static const struct hdmiphy_config hdmiphy_5420_configs[] = { | ||
426 | { | ||
427 | .pixel_clock = 25200000, | ||
428 | .conf = { | ||
429 | 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8, | ||
430 | 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
431 | 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
432 | 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
433 | }, | ||
434 | }, | ||
435 | { | ||
436 | .pixel_clock = 27000000, | ||
437 | .conf = { | ||
438 | 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0, | ||
439 | 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
440 | 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
441 | 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
442 | }, | ||
443 | }, | ||
444 | { | ||
445 | .pixel_clock = 27027000, | ||
446 | .conf = { | ||
447 | 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8, | ||
448 | 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
449 | 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
450 | 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
451 | }, | ||
452 | }, | ||
453 | { | ||
454 | .pixel_clock = 36000000, | ||
455 | .conf = { | ||
456 | 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8, | ||
457 | 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
458 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
459 | 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
460 | }, | ||
461 | }, | ||
462 | { | ||
463 | .pixel_clock = 40000000, | ||
464 | .conf = { | ||
465 | 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8, | ||
466 | 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
467 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
468 | 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
469 | }, | ||
470 | }, | ||
471 | { | ||
472 | .pixel_clock = 65000000, | ||
473 | .conf = { | ||
474 | 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8, | ||
475 | 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
476 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
477 | 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
478 | }, | ||
479 | }, | ||
480 | { | ||
481 | .pixel_clock = 71000000, | ||
482 | .conf = { | ||
483 | 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8, | ||
484 | 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
485 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
486 | 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
487 | }, | ||
488 | }, | ||
489 | { | ||
490 | .pixel_clock = 73250000, | ||
491 | .conf = { | ||
492 | 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8, | ||
493 | 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
494 | 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
495 | 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
496 | }, | ||
497 | }, | ||
498 | { | ||
499 | .pixel_clock = 74176000, | ||
500 | .conf = { | ||
501 | 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8, | ||
502 | 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
503 | 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
504 | 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
505 | }, | ||
506 | }, | ||
507 | { | ||
508 | .pixel_clock = 74250000, | ||
509 | .conf = { | ||
510 | 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08, | ||
511 | 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
512 | 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66, | ||
513 | 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
514 | }, | ||
515 | }, | ||
516 | { | ||
517 | .pixel_clock = 83500000, | ||
518 | .conf = { | ||
519 | 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8, | ||
520 | 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
521 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
522 | 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
523 | }, | ||
524 | }, | ||
525 | { | ||
526 | .pixel_clock = 88750000, | ||
527 | .conf = { | ||
528 | 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8, | ||
529 | 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
530 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
531 | 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, | ||
532 | }, | ||
533 | }, | ||
534 | { | ||
535 | .pixel_clock = 106500000, | ||
536 | .conf = { | ||
537 | 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8, | ||
538 | 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
539 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
540 | 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
541 | }, | ||
542 | }, | ||
543 | { | ||
544 | .pixel_clock = 108000000, | ||
545 | .conf = { | ||
546 | 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8, | ||
547 | 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
548 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
549 | 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, | ||
550 | }, | ||
551 | }, | ||
552 | { | ||
553 | .pixel_clock = 115500000, | ||
554 | .conf = { | ||
555 | 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8, | ||
556 | 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
557 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
558 | 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
559 | }, | ||
560 | }, | ||
561 | { | ||
562 | .pixel_clock = 146250000, | ||
563 | .conf = { | ||
564 | 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8, | ||
565 | 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
566 | 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, | ||
567 | 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, | ||
568 | }, | ||
569 | }, | ||
570 | { | ||
571 | .pixel_clock = 148500000, | ||
572 | .conf = { | ||
573 | 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08, | ||
574 | 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
575 | 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66, | ||
576 | 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80, | ||
577 | }, | ||
578 | }, | ||
579 | }; | ||
580 | |||
581 | static struct hdmi_driver_data exynos5420_hdmi_driver_data = { | ||
582 | .type = HDMI_TYPE14, | ||
583 | .phy_confs = hdmiphy_5420_configs, | ||
584 | .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs), | ||
585 | .is_apb_phy = 1, | ||
586 | }; | ||
587 | |||
588 | static struct hdmi_driver_data exynos4212_hdmi_driver_data = { | ||
589 | .type = HDMI_TYPE14, | ||
590 | .phy_confs = hdmiphy_v14_configs, | ||
591 | .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs), | ||
592 | .is_apb_phy = 0, | ||
593 | }; | ||
594 | |||
595 | static struct hdmi_driver_data exynos5_hdmi_driver_data = { | ||
596 | .type = HDMI_TYPE14, | ||
597 | .phy_confs = hdmiphy_v13_configs, | ||
598 | .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), | ||
599 | .is_apb_phy = 0, | ||
600 | }; | ||
601 | |||
429 | static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) | 602 | static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) |
430 | { | 603 | { |
431 | return readl(hdata->regs + reg_id); | 604 | return readl(hdata->regs + reg_id); |
@@ -445,6 +618,48 @@ static inline void hdmi_reg_writemask(struct hdmi_context *hdata, | |||
445 | writel(value, hdata->regs + reg_id); | 618 | writel(value, hdata->regs + reg_id); |
446 | } | 619 | } |
447 | 620 | ||
621 | static int hdmiphy_reg_writeb(struct hdmi_context *hdata, | ||
622 | u32 reg_offset, u8 value) | ||
623 | { | ||
624 | if (hdata->hdmiphy_port) { | ||
625 | u8 buffer[2]; | ||
626 | int ret; | ||
627 | |||
628 | buffer[0] = reg_offset; | ||
629 | buffer[1] = value; | ||
630 | |||
631 | ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2); | ||
632 | if (ret == 2) | ||
633 | return 0; | ||
634 | return ret; | ||
635 | } else { | ||
636 | writeb(value, hdata->regs_hdmiphy + (reg_offset<<2)); | ||
637 | return 0; | ||
638 | } | ||
639 | } | ||
640 | |||
641 | static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, | ||
642 | u32 reg_offset, const u8 *buf, u32 len) | ||
643 | { | ||
644 | if ((reg_offset + len) > 32) | ||
645 | return -EINVAL; | ||
646 | |||
647 | if (hdata->hdmiphy_port) { | ||
648 | int ret; | ||
649 | |||
650 | ret = i2c_master_send(hdata->hdmiphy_port, buf, len); | ||
651 | if (ret == len) | ||
652 | return 0; | ||
653 | return ret; | ||
654 | } else { | ||
655 | int i; | ||
656 | for (i = 0; i < len; i++) | ||
657 | writeb(buf[i], hdata->regs_hdmiphy + | ||
658 | ((reg_offset + i)<<2)); | ||
659 | return 0; | ||
660 | } | ||
661 | } | ||
662 | |||
448 | static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix) | 663 | static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix) |
449 | { | 664 | { |
450 | #define DUMPREG(reg_id) \ | 665 | #define DUMPREG(reg_id) \ |
@@ -809,6 +1024,8 @@ static enum drm_connector_status hdmi_detect(struct drm_connector *connector, | |||
809 | { | 1024 | { |
810 | struct hdmi_context *hdata = ctx_from_connector(connector); | 1025 | struct hdmi_context *hdata = ctx_from_connector(connector); |
811 | 1026 | ||
1027 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | ||
1028 | |||
812 | return hdata->hpd ? connector_status_connected : | 1029 | return hdata->hpd ? connector_status_connected : |
813 | connector_status_disconnected; | 1030 | connector_status_disconnected; |
814 | } | 1031 | } |
@@ -848,20 +1065,10 @@ static int hdmi_get_modes(struct drm_connector *connector) | |||
848 | 1065 | ||
849 | static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) | 1066 | static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) |
850 | { | 1067 | { |
851 | const struct hdmiphy_config *confs; | 1068 | int i; |
852 | int count, i; | ||
853 | |||
854 | if (hdata->type == HDMI_TYPE13) { | ||
855 | confs = hdmiphy_v13_configs; | ||
856 | count = ARRAY_SIZE(hdmiphy_v13_configs); | ||
857 | } else if (hdata->type == HDMI_TYPE14) { | ||
858 | confs = hdmiphy_v14_configs; | ||
859 | count = ARRAY_SIZE(hdmiphy_v14_configs); | ||
860 | } else | ||
861 | return -EINVAL; | ||
862 | 1069 | ||
863 | for (i = 0; i < count; i++) | 1070 | for (i = 0; i < hdata->phy_conf_count; i++) |
864 | if (confs[i].pixel_clock == pixel_clock) | 1071 | if (hdata->phy_confs[i].pixel_clock == pixel_clock) |
865 | return i; | 1072 | return i; |
866 | 1073 | ||
867 | DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); | 1074 | DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); |
@@ -928,16 +1135,6 @@ static int hdmi_create_connector(struct exynos_drm_display *display, | |||
928 | return 0; | 1135 | return 0; |
929 | } | 1136 | } |
930 | 1137 | ||
931 | static int hdmi_initialize(struct exynos_drm_display *display, | ||
932 | struct drm_device *drm_dev) | ||
933 | { | ||
934 | struct hdmi_context *hdata = display->ctx; | ||
935 | |||
936 | hdata->drm_dev = drm_dev; | ||
937 | |||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static void hdmi_mode_fixup(struct exynos_drm_display *display, | 1138 | static void hdmi_mode_fixup(struct exynos_drm_display *display, |
942 | struct drm_connector *connector, | 1139 | struct drm_connector *connector, |
943 | const struct drm_display_mode *mode, | 1140 | const struct drm_display_mode *mode, |
@@ -1136,20 +1333,15 @@ static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff) | |||
1136 | HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK); | 1333 | HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK); |
1137 | } | 1334 | } |
1138 | 1335 | ||
1139 | static void hdmi_conf_reset(struct hdmi_context *hdata) | 1336 | static void hdmi_start(struct hdmi_context *hdata, bool start) |
1140 | { | 1337 | { |
1141 | u32 reg; | 1338 | u32 val = start ? HDMI_TG_EN : 0; |
1142 | 1339 | ||
1143 | if (hdata->type == HDMI_TYPE13) | 1340 | if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE) |
1144 | reg = HDMI_V13_CORE_RSTOUT; | 1341 | val |= HDMI_FIELD_EN; |
1145 | else | ||
1146 | reg = HDMI_CORE_RSTOUT; | ||
1147 | 1342 | ||
1148 | /* resetting HDMI core */ | 1343 | hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN); |
1149 | hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT); | 1344 | hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN); |
1150 | usleep_range(10000, 12000); | ||
1151 | hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT); | ||
1152 | usleep_range(10000, 12000); | ||
1153 | } | 1345 | } |
1154 | 1346 | ||
1155 | static void hdmi_conf_init(struct hdmi_context *hdata) | 1347 | static void hdmi_conf_init(struct hdmi_context *hdata) |
@@ -1163,6 +1355,8 @@ static void hdmi_conf_init(struct hdmi_context *hdata) | |||
1163 | /* choose HDMI mode */ | 1355 | /* choose HDMI mode */ |
1164 | hdmi_reg_writemask(hdata, HDMI_MODE_SEL, | 1356 | hdmi_reg_writemask(hdata, HDMI_MODE_SEL, |
1165 | HDMI_MODE_HDMI_EN, HDMI_MODE_MASK); | 1357 | HDMI_MODE_HDMI_EN, HDMI_MODE_MASK); |
1358 | /* Apply Video preable and Guard band in HDMI mode only */ | ||
1359 | hdmi_reg_writeb(hdata, HDMI_CON_2, 0); | ||
1166 | /* disable bluescreen */ | 1360 | /* disable bluescreen */ |
1167 | hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); | 1361 | hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); |
1168 | 1362 | ||
@@ -1286,12 +1480,7 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) | |||
1286 | clk_prepare_enable(hdata->res.sclk_hdmi); | 1480 | clk_prepare_enable(hdata->res.sclk_hdmi); |
1287 | 1481 | ||
1288 | /* enable HDMI and timing generator */ | 1482 | /* enable HDMI and timing generator */ |
1289 | hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN); | 1483 | hdmi_start(hdata, true); |
1290 | if (core->int_pro_mode[0]) | ||
1291 | hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN | | ||
1292 | HDMI_FIELD_EN); | ||
1293 | else | ||
1294 | hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN); | ||
1295 | } | 1484 | } |
1296 | 1485 | ||
1297 | static void hdmi_v14_mode_apply(struct hdmi_context *hdata) | 1486 | static void hdmi_v14_mode_apply(struct hdmi_context *hdata) |
@@ -1453,12 +1642,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) | |||
1453 | clk_prepare_enable(hdata->res.sclk_hdmi); | 1642 | clk_prepare_enable(hdata->res.sclk_hdmi); |
1454 | 1643 | ||
1455 | /* enable HDMI and timing generator */ | 1644 | /* enable HDMI and timing generator */ |
1456 | hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN); | 1645 | hdmi_start(hdata, true); |
1457 | if (core->int_pro_mode[0]) | ||
1458 | hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN | | ||
1459 | HDMI_FIELD_EN); | ||
1460 | else | ||
1461 | hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN); | ||
1462 | } | 1646 | } |
1463 | 1647 | ||
1464 | static void hdmi_mode_apply(struct hdmi_context *hdata) | 1648 | static void hdmi_mode_apply(struct hdmi_context *hdata) |
@@ -1499,32 +1683,51 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) | |||
1499 | 1683 | ||
1500 | static void hdmiphy_poweron(struct hdmi_context *hdata) | 1684 | static void hdmiphy_poweron(struct hdmi_context *hdata) |
1501 | { | 1685 | { |
1502 | if (hdata->type == HDMI_TYPE14) | 1686 | if (hdata->type != HDMI_TYPE14) |
1503 | hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, | 1687 | return; |
1504 | HDMI_PHY_POWER_OFF_EN); | 1688 | |
1689 | DRM_DEBUG_KMS("\n"); | ||
1690 | |||
1691 | /* For PHY Mode Setting */ | ||
1692 | hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, | ||
1693 | HDMI_PHY_ENABLE_MODE_SET); | ||
1694 | /* Phy Power On */ | ||
1695 | hdmiphy_reg_writeb(hdata, HDMIPHY_POWER, | ||
1696 | HDMI_PHY_POWER_ON); | ||
1697 | /* For PHY Mode Setting */ | ||
1698 | hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, | ||
1699 | HDMI_PHY_DISABLE_MODE_SET); | ||
1700 | /* PHY SW Reset */ | ||
1701 | hdmiphy_conf_reset(hdata); | ||
1505 | } | 1702 | } |
1506 | 1703 | ||
1507 | static void hdmiphy_poweroff(struct hdmi_context *hdata) | 1704 | static void hdmiphy_poweroff(struct hdmi_context *hdata) |
1508 | { | 1705 | { |
1509 | if (hdata->type == HDMI_TYPE14) | 1706 | if (hdata->type != HDMI_TYPE14) |
1510 | hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, | 1707 | return; |
1511 | HDMI_PHY_POWER_OFF_EN); | 1708 | |
1709 | DRM_DEBUG_KMS("\n"); | ||
1710 | |||
1711 | /* PHY SW Reset */ | ||
1712 | hdmiphy_conf_reset(hdata); | ||
1713 | /* For PHY Mode Setting */ | ||
1714 | hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, | ||
1715 | HDMI_PHY_ENABLE_MODE_SET); | ||
1716 | |||
1717 | /* PHY Power Off */ | ||
1718 | hdmiphy_reg_writeb(hdata, HDMIPHY_POWER, | ||
1719 | HDMI_PHY_POWER_OFF); | ||
1720 | |||
1721 | /* For PHY Mode Setting */ | ||
1722 | hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, | ||
1723 | HDMI_PHY_DISABLE_MODE_SET); | ||
1512 | } | 1724 | } |
1513 | 1725 | ||
1514 | static void hdmiphy_conf_apply(struct hdmi_context *hdata) | 1726 | static void hdmiphy_conf_apply(struct hdmi_context *hdata) |
1515 | { | 1727 | { |
1516 | const u8 *hdmiphy_data; | ||
1517 | u8 buffer[32]; | ||
1518 | u8 operation[2]; | ||
1519 | u8 read_buffer[32] = {0, }; | ||
1520 | int ret; | 1728 | int ret; |
1521 | int i; | 1729 | int i; |
1522 | 1730 | ||
1523 | if (!hdata->hdmiphy_port) { | ||
1524 | DRM_ERROR("hdmiphy is not attached\n"); | ||
1525 | return; | ||
1526 | } | ||
1527 | |||
1528 | /* pixel clock */ | 1731 | /* pixel clock */ |
1529 | i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock); | 1732 | i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock); |
1530 | if (i < 0) { | 1733 | if (i < 0) { |
@@ -1532,39 +1735,21 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) | |||
1532 | return; | 1735 | return; |
1533 | } | 1736 | } |
1534 | 1737 | ||
1535 | if (hdata->type == HDMI_TYPE13) | 1738 | ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32); |
1536 | hdmiphy_data = hdmiphy_v13_configs[i].conf; | 1739 | if (ret) { |
1537 | else | 1740 | DRM_ERROR("failed to configure hdmiphy\n"); |
1538 | hdmiphy_data = hdmiphy_v14_configs[i].conf; | ||
1539 | |||
1540 | memcpy(buffer, hdmiphy_data, 32); | ||
1541 | ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32); | ||
1542 | if (ret != 32) { | ||
1543 | DRM_ERROR("failed to configure HDMIPHY via I2C\n"); | ||
1544 | return; | 1741 | return; |
1545 | } | 1742 | } |
1546 | 1743 | ||
1547 | usleep_range(10000, 12000); | 1744 | usleep_range(10000, 12000); |
1548 | 1745 | ||
1549 | /* operation mode */ | 1746 | ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, |
1550 | operation[0] = 0x1f; | 1747 | HDMI_PHY_DISABLE_MODE_SET); |
1551 | operation[1] = 0x80; | 1748 | if (ret) { |
1552 | |||
1553 | ret = i2c_master_send(hdata->hdmiphy_port, operation, 2); | ||
1554 | if (ret != 2) { | ||
1555 | DRM_ERROR("failed to enable hdmiphy\n"); | 1749 | DRM_ERROR("failed to enable hdmiphy\n"); |
1556 | return; | 1750 | return; |
1557 | } | 1751 | } |
1558 | 1752 | ||
1559 | ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32); | ||
1560 | if (ret < 0) { | ||
1561 | DRM_ERROR("failed to read hdmiphy config\n"); | ||
1562 | return; | ||
1563 | } | ||
1564 | |||
1565 | for (i = 0; i < ret; i++) | ||
1566 | DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - " | ||
1567 | "recv [0x%02x]\n", i, buffer[i], read_buffer[i]); | ||
1568 | } | 1753 | } |
1569 | 1754 | ||
1570 | static void hdmi_conf_apply(struct hdmi_context *hdata) | 1755 | static void hdmi_conf_apply(struct hdmi_context *hdata) |
@@ -1573,7 +1758,7 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) | |||
1573 | hdmiphy_conf_apply(hdata); | 1758 | hdmiphy_conf_apply(hdata); |
1574 | 1759 | ||
1575 | mutex_lock(&hdata->hdmi_mutex); | 1760 | mutex_lock(&hdata->hdmi_mutex); |
1576 | hdmi_conf_reset(hdata); | 1761 | hdmi_start(hdata, false); |
1577 | hdmi_conf_init(hdata); | 1762 | hdmi_conf_init(hdata); |
1578 | mutex_unlock(&hdata->hdmi_mutex); | 1763 | mutex_unlock(&hdata->hdmi_mutex); |
1579 | 1764 | ||
@@ -1814,6 +1999,9 @@ static void hdmi_mode_set(struct exynos_drm_display *display, | |||
1814 | m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? | 1999 | m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? |
1815 | "INTERLACED" : "PROGERESSIVE"); | 2000 | "INTERLACED" : "PROGERESSIVE"); |
1816 | 2001 | ||
2002 | /* preserve mode information for later use. */ | ||
2003 | drm_mode_copy(&hdata->current_mode, mode); | ||
2004 | |||
1817 | if (hdata->type == HDMI_TYPE13) | 2005 | if (hdata->type == HDMI_TYPE13) |
1818 | hdmi_v13_mode_set(hdata, mode); | 2006 | hdmi_v13_mode_set(hdata, mode); |
1819 | else | 2007 | else |
@@ -1854,7 +2042,10 @@ static void hdmi_poweron(struct exynos_drm_display *display) | |||
1854 | if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) | 2042 | if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) |
1855 | DRM_DEBUG_KMS("failed to enable regulator bulk\n"); | 2043 | DRM_DEBUG_KMS("failed to enable regulator bulk\n"); |
1856 | 2044 | ||
1857 | clk_prepare_enable(res->hdmiphy); | 2045 | /* set pmu hdmiphy control bit to enable hdmiphy */ |
2046 | regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, | ||
2047 | PMU_HDMI_PHY_ENABLE_BIT, 1); | ||
2048 | |||
1858 | clk_prepare_enable(res->hdmi); | 2049 | clk_prepare_enable(res->hdmi); |
1859 | clk_prepare_enable(res->sclk_hdmi); | 2050 | clk_prepare_enable(res->sclk_hdmi); |
1860 | 2051 | ||
@@ -1872,16 +2063,20 @@ static void hdmi_poweroff(struct exynos_drm_display *display) | |||
1872 | goto out; | 2063 | goto out; |
1873 | mutex_unlock(&hdata->hdmi_mutex); | 2064 | mutex_unlock(&hdata->hdmi_mutex); |
1874 | 2065 | ||
1875 | /* | 2066 | /* HDMI System Disable */ |
1876 | * The TV power domain needs any condition of hdmiphy to turn off and | 2067 | hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); |
1877 | * its reset state seems to meet the condition. | 2068 | |
1878 | */ | ||
1879 | hdmiphy_conf_reset(hdata); | ||
1880 | hdmiphy_poweroff(hdata); | 2069 | hdmiphy_poweroff(hdata); |
1881 | 2070 | ||
2071 | cancel_delayed_work(&hdata->hotplug_work); | ||
2072 | |||
1882 | clk_disable_unprepare(res->sclk_hdmi); | 2073 | clk_disable_unprepare(res->sclk_hdmi); |
1883 | clk_disable_unprepare(res->hdmi); | 2074 | clk_disable_unprepare(res->hdmi); |
1884 | clk_disable_unprepare(res->hdmiphy); | 2075 | |
2076 | /* reset pmu hdmiphy control bit to disable hdmiphy */ | ||
2077 | regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, | ||
2078 | PMU_HDMI_PHY_ENABLE_BIT, 0); | ||
2079 | |||
1885 | regulator_bulk_disable(res->regul_count, res->regul_bulk); | 2080 | regulator_bulk_disable(res->regul_count, res->regul_bulk); |
1886 | 2081 | ||
1887 | pm_runtime_put_sync(hdata->dev); | 2082 | pm_runtime_put_sync(hdata->dev); |
@@ -1913,7 +2108,6 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode) | |||
1913 | } | 2108 | } |
1914 | 2109 | ||
1915 | static struct exynos_drm_display_ops hdmi_display_ops = { | 2110 | static struct exynos_drm_display_ops hdmi_display_ops = { |
1916 | .initialize = hdmi_initialize, | ||
1917 | .create_connector = hdmi_create_connector, | 2111 | .create_connector = hdmi_create_connector, |
1918 | .mode_fixup = hdmi_mode_fixup, | 2112 | .mode_fixup = hdmi_mode_fixup, |
1919 | .mode_set = hdmi_mode_set, | 2113 | .mode_set = hdmi_mode_set, |
@@ -1926,9 +2120,11 @@ static struct exynos_drm_display hdmi_display = { | |||
1926 | .ops = &hdmi_display_ops, | 2120 | .ops = &hdmi_display_ops, |
1927 | }; | 2121 | }; |
1928 | 2122 | ||
1929 | static irqreturn_t hdmi_irq_thread(int irq, void *arg) | 2123 | static void hdmi_hotplug_work_func(struct work_struct *work) |
1930 | { | 2124 | { |
1931 | struct hdmi_context *hdata = arg; | 2125 | struct hdmi_context *hdata; |
2126 | |||
2127 | hdata = container_of(work, struct hdmi_context, hotplug_work.work); | ||
1932 | 2128 | ||
1933 | mutex_lock(&hdata->hdmi_mutex); | 2129 | mutex_lock(&hdata->hdmi_mutex); |
1934 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | 2130 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); |
@@ -1936,6 +2132,14 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) | |||
1936 | 2132 | ||
1937 | if (hdata->drm_dev) | 2133 | if (hdata->drm_dev) |
1938 | drm_helper_hpd_irq_event(hdata->drm_dev); | 2134 | drm_helper_hpd_irq_event(hdata->drm_dev); |
2135 | } | ||
2136 | |||
2137 | static irqreturn_t hdmi_irq_thread(int irq, void *arg) | ||
2138 | { | ||
2139 | struct hdmi_context *hdata = arg; | ||
2140 | |||
2141 | mod_delayed_work(system_wq, &hdata->hotplug_work, | ||
2142 | msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); | ||
1939 | 2143 | ||
1940 | return IRQ_HANDLED; | 2144 | return IRQ_HANDLED; |
1941 | } | 2145 | } |
@@ -1954,37 +2158,35 @@ static int hdmi_resources_init(struct hdmi_context *hdata) | |||
1954 | 2158 | ||
1955 | DRM_DEBUG_KMS("HDMI resource init\n"); | 2159 | DRM_DEBUG_KMS("HDMI resource init\n"); |
1956 | 2160 | ||
1957 | memset(res, 0, sizeof(*res)); | ||
1958 | |||
1959 | /* get clocks, power */ | 2161 | /* get clocks, power */ |
1960 | res->hdmi = devm_clk_get(dev, "hdmi"); | 2162 | res->hdmi = devm_clk_get(dev, "hdmi"); |
1961 | if (IS_ERR(res->hdmi)) { | 2163 | if (IS_ERR(res->hdmi)) { |
1962 | DRM_ERROR("failed to get clock 'hdmi'\n"); | 2164 | DRM_ERROR("failed to get clock 'hdmi'\n"); |
2165 | ret = PTR_ERR(res->hdmi); | ||
1963 | goto fail; | 2166 | goto fail; |
1964 | } | 2167 | } |
1965 | res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); | 2168 | res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); |
1966 | if (IS_ERR(res->sclk_hdmi)) { | 2169 | if (IS_ERR(res->sclk_hdmi)) { |
1967 | DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); | 2170 | DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); |
2171 | ret = PTR_ERR(res->sclk_hdmi); | ||
1968 | goto fail; | 2172 | goto fail; |
1969 | } | 2173 | } |
1970 | res->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); | 2174 | res->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); |
1971 | if (IS_ERR(res->sclk_pixel)) { | 2175 | if (IS_ERR(res->sclk_pixel)) { |
1972 | DRM_ERROR("failed to get clock 'sclk_pixel'\n"); | 2176 | DRM_ERROR("failed to get clock 'sclk_pixel'\n"); |
2177 | ret = PTR_ERR(res->sclk_pixel); | ||
1973 | goto fail; | 2178 | goto fail; |
1974 | } | 2179 | } |
1975 | res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); | 2180 | res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); |
1976 | if (IS_ERR(res->sclk_hdmiphy)) { | 2181 | if (IS_ERR(res->sclk_hdmiphy)) { |
1977 | DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); | 2182 | DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); |
1978 | goto fail; | 2183 | ret = PTR_ERR(res->sclk_hdmiphy); |
1979 | } | ||
1980 | res->hdmiphy = devm_clk_get(dev, "hdmiphy"); | ||
1981 | if (IS_ERR(res->hdmiphy)) { | ||
1982 | DRM_ERROR("failed to get clock 'hdmiphy'\n"); | ||
1983 | goto fail; | 2184 | goto fail; |
1984 | } | 2185 | } |
1985 | res->mout_hdmi = devm_clk_get(dev, "mout_hdmi"); | 2186 | res->mout_hdmi = devm_clk_get(dev, "mout_hdmi"); |
1986 | if (IS_ERR(res->mout_hdmi)) { | 2187 | if (IS_ERR(res->mout_hdmi)) { |
1987 | DRM_ERROR("failed to get clock 'mout_hdmi'\n"); | 2188 | DRM_ERROR("failed to get clock 'mout_hdmi'\n"); |
2189 | ret = PTR_ERR(res->mout_hdmi); | ||
1988 | goto fail; | 2190 | goto fail; |
1989 | } | 2191 | } |
1990 | 2192 | ||
@@ -1992,8 +2194,10 @@ static int hdmi_resources_init(struct hdmi_context *hdata) | |||
1992 | 2194 | ||
1993 | res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) * | 2195 | res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) * |
1994 | sizeof(res->regul_bulk[0]), GFP_KERNEL); | 2196 | sizeof(res->regul_bulk[0]), GFP_KERNEL); |
1995 | if (!res->regul_bulk) | 2197 | if (!res->regul_bulk) { |
2198 | ret = -ENOMEM; | ||
1996 | goto fail; | 2199 | goto fail; |
2200 | } | ||
1997 | for (i = 0; i < ARRAY_SIZE(supply); ++i) { | 2201 | for (i = 0; i < ARRAY_SIZE(supply); ++i) { |
1998 | res->regul_bulk[i].supply = supply[i]; | 2202 | res->regul_bulk[i].supply = supply[i]; |
1999 | res->regul_bulk[i].consumer = NULL; | 2203 | res->regul_bulk[i].consumer = NULL; |
@@ -2001,14 +2205,14 @@ static int hdmi_resources_init(struct hdmi_context *hdata) | |||
2001 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk); | 2205 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk); |
2002 | if (ret) { | 2206 | if (ret) { |
2003 | DRM_ERROR("failed to get regulators\n"); | 2207 | DRM_ERROR("failed to get regulators\n"); |
2004 | goto fail; | 2208 | return ret; |
2005 | } | 2209 | } |
2006 | res->regul_count = ARRAY_SIZE(supply); | 2210 | res->regul_count = ARRAY_SIZE(supply); |
2007 | 2211 | ||
2008 | return 0; | 2212 | return ret; |
2009 | fail: | 2213 | fail: |
2010 | DRM_ERROR("HDMI resource init - failed\n"); | 2214 | DRM_ERROR("HDMI resource init - failed\n"); |
2011 | return -ENODEV; | 2215 | return ret; |
2012 | } | 2216 | } |
2013 | 2217 | ||
2014 | static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata | 2218 | static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata |
@@ -2043,42 +2247,105 @@ static struct of_device_id hdmi_match_types[] = { | |||
2043 | .compatible = "samsung,exynos4212-hdmi", | 2247 | .compatible = "samsung,exynos4212-hdmi", |
2044 | .data = &exynos4212_hdmi_driver_data, | 2248 | .data = &exynos4212_hdmi_driver_data, |
2045 | }, { | 2249 | }, { |
2250 | .compatible = "samsung,exynos5420-hdmi", | ||
2251 | .data = &exynos5420_hdmi_driver_data, | ||
2252 | }, { | ||
2046 | /* end node */ | 2253 | /* end node */ |
2047 | } | 2254 | } |
2048 | }; | 2255 | }; |
2049 | 2256 | ||
2257 | static int hdmi_bind(struct device *dev, struct device *master, void *data) | ||
2258 | { | ||
2259 | struct drm_device *drm_dev = data; | ||
2260 | struct hdmi_context *hdata; | ||
2261 | |||
2262 | hdata = hdmi_display.ctx; | ||
2263 | hdata->drm_dev = drm_dev; | ||
2264 | |||
2265 | return exynos_drm_create_enc_conn(drm_dev, &hdmi_display); | ||
2266 | } | ||
2267 | |||
2268 | static void hdmi_unbind(struct device *dev, struct device *master, void *data) | ||
2269 | { | ||
2270 | struct exynos_drm_display *display = get_hdmi_display(dev); | ||
2271 | struct drm_encoder *encoder = display->encoder; | ||
2272 | struct hdmi_context *hdata = display->ctx; | ||
2273 | |||
2274 | encoder->funcs->destroy(encoder); | ||
2275 | drm_connector_cleanup(&hdata->connector); | ||
2276 | } | ||
2277 | |||
2278 | static const struct component_ops hdmi_component_ops = { | ||
2279 | .bind = hdmi_bind, | ||
2280 | .unbind = hdmi_unbind, | ||
2281 | }; | ||
2282 | |||
2283 | static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev) | ||
2284 | { | ||
2285 | const char *compatible_str = "samsung,exynos4210-hdmiddc"; | ||
2286 | struct device_node *np; | ||
2287 | |||
2288 | np = of_find_compatible_node(NULL, NULL, compatible_str); | ||
2289 | if (np) | ||
2290 | return of_get_next_parent(np); | ||
2291 | |||
2292 | return NULL; | ||
2293 | } | ||
2294 | |||
2295 | static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev) | ||
2296 | { | ||
2297 | const char *compatible_str = "samsung,exynos4212-hdmiphy"; | ||
2298 | |||
2299 | return of_find_compatible_node(NULL, NULL, compatible_str); | ||
2300 | } | ||
2301 | |||
2050 | static int hdmi_probe(struct platform_device *pdev) | 2302 | static int hdmi_probe(struct platform_device *pdev) |
2051 | { | 2303 | { |
2304 | struct device_node *ddc_node, *phy_node; | ||
2305 | struct s5p_hdmi_platform_data *pdata; | ||
2306 | struct hdmi_driver_data *drv_data; | ||
2307 | const struct of_device_id *match; | ||
2052 | struct device *dev = &pdev->dev; | 2308 | struct device *dev = &pdev->dev; |
2053 | struct hdmi_context *hdata; | 2309 | struct hdmi_context *hdata; |
2054 | struct s5p_hdmi_platform_data *pdata; | ||
2055 | struct resource *res; | 2310 | struct resource *res; |
2056 | const struct of_device_id *match; | ||
2057 | struct device_node *ddc_node, *phy_node; | ||
2058 | struct hdmi_driver_data *drv_data; | ||
2059 | int ret; | 2311 | int ret; |
2060 | 2312 | ||
2061 | if (!dev->of_node) | 2313 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, |
2062 | return -ENODEV; | 2314 | hdmi_display.type); |
2315 | if (ret) | ||
2316 | return ret; | ||
2317 | |||
2318 | if (!dev->of_node) { | ||
2319 | ret = -ENODEV; | ||
2320 | goto err_del_component; | ||
2321 | } | ||
2063 | 2322 | ||
2064 | pdata = drm_hdmi_dt_parse_pdata(dev); | 2323 | pdata = drm_hdmi_dt_parse_pdata(dev); |
2065 | if (!pdata) | 2324 | if (!pdata) { |
2066 | return -EINVAL; | 2325 | ret = -EINVAL; |
2326 | goto err_del_component; | ||
2327 | } | ||
2067 | 2328 | ||
2068 | hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); | 2329 | hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); |
2069 | if (!hdata) | 2330 | if (!hdata) { |
2070 | return -ENOMEM; | 2331 | ret = -ENOMEM; |
2332 | goto err_del_component; | ||
2333 | } | ||
2071 | 2334 | ||
2072 | mutex_init(&hdata->hdmi_mutex); | 2335 | mutex_init(&hdata->hdmi_mutex); |
2073 | 2336 | ||
2074 | platform_set_drvdata(pdev, &hdmi_display); | 2337 | platform_set_drvdata(pdev, &hdmi_display); |
2075 | 2338 | ||
2076 | match = of_match_node(hdmi_match_types, dev->of_node); | 2339 | match = of_match_node(hdmi_match_types, dev->of_node); |
2077 | if (!match) | 2340 | if (!match) { |
2078 | return -ENODEV; | 2341 | ret = -ENODEV; |
2342 | goto err_del_component; | ||
2343 | } | ||
2079 | 2344 | ||
2080 | drv_data = (struct hdmi_driver_data *)match->data; | 2345 | drv_data = (struct hdmi_driver_data *)match->data; |
2081 | hdata->type = drv_data->type; | 2346 | hdata->type = drv_data->type; |
2347 | hdata->phy_confs = drv_data->phy_confs; | ||
2348 | hdata->phy_conf_count = drv_data->phy_conf_count; | ||
2082 | 2349 | ||
2083 | hdata->hpd_gpio = pdata->hpd_gpio; | 2350 | hdata->hpd_gpio = pdata->hpd_gpio; |
2084 | hdata->dev = dev; | 2351 | hdata->dev = dev; |
@@ -2086,35 +2353,44 @@ static int hdmi_probe(struct platform_device *pdev) | |||
2086 | ret = hdmi_resources_init(hdata); | 2353 | ret = hdmi_resources_init(hdata); |
2087 | if (ret) { | 2354 | if (ret) { |
2088 | DRM_ERROR("hdmi_resources_init failed\n"); | 2355 | DRM_ERROR("hdmi_resources_init failed\n"); |
2089 | return -EINVAL; | 2356 | return ret; |
2090 | } | 2357 | } |
2091 | 2358 | ||
2092 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2359 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
2093 | hdata->regs = devm_ioremap_resource(dev, res); | 2360 | hdata->regs = devm_ioremap_resource(dev, res); |
2094 | if (IS_ERR(hdata->regs)) | 2361 | if (IS_ERR(hdata->regs)) { |
2095 | return PTR_ERR(hdata->regs); | 2362 | ret = PTR_ERR(hdata->regs); |
2363 | goto err_del_component; | ||
2364 | } | ||
2096 | 2365 | ||
2097 | ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD"); | 2366 | ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD"); |
2098 | if (ret) { | 2367 | if (ret) { |
2099 | DRM_ERROR("failed to request HPD gpio\n"); | 2368 | DRM_ERROR("failed to request HPD gpio\n"); |
2100 | return ret; | 2369 | goto err_del_component; |
2101 | } | 2370 | } |
2102 | 2371 | ||
2372 | ddc_node = hdmi_legacy_ddc_dt_binding(dev); | ||
2373 | if (ddc_node) | ||
2374 | goto out_get_ddc_adpt; | ||
2375 | |||
2103 | /* DDC i2c driver */ | 2376 | /* DDC i2c driver */ |
2104 | ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); | 2377 | ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); |
2105 | if (!ddc_node) { | 2378 | if (!ddc_node) { |
2106 | DRM_ERROR("Failed to find ddc node in device tree\n"); | 2379 | DRM_ERROR("Failed to find ddc node in device tree\n"); |
2107 | return -ENODEV; | 2380 | ret = -ENODEV; |
2381 | goto err_del_component; | ||
2108 | } | 2382 | } |
2383 | |||
2384 | out_get_ddc_adpt: | ||
2109 | hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node); | 2385 | hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node); |
2110 | if (!hdata->ddc_adpt) { | 2386 | if (!hdata->ddc_adpt) { |
2111 | DRM_ERROR("Failed to get ddc i2c adapter by node\n"); | 2387 | DRM_ERROR("Failed to get ddc i2c adapter by node\n"); |
2112 | return -ENODEV; | 2388 | return -EPROBE_DEFER; |
2113 | } | 2389 | } |
2114 | 2390 | ||
2115 | /* Not support APB PHY yet. */ | 2391 | phy_node = hdmi_legacy_phy_dt_binding(dev); |
2116 | if (drv_data->is_apb_phy) | 2392 | if (phy_node) |
2117 | return -EPERM; | 2393 | goto out_get_phy_port; |
2118 | 2394 | ||
2119 | /* hdmiphy i2c driver */ | 2395 | /* hdmiphy i2c driver */ |
2120 | phy_node = of_parse_phandle(dev->of_node, "phy", 0); | 2396 | phy_node = of_parse_phandle(dev->of_node, "phy", 0); |
@@ -2123,11 +2399,22 @@ static int hdmi_probe(struct platform_device *pdev) | |||
2123 | ret = -ENODEV; | 2399 | ret = -ENODEV; |
2124 | goto err_ddc; | 2400 | goto err_ddc; |
2125 | } | 2401 | } |
2126 | hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node); | 2402 | |
2127 | if (!hdata->hdmiphy_port) { | 2403 | out_get_phy_port: |
2128 | DRM_ERROR("Failed to get hdmi phy i2c client from node\n"); | 2404 | if (drv_data->is_apb_phy) { |
2129 | ret = -ENODEV; | 2405 | hdata->regs_hdmiphy = of_iomap(phy_node, 0); |
2130 | goto err_ddc; | 2406 | if (!hdata->regs_hdmiphy) { |
2407 | DRM_ERROR("failed to ioremap hdmi phy\n"); | ||
2408 | ret = -ENOMEM; | ||
2409 | goto err_ddc; | ||
2410 | } | ||
2411 | } else { | ||
2412 | hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node); | ||
2413 | if (!hdata->hdmiphy_port) { | ||
2414 | DRM_ERROR("Failed to get hdmi phy i2c client\n"); | ||
2415 | ret = -EPROBE_DEFER; | ||
2416 | goto err_ddc; | ||
2417 | } | ||
2131 | } | 2418 | } |
2132 | 2419 | ||
2133 | hdata->irq = gpio_to_irq(hdata->hpd_gpio); | 2420 | hdata->irq = gpio_to_irq(hdata->hpd_gpio); |
@@ -2139,6 +2426,8 @@ static int hdmi_probe(struct platform_device *pdev) | |||
2139 | 2426 | ||
2140 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | 2427 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); |
2141 | 2428 | ||
2429 | INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); | ||
2430 | |||
2142 | ret = devm_request_threaded_irq(dev, hdata->irq, NULL, | 2431 | ret = devm_request_threaded_irq(dev, hdata->irq, NULL, |
2143 | hdmi_irq_thread, IRQF_TRIGGER_RISING | | 2432 | hdmi_irq_thread, IRQF_TRIGGER_RISING | |
2144 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 2433 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
@@ -2148,30 +2437,51 @@ static int hdmi_probe(struct platform_device *pdev) | |||
2148 | goto err_hdmiphy; | 2437 | goto err_hdmiphy; |
2149 | } | 2438 | } |
2150 | 2439 | ||
2151 | pm_runtime_enable(dev); | 2440 | hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, |
2441 | "samsung,syscon-phandle"); | ||
2442 | if (IS_ERR(hdata->pmureg)) { | ||
2443 | DRM_ERROR("syscon regmap lookup failed.\n"); | ||
2444 | ret = -EPROBE_DEFER; | ||
2445 | goto err_hdmiphy; | ||
2446 | } | ||
2152 | 2447 | ||
2448 | pm_runtime_enable(dev); | ||
2153 | hdmi_display.ctx = hdata; | 2449 | hdmi_display.ctx = hdata; |
2154 | exynos_drm_display_register(&hdmi_display); | ||
2155 | 2450 | ||
2156 | return 0; | 2451 | ret = component_add(&pdev->dev, &hdmi_component_ops); |
2452 | if (ret) | ||
2453 | goto err_disable_pm_runtime; | ||
2454 | |||
2455 | return ret; | ||
2456 | |||
2457 | err_disable_pm_runtime: | ||
2458 | pm_runtime_disable(dev); | ||
2157 | 2459 | ||
2158 | err_hdmiphy: | 2460 | err_hdmiphy: |
2159 | put_device(&hdata->hdmiphy_port->dev); | 2461 | if (hdata->hdmiphy_port) |
2462 | put_device(&hdata->hdmiphy_port->dev); | ||
2160 | err_ddc: | 2463 | err_ddc: |
2161 | put_device(&hdata->ddc_adpt->dev); | 2464 | put_device(&hdata->ddc_adpt->dev); |
2465 | |||
2466 | err_del_component: | ||
2467 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
2468 | |||
2162 | return ret; | 2469 | return ret; |
2163 | } | 2470 | } |
2164 | 2471 | ||
2165 | static int hdmi_remove(struct platform_device *pdev) | 2472 | static int hdmi_remove(struct platform_device *pdev) |
2166 | { | 2473 | { |
2167 | struct device *dev = &pdev->dev; | 2474 | struct hdmi_context *hdata = hdmi_display.ctx; |
2168 | struct exynos_drm_display *display = get_hdmi_display(dev); | 2475 | |
2169 | struct hdmi_context *hdata = display->ctx; | 2476 | cancel_delayed_work_sync(&hdata->hotplug_work); |
2170 | 2477 | ||
2171 | put_device(&hdata->hdmiphy_port->dev); | 2478 | put_device(&hdata->hdmiphy_port->dev); |
2172 | put_device(&hdata->ddc_adpt->dev); | 2479 | put_device(&hdata->ddc_adpt->dev); |
2480 | |||
2173 | pm_runtime_disable(&pdev->dev); | 2481 | pm_runtime_disable(&pdev->dev); |
2482 | component_del(&pdev->dev, &hdmi_component_ops); | ||
2174 | 2483 | ||
2484 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); | ||
2175 | return 0; | 2485 | return 0; |
2176 | } | 2486 | } |
2177 | 2487 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h deleted file mode 100644 index 0ddf3957de15..000000000000 --- a/drivers/gpu/drm/exynos/exynos_hdmi.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * Authors: | ||
5 | * Inki Dae <inki.dae@samsung.com> | ||
6 | * Seung-Woo Kim <sw0312.kim@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #ifndef _EXYNOS_HDMI_H_ | ||
15 | #define _EXYNOS_HDMI_H_ | ||
16 | |||
17 | void hdmi_attach_ddc_client(struct i2c_client *ddc); | ||
18 | void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy); | ||
19 | |||
20 | extern struct i2c_driver hdmiphy_driver; | ||
21 | extern struct i2c_driver ddc_driver; | ||
22 | |||
23 | #endif | ||
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c deleted file mode 100644 index 59abb1494ceb..000000000000 --- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c +++ /dev/null | |||
@@ -1,65 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Samsung Electronics Co.Ltd | ||
3 | * Authors: | ||
4 | * Seung-Woo Kim <sw0312.kim@samsung.com> | ||
5 | * Inki Dae <inki.dae@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 | |||
14 | #include <drm/drmP.h> | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include "exynos_drm_drv.h" | ||
21 | #include "exynos_hdmi.h" | ||
22 | |||
23 | |||
24 | static int hdmiphy_probe(struct i2c_client *client, | ||
25 | const struct i2c_device_id *id) | ||
26 | { | ||
27 | hdmi_attach_hdmiphy_client(client); | ||
28 | |||
29 | dev_info(&client->adapter->dev, "attached s5p_hdmiphy " | ||
30 | "into i2c adapter successfully\n"); | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static int hdmiphy_remove(struct i2c_client *client) | ||
36 | { | ||
37 | dev_info(&client->adapter->dev, "detached s5p_hdmiphy " | ||
38 | "from i2c adapter successfully\n"); | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static struct of_device_id hdmiphy_match_types[] = { | ||
44 | { | ||
45 | .compatible = "samsung,exynos5-hdmiphy", | ||
46 | }, { | ||
47 | .compatible = "samsung,exynos4210-hdmiphy", | ||
48 | }, { | ||
49 | .compatible = "samsung,exynos4212-hdmiphy", | ||
50 | }, { | ||
51 | /* end node */ | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | struct i2c_driver hdmiphy_driver = { | ||
56 | .driver = { | ||
57 | .name = "exynos-hdmiphy", | ||
58 | .owner = THIS_MODULE, | ||
59 | .of_match_table = hdmiphy_match_types, | ||
60 | }, | ||
61 | .probe = hdmiphy_probe, | ||
62 | .remove = hdmiphy_remove, | ||
63 | .command = NULL, | ||
64 | }; | ||
65 | EXPORT_SYMBOL(hdmiphy_driver); | ||
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index ce288818d2c0..4c5aed7e54c8 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
32 | #include <linux/regulator/consumer.h> | 32 | #include <linux/regulator/consumer.h> |
33 | #include <linux/of.h> | 33 | #include <linux/of.h> |
34 | #include <linux/component.h> | ||
34 | 35 | ||
35 | #include <drm/exynos_drm.h> | 36 | #include <drm/exynos_drm.h> |
36 | 37 | ||
@@ -830,13 +831,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx) | |||
830 | } | 831 | } |
831 | 832 | ||
832 | static int mixer_initialize(struct exynos_drm_manager *mgr, | 833 | static int mixer_initialize(struct exynos_drm_manager *mgr, |
833 | struct drm_device *drm_dev, int pipe) | 834 | struct drm_device *drm_dev) |
834 | { | 835 | { |
835 | int ret; | 836 | int ret; |
836 | struct mixer_context *mixer_ctx = mgr->ctx; | 837 | struct mixer_context *mixer_ctx = mgr->ctx; |
838 | struct exynos_drm_private *priv; | ||
839 | priv = drm_dev->dev_private; | ||
837 | 840 | ||
838 | mixer_ctx->drm_dev = drm_dev; | 841 | mgr->drm_dev = mixer_ctx->drm_dev = drm_dev; |
839 | mixer_ctx->pipe = pipe; | 842 | mgr->pipe = mixer_ctx->pipe = priv->pipe++; |
840 | 843 | ||
841 | /* acquire resources: regs, irqs, clocks */ | 844 | /* acquire resources: regs, irqs, clocks */ |
842 | ret = mixer_resources_init(mixer_ctx); | 845 | ret = mixer_resources_init(mixer_ctx); |
@@ -1142,8 +1145,6 @@ int mixer_check_mode(struct drm_display_mode *mode) | |||
1142 | } | 1145 | } |
1143 | 1146 | ||
1144 | static struct exynos_drm_manager_ops mixer_manager_ops = { | 1147 | static struct exynos_drm_manager_ops mixer_manager_ops = { |
1145 | .initialize = mixer_initialize, | ||
1146 | .remove = mixer_mgr_remove, | ||
1147 | .dpms = mixer_dpms, | 1148 | .dpms = mixer_dpms, |
1148 | .enable_vblank = mixer_enable_vblank, | 1149 | .enable_vblank = mixer_enable_vblank, |
1149 | .disable_vblank = mixer_disable_vblank, | 1150 | .disable_vblank = mixer_disable_vblank, |
@@ -1200,11 +1201,13 @@ static struct of_device_id mixer_match_types[] = { | |||
1200 | } | 1201 | } |
1201 | }; | 1202 | }; |
1202 | 1203 | ||
1203 | static int mixer_probe(struct platform_device *pdev) | 1204 | static int mixer_bind(struct device *dev, struct device *manager, void *data) |
1204 | { | 1205 | { |
1205 | struct device *dev = &pdev->dev; | 1206 | struct platform_device *pdev = to_platform_device(dev); |
1207 | struct drm_device *drm_dev = data; | ||
1206 | struct mixer_context *ctx; | 1208 | struct mixer_context *ctx; |
1207 | struct mixer_drv_data *drv; | 1209 | struct mixer_drv_data *drv; |
1210 | int ret; | ||
1208 | 1211 | ||
1209 | dev_info(dev, "probe start\n"); | 1212 | dev_info(dev, "probe start\n"); |
1210 | 1213 | ||
@@ -1233,19 +1236,61 @@ static int mixer_probe(struct platform_device *pdev) | |||
1233 | atomic_set(&ctx->wait_vsync_event, 0); | 1236 | atomic_set(&ctx->wait_vsync_event, 0); |
1234 | 1237 | ||
1235 | mixer_manager.ctx = ctx; | 1238 | mixer_manager.ctx = ctx; |
1239 | ret = mixer_initialize(&mixer_manager, drm_dev); | ||
1240 | if (ret) | ||
1241 | return ret; | ||
1242 | |||
1236 | platform_set_drvdata(pdev, &mixer_manager); | 1243 | platform_set_drvdata(pdev, &mixer_manager); |
1237 | exynos_drm_manager_register(&mixer_manager); | 1244 | ret = exynos_drm_crtc_create(&mixer_manager); |
1245 | if (ret) { | ||
1246 | mixer_mgr_remove(&mixer_manager); | ||
1247 | return ret; | ||
1248 | } | ||
1238 | 1249 | ||
1239 | pm_runtime_enable(dev); | 1250 | pm_runtime_enable(dev); |
1240 | 1251 | ||
1241 | return 0; | 1252 | return 0; |
1242 | } | 1253 | } |
1243 | 1254 | ||
1244 | static int mixer_remove(struct platform_device *pdev) | 1255 | static void mixer_unbind(struct device *dev, struct device *master, void *data) |
1256 | { | ||
1257 | struct exynos_drm_manager *mgr = dev_get_drvdata(dev); | ||
1258 | struct drm_crtc *crtc = mgr->crtc; | ||
1259 | |||
1260 | dev_info(dev, "remove successful\n"); | ||
1261 | |||
1262 | mixer_mgr_remove(mgr); | ||
1263 | |||
1264 | pm_runtime_disable(dev); | ||
1265 | |||
1266 | crtc->funcs->destroy(crtc); | ||
1267 | } | ||
1268 | |||
1269 | static const struct component_ops mixer_component_ops = { | ||
1270 | .bind = mixer_bind, | ||
1271 | .unbind = mixer_unbind, | ||
1272 | }; | ||
1273 | |||
1274 | static int mixer_probe(struct platform_device *pdev) | ||
1245 | { | 1275 | { |
1246 | dev_info(&pdev->dev, "remove successful\n"); | 1276 | int ret; |
1247 | 1277 | ||
1248 | pm_runtime_disable(&pdev->dev); | 1278 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, |
1279 | mixer_manager.type); | ||
1280 | if (ret) | ||
1281 | return ret; | ||
1282 | |||
1283 | ret = component_add(&pdev->dev, &mixer_component_ops); | ||
1284 | if (ret) | ||
1285 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); | ||
1286 | |||
1287 | return ret; | ||
1288 | } | ||
1289 | |||
1290 | static int mixer_remove(struct platform_device *pdev) | ||
1291 | { | ||
1292 | component_del(&pdev->dev, &mixer_component_ops); | ||
1293 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); | ||
1249 | 1294 | ||
1250 | return 0; | 1295 | return 0; |
1251 | } | 1296 | } |
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h index ef1b3eb3ba6e..3f35ac6d8a47 100644 --- a/drivers/gpu/drm/exynos/regs-hdmi.h +++ b/drivers/gpu/drm/exynos/regs-hdmi.h | |||
@@ -578,4 +578,20 @@ | |||
578 | #define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074) | 578 | #define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074) |
579 | #define HDMI_TG_3D HDMI_TG_BASE(0x00F0) | 579 | #define HDMI_TG_3D HDMI_TG_BASE(0x00F0) |
580 | 580 | ||
581 | /* HDMI PHY Registers Offsets*/ | ||
582 | #define HDMIPHY_POWER (0x74 >> 2) | ||
583 | #define HDMIPHY_MODE_SET_DONE (0x7c >> 2) | ||
584 | |||
585 | /* HDMI PHY Values */ | ||
586 | #define HDMI_PHY_POWER_ON 0x80 | ||
587 | #define HDMI_PHY_POWER_OFF 0xff | ||
588 | |||
589 | /* HDMI PHY Values */ | ||
590 | #define HDMI_PHY_DISABLE_MODE_SET 0x80 | ||
591 | #define HDMI_PHY_ENABLE_MODE_SET 0x00 | ||
592 | |||
593 | /* PMU Registers for PHY */ | ||
594 | #define PMU_HDMI_PHY_CONTROL 0x700 | ||
595 | #define PMU_HDMI_PHY_ENABLE_BIT BIT(0) | ||
596 | |||
581 | #endif /* SAMSUNG_REGS_HDMI_H */ | 597 | #endif /* SAMSUNG_REGS_HDMI_H */ |
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index efcde2c38cc1..488b41635dec 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h | |||
@@ -310,6 +310,8 @@ | |||
310 | # define DP_TEST_NAK (1 << 1) | 310 | # define DP_TEST_NAK (1 << 1) |
311 | # define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) | 311 | # define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) |
312 | 312 | ||
313 | #define DP_TEST_EDID_CHECKSUM 0x261 | ||
314 | |||
313 | #define DP_TEST_SINK 0x270 | 315 | #define DP_TEST_SINK 0x270 |
314 | #define DP_TEST_SINK_START (1 << 0) | 316 | #define DP_TEST_SINK_START (1 << 0) |
315 | 317 | ||