diff options
author | Dave Airlie <airlied@redhat.com> | 2014-08-04 01:07:21 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-08-04 01:07:21 -0400 |
commit | 1fae6dfeb63cddea9b9cd19f236c40f73c72f61d (patch) | |
tree | cfbd52dcaa4d239c24ebdc7ca4ee14ae464da2a3 | |
parent | 08d645c181e9b9482c249e82a061c279a986db15 (diff) | |
parent | ef7ce055a9e00f6376416466b996515a27b7cb31 (diff) |
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This pull request includes i80 interface support, module auto-loading
ipp consolidation, and trivail fixups and cleanups.
Summary:
- Add i80 interface support. For this, we added some features to
Exynos drm framework, which don't affect any other SoC and common
framework because they are specific to Exynos drm.
- Add module auto-loading support. For this, sub drivers of Exynos drm
exports their of match tables to userspace. This allows modules to be
loaded automatically based on devicetree information
- Consolidate ipp driver. This patch just just includes cleanups and
a littl bit refactoring codes.
If there is any problem, please kindly let me know.
* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (38 commits)
drm/exynos: g2d: let exynos_g2d_get_ver_ioctl fail
drm/exynos: g2d: make ioctls more robust
drm/exynos: hdmi: add null check for hdmiphy_port
drm/exynos: control blending of mixer graphic layer 0
drm/exynos: Add MODULE_DEVICE_TABLE entries for various components
Subject: Revert "drm/exynos: remove MODULE_DEVICE_TABLE definitions"
Subject: Revert "drm/exynos: fix module build error"
drm/exynos/ipp: simplify ipp_find_driver
drm/exynos/ipp: simplify ipp_create_id
drm/exynos/ipp: remove redundant messages
drm/exynos/ipp: simplify ipp_find_obj
drm/exynos/ipp: remove useless registration checks
drm/exynos/ipp: simplify memory check function
drm/exynos/ipp: remove incorrect checks of list_first_entry result
drm/exynos/ipp: remove temporary variable
drm/exynos/ipp: correct address type
drm/exynos/ipp: remove struct exynos_drm_ipp_private
drm/exynos/ipp: remove unused field from exynos_drm_ipp_private
drm/exynos/ipp: remove type casting
drm/exynos: g2d: add exynos4212 as a compatible device.
...
23 files changed, 739 insertions, 300 deletions
diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt index 33b5730d07ba..31036c667d54 100644 --- a/Documentation/devicetree/bindings/video/exynos_dsim.txt +++ b/Documentation/devicetree/bindings/video/exynos_dsim.txt | |||
@@ -1,7 +1,9 @@ | |||
1 | Exynos MIPI DSI Master | 1 | Exynos MIPI DSI Master |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: "samsung,exynos4210-mipi-dsi" | 4 | - compatible: value should be one of the following |
5 | "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */ | ||
6 | "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */ | ||
5 | - reg: physical base address and length of the registers set for the device | 7 | - reg: physical base address and length of the registers set for the device |
6 | - interrupts: should contain DSI interrupt | 8 | - interrupts: should contain DSI interrupt |
7 | - clocks: list of clock specifiers, must contain an entry for each required | 9 | - clocks: list of clock specifiers, must contain an entry for each required |
diff --git a/Documentation/devicetree/bindings/video/exynos_mixer.txt b/Documentation/devicetree/bindings/video/exynos_mixer.txt index 7bfde9c9d658..08b394b1edbf 100644 --- a/Documentation/devicetree/bindings/video/exynos_mixer.txt +++ b/Documentation/devicetree/bindings/video/exynos_mixer.txt | |||
@@ -4,8 +4,9 @@ Required properties: | |||
4 | - compatible: value should be one of the following: | 4 | - compatible: value should be one of the following: |
5 | 1) "samsung,exynos5-mixer" <DEPRECATED> | 5 | 1) "samsung,exynos5-mixer" <DEPRECATED> |
6 | 2) "samsung,exynos4210-mixer" | 6 | 2) "samsung,exynos4210-mixer" |
7 | 3) "samsung,exynos5250-mixer" | 7 | 3) "samsung,exynos4212-mixer" |
8 | 4) "samsung,exynos5420-mixer" | 8 | 4) "samsung,exynos5250-mixer" |
9 | 5) "samsung,exynos5420-mixer" | ||
9 | 10 | ||
10 | - reg: physical base address of the mixer and length of memory mapped | 11 | - reg: physical base address of the mixer and length of memory mapped |
11 | region. | 12 | region. |
diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt index 2dad41b689af..8428fcff8037 100644 --- a/Documentation/devicetree/bindings/video/samsung-fimd.txt +++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt | |||
@@ -44,6 +44,34 @@ Optional Properties: | |||
44 | - display-timings: timing settings for FIMD, as described in document [1]. | 44 | - display-timings: timing settings for FIMD, as described in document [1]. |
45 | Can be used in case timings cannot be provided otherwise | 45 | Can be used in case timings cannot be provided otherwise |
46 | or to override timings provided by the panel. | 46 | or to override timings provided by the panel. |
47 | - samsung,sysreg: handle to syscon used to control the system registers | ||
48 | - i80-if-timings: timing configuration for lcd i80 interface support. | ||
49 | - cs-setup: clock cycles for the active period of address signal is enabled | ||
50 | until chip select is enabled. | ||
51 | If not specified, the default value(0) will be used. | ||
52 | - wr-setup: clock cycles for the active period of CS signal is enabled until | ||
53 | write signal is enabled. | ||
54 | If not specified, the default value(0) will be used. | ||
55 | - wr-active: clock cycles for the active period of CS is enabled. | ||
56 | If not specified, the default value(1) will be used. | ||
57 | - wr-hold: clock cycles for the active period of CS is disabled until write | ||
58 | signal is disabled. | ||
59 | If not specified, the default value(0) will be used. | ||
60 | |||
61 | The parameters are defined as: | ||
62 | |||
63 | VCLK(internal) __|??????|_____|??????|_____|??????|_____|??????|_____|?? | ||
64 | : : : : : | ||
65 | Address Output --:<XXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XX | ||
66 | | cs-setup+1 | : : : | ||
67 | |<---------->| : : : | ||
68 | Chip Select ???????????????|____________:____________:____________|?? | ||
69 | | wr-setup+1 | | wr-hold+1 | | ||
70 | |<---------->| |<---------->| | ||
71 | Write Enable ????????????????????????????|____________|??????????????? | ||
72 | | wr-active+1| | ||
73 | |<---------->| | ||
74 | Video Data ----------------------------<XXXXXXXXXXXXXXXXXXXXXXXXX>-- | ||
47 | 75 | ||
48 | The device node can contain 'port' child nodes according to the bindings defined | 76 | The device node can contain 'port' child nodes according to the bindings defined |
49 | in [2]. The following are properties specific to those nodes: | 77 | in [2]. The following are properties specific to those nodes: |
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index fbaf426d2daa..379388121268 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi | |||
@@ -608,6 +608,7 @@ | |||
608 | clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>; | 608 | clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>; |
609 | clock-names = "sclk_fimd", "fimd"; | 609 | clock-names = "sclk_fimd", "fimd"; |
610 | samsung,power-domain = <&pd_lcd0>; | 610 | samsung,power-domain = <&pd_lcd0>; |
611 | samsung,sysreg = <&sys_reg>; | ||
611 | status = "disabled"; | 612 | status = "disabled"; |
612 | }; | 613 | }; |
613 | }; | 614 | }; |
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi index 79d0608d6dcc..fdead12952a1 100644 --- a/arch/arm/boot/dts/exynos5.dtsi +++ b/arch/arm/boot/dts/exynos5.dtsi | |||
@@ -87,6 +87,7 @@ | |||
87 | reg = <0x14400000 0x40000>; | 87 | reg = <0x14400000 0x40000>; |
88 | interrupt-names = "fifo", "vsync", "lcd_sys"; | 88 | interrupt-names = "fifo", "vsync", "lcd_sys"; |
89 | interrupts = <18 4>, <18 5>, <18 6>; | 89 | interrupts = <18 4>, <18 5>, <18 6>; |
90 | samsung,sysreg = <&sysreg_system_controller>; | ||
90 | status = "disabled"; | 91 | status = "disabled"; |
91 | }; | 92 | }; |
92 | 93 | ||
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index e38532271ef9..3a7862bc5f3e 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi | |||
@@ -517,6 +517,26 @@ | |||
517 | phy-names = "dp"; | 517 | phy-names = "dp"; |
518 | }; | 518 | }; |
519 | 519 | ||
520 | mipi_phy: video-phy@10040714 { | ||
521 | compatible = "samsung,s5pv210-mipi-video-phy"; | ||
522 | reg = <0x10040714 12>; | ||
523 | #phy-cells = <1>; | ||
524 | }; | ||
525 | |||
526 | dsi@14500000 { | ||
527 | compatible = "samsung,exynos5410-mipi-dsi"; | ||
528 | reg = <0x14500000 0x10000>; | ||
529 | interrupts = <0 82 0>; | ||
530 | samsung,power-domain = <&disp_pd>; | ||
531 | phys = <&mipi_phy 1>; | ||
532 | phy-names = "dsim"; | ||
533 | clocks = <&clock CLK_DSIM1>, <&clock CLK_SCLK_MIPI1>; | ||
534 | clock-names = "bus_clk", "pll_clk"; | ||
535 | #address-cells = <1>; | ||
536 | #size-cells = <0>; | ||
537 | status = "disabled"; | ||
538 | }; | ||
539 | |||
520 | fimd: fimd@14400000 { | 540 | fimd: fimd@14400000 { |
521 | samsung,power-domain = <&disp_pd>; | 541 | samsung,power-domain = <&disp_pd>; |
522 | clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>; | 542 | clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>; |
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 178d2a9672a8..9ba1aaeb8070 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
@@ -28,6 +28,7 @@ config DRM_EXYNOS_FIMD | |||
28 | bool "Exynos DRM FIMD" | 28 | bool "Exynos DRM FIMD" |
29 | depends on DRM_EXYNOS && !FB_S3C | 29 | depends on DRM_EXYNOS && !FB_S3C |
30 | select FB_MODE_HELPERS | 30 | select FB_MODE_HELPERS |
31 | select MFD_SYSCON | ||
31 | help | 32 | help |
32 | Choose this option if you want to use Exynos FIMD for DRM. | 33 | Choose this option if you want to use Exynos FIMD for DRM. |
33 | 34 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 86dc69d9eabb..31c3de98b885 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c | |||
@@ -1376,6 +1376,7 @@ static const struct of_device_id exynos_dp_match[] = { | |||
1376 | { .compatible = "samsung,exynos5-dp" }, | 1376 | { .compatible = "samsung,exynos5-dp" }, |
1377 | {}, | 1377 | {}, |
1378 | }; | 1378 | }; |
1379 | MODULE_DEVICE_TABLE(of, exynos_dp_match); | ||
1379 | 1380 | ||
1380 | struct platform_driver dp_driver = { | 1381 | struct platform_driver dp_driver = { |
1381 | .probe = exynos_dp_probe, | 1382 | .probe = exynos_dp_probe, |
@@ -1390,4 +1391,4 @@ struct platform_driver dp_driver = { | |||
1390 | 1391 | ||
1391 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | 1392 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); |
1392 | MODULE_DESCRIPTION("Samsung SoC DP Driver"); | 1393 | MODULE_DESCRIPTION("Samsung SoC DP Driver"); |
1393 | MODULE_LICENSE("GPL"); | 1394 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 95c9435d0266..b68e58f78cd1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c | |||
@@ -69,8 +69,10 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
69 | 69 | ||
70 | if (mode > DRM_MODE_DPMS_ON) { | 70 | if (mode > DRM_MODE_DPMS_ON) { |
71 | /* wait for the completion of page flip. */ | 71 | /* wait for the completion of page flip. */ |
72 | wait_event(exynos_crtc->pending_flip_queue, | 72 | if (!wait_event_timeout(exynos_crtc->pending_flip_queue, |
73 | atomic_read(&exynos_crtc->pending_flip) == 0); | 73 | !atomic_read(&exynos_crtc->pending_flip), |
74 | HZ/20)) | ||
75 | atomic_set(&exynos_crtc->pending_flip, 0); | ||
74 | drm_vblank_off(crtc->dev, exynos_crtc->pipe); | 76 | drm_vblank_off(crtc->dev, exynos_crtc->pipe); |
75 | } | 77 | } |
76 | 78 | ||
@@ -259,6 +261,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, | |||
259 | spin_lock_irq(&dev->event_lock); | 261 | spin_lock_irq(&dev->event_lock); |
260 | drm_vblank_put(dev, exynos_crtc->pipe); | 262 | drm_vblank_put(dev, exynos_crtc->pipe); |
261 | list_del(&event->base.link); | 263 | list_del(&event->base.link); |
264 | atomic_set(&exynos_crtc->pending_flip, 0); | ||
262 | spin_unlock_irq(&dev->event_lock); | 265 | spin_unlock_irq(&dev->event_lock); |
263 | 266 | ||
264 | goto out; | 267 | goto out; |
@@ -508,3 +511,11 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | |||
508 | 511 | ||
509 | return -EPERM; | 512 | return -EPERM; |
510 | } | 513 | } |
514 | |||
515 | void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) | ||
516 | { | ||
517 | struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; | ||
518 | |||
519 | if (manager->ops->te_handler) | ||
520 | manager->ops->te_handler(manager); | ||
521 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 9f74b10a8a01..690dcddab725 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h | |||
@@ -36,4 +36,11 @@ void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos); | |||
36 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | 36 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, |
37 | unsigned int out_type); | 37 | unsigned int out_type); |
38 | 38 | ||
39 | /* | ||
40 | * This function calls the crtc device(manager)'s te_handler() callback | ||
41 | * to trigger to transfer video image at the tearing effect synchronization | ||
42 | * signal. | ||
43 | */ | ||
44 | void exynos_drm_crtc_te_handler(struct drm_crtc *crtc); | ||
45 | |||
39 | #endif | 46 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index d82e3cb8a70d..0d74e9b99c4e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -358,7 +358,7 @@ static int exynos_drm_sys_suspend(struct device *dev) | |||
358 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 358 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
359 | pm_message_t message; | 359 | pm_message_t message; |
360 | 360 | ||
361 | if (pm_runtime_suspended(dev)) | 361 | if (pm_runtime_suspended(dev) || !drm_dev) |
362 | return 0; | 362 | return 0; |
363 | 363 | ||
364 | message.event = PM_EVENT_SUSPEND; | 364 | message.event = PM_EVENT_SUSPEND; |
@@ -369,7 +369,7 @@ static int exynos_drm_sys_resume(struct device *dev) | |||
369 | { | 369 | { |
370 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 370 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
371 | 371 | ||
372 | if (pm_runtime_suspended(dev)) | 372 | if (pm_runtime_suspended(dev) || !drm_dev) |
373 | return 0; | 373 | return 0; |
374 | 374 | ||
375 | return exynos_drm_resume(drm_dev); | 375 | return exynos_drm_resume(drm_dev); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 02f3b3dcb9f8..69a6fa397d75 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -186,6 +186,8 @@ struct exynos_drm_display { | |||
186 | * @win_commit: apply hardware specific overlay data to registers. | 186 | * @win_commit: apply hardware specific overlay data to registers. |
187 | * @win_enable: enable hardware specific overlay. | 187 | * @win_enable: enable hardware specific overlay. |
188 | * @win_disable: disable hardware specific overlay. | 188 | * @win_disable: disable hardware specific overlay. |
189 | * @te_handler: trigger to transfer video image at the tearing effect | ||
190 | * synchronization signal if there is a page flip request. | ||
189 | */ | 191 | */ |
190 | struct exynos_drm_manager; | 192 | struct exynos_drm_manager; |
191 | struct exynos_drm_manager_ops { | 193 | struct exynos_drm_manager_ops { |
@@ -204,6 +206,7 @@ struct exynos_drm_manager_ops { | |||
204 | void (*win_commit)(struct exynos_drm_manager *mgr, int zpos); | 206 | void (*win_commit)(struct exynos_drm_manager *mgr, int zpos); |
205 | void (*win_enable)(struct exynos_drm_manager *mgr, int zpos); | 207 | void (*win_enable)(struct exynos_drm_manager *mgr, int zpos); |
206 | void (*win_disable)(struct exynos_drm_manager *mgr, int zpos); | 208 | void (*win_disable)(struct exynos_drm_manager *mgr, int zpos); |
209 | void (*te_handler)(struct exynos_drm_manager *mgr); | ||
207 | }; | 210 | }; |
208 | 211 | ||
209 | /* | 212 | /* |
@@ -234,14 +237,9 @@ struct exynos_drm_g2d_private { | |||
234 | struct list_head userptr_list; | 237 | struct list_head userptr_list; |
235 | }; | 238 | }; |
236 | 239 | ||
237 | struct exynos_drm_ipp_private { | ||
238 | struct device *dev; | ||
239 | struct list_head event_list; | ||
240 | }; | ||
241 | |||
242 | struct drm_exynos_file_private { | 240 | struct drm_exynos_file_private { |
243 | struct exynos_drm_g2d_private *g2d_priv; | 241 | struct exynos_drm_g2d_private *g2d_priv; |
244 | struct exynos_drm_ipp_private *ipp_priv; | 242 | struct device *ipp_dev; |
245 | struct file *anon_filp; | 243 | struct file *anon_filp; |
246 | }; | 244 | }; |
247 | 245 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 2df3592166de..86aebd83a71b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c | |||
@@ -16,7 +16,10 @@ | |||
16 | #include <drm/drm_panel.h> | 16 | #include <drm/drm_panel.h> |
17 | 17 | ||
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/gpio/consumer.h> | ||
19 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/of_device.h> | ||
22 | #include <linux/of_gpio.h> | ||
20 | #include <linux/phy/phy.h> | 23 | #include <linux/phy/phy.h> |
21 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
22 | #include <linux/component.h> | 25 | #include <linux/component.h> |
@@ -24,6 +27,7 @@ | |||
24 | #include <video/mipi_display.h> | 27 | #include <video/mipi_display.h> |
25 | #include <video/videomode.h> | 28 | #include <video/videomode.h> |
26 | 29 | ||
30 | #include "exynos_drm_crtc.h" | ||
27 | #include "exynos_drm_drv.h" | 31 | #include "exynos_drm_drv.h" |
28 | 32 | ||
29 | /* returns true iff both arguments logically differs */ | 33 | /* returns true iff both arguments logically differs */ |
@@ -54,9 +58,12 @@ | |||
54 | 58 | ||
55 | /* FIFO memory AC characteristic register */ | 59 | /* FIFO memory AC characteristic register */ |
56 | #define DSIM_PLLCTRL_REG 0x4c /* PLL control register */ | 60 | #define DSIM_PLLCTRL_REG 0x4c /* PLL control register */ |
57 | #define DSIM_PLLTMR_REG 0x50 /* PLL timer register */ | ||
58 | #define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */ | 61 | #define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */ |
59 | #define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */ | 62 | #define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */ |
63 | #define DSIM_PHYCTRL_REG 0x5c | ||
64 | #define DSIM_PHYTIMING_REG 0x64 | ||
65 | #define DSIM_PHYTIMING1_REG 0x68 | ||
66 | #define DSIM_PHYTIMING2_REG 0x6c | ||
60 | 67 | ||
61 | /* DSIM_STATUS */ | 68 | /* DSIM_STATUS */ |
62 | #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) | 69 | #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) |
@@ -200,6 +207,24 @@ | |||
200 | #define DSIM_PLL_M(x) ((x) << 4) | 207 | #define DSIM_PLL_M(x) ((x) << 4) |
201 | #define DSIM_PLL_S(x) ((x) << 1) | 208 | #define DSIM_PLL_S(x) ((x) << 1) |
202 | 209 | ||
210 | /* DSIM_PHYCTRL */ | ||
211 | #define DSIM_PHYCTRL_ULPS_EXIT(x) (((x) & 0x1ff) << 0) | ||
212 | |||
213 | /* DSIM_PHYTIMING */ | ||
214 | #define DSIM_PHYTIMING_LPX(x) ((x) << 8) | ||
215 | #define DSIM_PHYTIMING_HS_EXIT(x) ((x) << 0) | ||
216 | |||
217 | /* DSIM_PHYTIMING1 */ | ||
218 | #define DSIM_PHYTIMING1_CLK_PREPARE(x) ((x) << 24) | ||
219 | #define DSIM_PHYTIMING1_CLK_ZERO(x) ((x) << 16) | ||
220 | #define DSIM_PHYTIMING1_CLK_POST(x) ((x) << 8) | ||
221 | #define DSIM_PHYTIMING1_CLK_TRAIL(x) ((x) << 0) | ||
222 | |||
223 | /* DSIM_PHYTIMING2 */ | ||
224 | #define DSIM_PHYTIMING2_HS_PREPARE(x) ((x) << 16) | ||
225 | #define DSIM_PHYTIMING2_HS_ZERO(x) ((x) << 8) | ||
226 | #define DSIM_PHYTIMING2_HS_TRAIL(x) ((x) << 0) | ||
227 | |||
203 | #define DSI_MAX_BUS_WIDTH 4 | 228 | #define DSI_MAX_BUS_WIDTH 4 |
204 | #define DSI_NUM_VIRTUAL_CHANNELS 4 | 229 | #define DSI_NUM_VIRTUAL_CHANNELS 4 |
205 | #define DSI_TX_FIFO_SIZE 2048 | 230 | #define DSI_TX_FIFO_SIZE 2048 |
@@ -233,6 +258,12 @@ struct exynos_dsi_transfer { | |||
233 | #define DSIM_STATE_INITIALIZED BIT(1) | 258 | #define DSIM_STATE_INITIALIZED BIT(1) |
234 | #define DSIM_STATE_CMD_LPM BIT(2) | 259 | #define DSIM_STATE_CMD_LPM BIT(2) |
235 | 260 | ||
261 | struct exynos_dsi_driver_data { | ||
262 | unsigned int plltmr_reg; | ||
263 | |||
264 | unsigned int has_freqband:1; | ||
265 | }; | ||
266 | |||
236 | struct exynos_dsi { | 267 | struct exynos_dsi { |
237 | struct mipi_dsi_host dsi_host; | 268 | struct mipi_dsi_host dsi_host; |
238 | struct drm_connector connector; | 269 | struct drm_connector connector; |
@@ -247,6 +278,7 @@ struct exynos_dsi { | |||
247 | struct clk *bus_clk; | 278 | struct clk *bus_clk; |
248 | struct regulator_bulk_data supplies[2]; | 279 | struct regulator_bulk_data supplies[2]; |
249 | int irq; | 280 | int irq; |
281 | int te_gpio; | ||
250 | 282 | ||
251 | u32 pll_clk_rate; | 283 | u32 pll_clk_rate; |
252 | u32 burst_clk_rate; | 284 | u32 burst_clk_rate; |
@@ -262,11 +294,39 @@ struct exynos_dsi { | |||
262 | 294 | ||
263 | spinlock_t transfer_lock; /* protects transfer_list */ | 295 | spinlock_t transfer_lock; /* protects transfer_list */ |
264 | struct list_head transfer_list; | 296 | struct list_head transfer_list; |
297 | |||
298 | struct exynos_dsi_driver_data *driver_data; | ||
265 | }; | 299 | }; |
266 | 300 | ||
267 | #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) | 301 | #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) |
268 | #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) | 302 | #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) |
269 | 303 | ||
304 | static struct exynos_dsi_driver_data exynos4_dsi_driver_data = { | ||
305 | .plltmr_reg = 0x50, | ||
306 | .has_freqband = 1, | ||
307 | }; | ||
308 | |||
309 | static struct exynos_dsi_driver_data exynos5_dsi_driver_data = { | ||
310 | .plltmr_reg = 0x58, | ||
311 | }; | ||
312 | |||
313 | static struct of_device_id exynos_dsi_of_match[] = { | ||
314 | { .compatible = "samsung,exynos4210-mipi-dsi", | ||
315 | .data = &exynos4_dsi_driver_data }, | ||
316 | { .compatible = "samsung,exynos5410-mipi-dsi", | ||
317 | .data = &exynos5_dsi_driver_data }, | ||
318 | { } | ||
319 | }; | ||
320 | |||
321 | static inline struct exynos_dsi_driver_data *exynos_dsi_get_driver_data( | ||
322 | struct platform_device *pdev) | ||
323 | { | ||
324 | const struct of_device_id *of_id = | ||
325 | of_match_device(exynos_dsi_of_match, &pdev->dev); | ||
326 | |||
327 | return (struct exynos_dsi_driver_data *)of_id->data; | ||
328 | } | ||
329 | |||
270 | static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) | 330 | static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) |
271 | { | 331 | { |
272 | if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) | 332 | if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) |
@@ -340,14 +400,9 @@ static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, | |||
340 | static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, | 400 | static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, |
341 | unsigned long freq) | 401 | unsigned long freq) |
342 | { | 402 | { |
343 | static const unsigned long freq_bands[] = { | 403 | struct exynos_dsi_driver_data *driver_data = dsi->driver_data; |
344 | 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, | ||
345 | 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, | ||
346 | 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, | ||
347 | 770 * MHZ, 870 * MHZ, 950 * MHZ, | ||
348 | }; | ||
349 | unsigned long fin, fout; | 404 | unsigned long fin, fout; |
350 | int timeout, band; | 405 | int timeout; |
351 | u8 p, s; | 406 | u8 p, s; |
352 | u16 m; | 407 | u16 m; |
353 | u32 reg; | 408 | u32 reg; |
@@ -368,18 +423,30 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, | |||
368 | "failed to find PLL PMS for requested frequency\n"); | 423 | "failed to find PLL PMS for requested frequency\n"); |
369 | return -EFAULT; | 424 | return -EFAULT; |
370 | } | 425 | } |
426 | dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d)\n", fout, p, m, s); | ||
371 | 427 | ||
372 | for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) | 428 | writel(500, dsi->reg_base + driver_data->plltmr_reg); |
373 | if (fout < freq_bands[band]) | 429 | |
374 | break; | 430 | reg = DSIM_PLL_EN | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); |
431 | |||
432 | if (driver_data->has_freqband) { | ||
433 | static const unsigned long freq_bands[] = { | ||
434 | 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, | ||
435 | 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, | ||
436 | 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, | ||
437 | 770 * MHZ, 870 * MHZ, 950 * MHZ, | ||
438 | }; | ||
439 | int band; | ||
375 | 440 | ||
376 | dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d), band %d\n", fout, | 441 | for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) |
377 | p, m, s, band); | 442 | if (fout < freq_bands[band]) |
443 | break; | ||
378 | 444 | ||
379 | writel(500, dsi->reg_base + DSIM_PLLTMR_REG); | 445 | dev_dbg(dsi->dev, "band %d\n", band); |
446 | |||
447 | reg |= DSIM_FREQ_BAND(band); | ||
448 | } | ||
380 | 449 | ||
381 | reg = DSIM_FREQ_BAND(band) | DSIM_PLL_EN | ||
382 | | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); | ||
383 | writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); | 450 | writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); |
384 | 451 | ||
385 | timeout = 1000; | 452 | timeout = 1000; |
@@ -433,6 +500,59 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) | |||
433 | return 0; | 500 | return 0; |
434 | } | 501 | } |
435 | 502 | ||
503 | static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) | ||
504 | { | ||
505 | struct exynos_dsi_driver_data *driver_data = dsi->driver_data; | ||
506 | u32 reg; | ||
507 | |||
508 | if (driver_data->has_freqband) | ||
509 | return; | ||
510 | |||
511 | /* B D-PHY: D-PHY Master & Slave Analog Block control */ | ||
512 | reg = DSIM_PHYCTRL_ULPS_EXIT(0x0af); | ||
513 | writel(reg, dsi->reg_base + DSIM_PHYCTRL_REG); | ||
514 | |||
515 | /* | ||
516 | * T LPX: Transmitted length of any Low-Power state period | ||
517 | * T HS-EXIT: Time that the transmitter drives LP-11 following a HS | ||
518 | * burst | ||
519 | */ | ||
520 | reg = DSIM_PHYTIMING_LPX(0x06) | DSIM_PHYTIMING_HS_EXIT(0x0b); | ||
521 | writel(reg, dsi->reg_base + DSIM_PHYTIMING_REG); | ||
522 | |||
523 | /* | ||
524 | * T CLK-PREPARE: Time that the transmitter drives the Clock Lane LP-00 | ||
525 | * Line state immediately before the HS-0 Line state starting the | ||
526 | * HS transmission | ||
527 | * T CLK-ZERO: Time that the transmitter drives the HS-0 state prior to | ||
528 | * transmitting the Clock. | ||
529 | * T CLK_POST: Time that the transmitter continues to send HS clock | ||
530 | * after the last associated Data Lane has transitioned to LP Mode | ||
531 | * Interval is defined as the period from the end of T HS-TRAIL to | ||
532 | * the beginning of T CLK-TRAIL | ||
533 | * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after | ||
534 | * the last payload clock bit of a HS transmission burst | ||
535 | */ | ||
536 | reg = DSIM_PHYTIMING1_CLK_PREPARE(0x07) | | ||
537 | DSIM_PHYTIMING1_CLK_ZERO(0x27) | | ||
538 | DSIM_PHYTIMING1_CLK_POST(0x0d) | | ||
539 | DSIM_PHYTIMING1_CLK_TRAIL(0x08); | ||
540 | writel(reg, dsi->reg_base + DSIM_PHYTIMING1_REG); | ||
541 | |||
542 | /* | ||
543 | * T HS-PREPARE: Time that the transmitter drives the Data Lane LP-00 | ||
544 | * Line state immediately before the HS-0 Line state starting the | ||
545 | * HS transmission | ||
546 | * T HS-ZERO: Time that the transmitter drives the HS-0 state prior to | ||
547 | * transmitting the Sync sequence. | ||
548 | * T HS-TRAIL: Time that the transmitter drives the flipped differential | ||
549 | * state after last payload data bit of a HS transmission burst | ||
550 | */ | ||
551 | reg = DSIM_PHYTIMING2_HS_PREPARE(0x09) | DSIM_PHYTIMING2_HS_ZERO(0x0d) | | ||
552 | DSIM_PHYTIMING2_HS_TRAIL(0x0b); | ||
553 | writel(reg, dsi->reg_base + DSIM_PHYTIMING2_REG); | ||
554 | } | ||
555 | |||
436 | static void exynos_dsi_disable_clock(struct exynos_dsi *dsi) | 556 | static void exynos_dsi_disable_clock(struct exynos_dsi *dsi) |
437 | { | 557 | { |
438 | u32 reg; | 558 | u32 reg; |
@@ -468,13 +588,20 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) | |||
468 | /* DSI configuration */ | 588 | /* DSI configuration */ |
469 | reg = 0; | 589 | reg = 0; |
470 | 590 | ||
591 | /* | ||
592 | * The first bit of mode_flags specifies display configuration. | ||
593 | * If this bit is set[= MIPI_DSI_MODE_VIDEO], dsi will support video | ||
594 | * mode, otherwise it will support command mode. | ||
595 | */ | ||
471 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { | 596 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { |
472 | reg |= DSIM_VIDEO_MODE; | 597 | reg |= DSIM_VIDEO_MODE; |
473 | 598 | ||
599 | /* | ||
600 | * The user manual describes that following bits are ignored in | ||
601 | * command mode. | ||
602 | */ | ||
474 | if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) | 603 | if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) |
475 | reg |= DSIM_MFLUSH_VS; | 604 | reg |= DSIM_MFLUSH_VS; |
476 | if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) | ||
477 | reg |= DSIM_EOT_DISABLE; | ||
478 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) | 605 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) |
479 | reg |= DSIM_SYNC_INFORM; | 606 | reg |= DSIM_SYNC_INFORM; |
480 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) | 607 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) |
@@ -491,6 +618,9 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) | |||
491 | reg |= DSIM_HSA_MODE; | 618 | reg |= DSIM_HSA_MODE; |
492 | } | 619 | } |
493 | 620 | ||
621 | if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) | ||
622 | reg |= DSIM_EOT_DISABLE; | ||
623 | |||
494 | switch (dsi->format) { | 624 | switch (dsi->format) { |
495 | case MIPI_DSI_FMT_RGB888: | 625 | case MIPI_DSI_FMT_RGB888: |
496 | reg |= DSIM_MAIN_PIX_FORMAT_RGB888; | 626 | reg |= DSIM_MAIN_PIX_FORMAT_RGB888; |
@@ -944,17 +1074,90 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) | |||
944 | return IRQ_HANDLED; | 1074 | return IRQ_HANDLED; |
945 | } | 1075 | } |
946 | 1076 | ||
1077 | static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) | ||
1078 | { | ||
1079 | struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; | ||
1080 | struct drm_encoder *encoder = dsi->encoder; | ||
1081 | |||
1082 | if (dsi->state & DSIM_STATE_ENABLED) | ||
1083 | exynos_drm_crtc_te_handler(encoder->crtc); | ||
1084 | |||
1085 | return IRQ_HANDLED; | ||
1086 | } | ||
1087 | |||
1088 | static void exynos_dsi_enable_irq(struct exynos_dsi *dsi) | ||
1089 | { | ||
1090 | enable_irq(dsi->irq); | ||
1091 | |||
1092 | if (gpio_is_valid(dsi->te_gpio)) | ||
1093 | enable_irq(gpio_to_irq(dsi->te_gpio)); | ||
1094 | } | ||
1095 | |||
1096 | static void exynos_dsi_disable_irq(struct exynos_dsi *dsi) | ||
1097 | { | ||
1098 | if (gpio_is_valid(dsi->te_gpio)) | ||
1099 | disable_irq(gpio_to_irq(dsi->te_gpio)); | ||
1100 | |||
1101 | disable_irq(dsi->irq); | ||
1102 | } | ||
1103 | |||
947 | static int exynos_dsi_init(struct exynos_dsi *dsi) | 1104 | static int exynos_dsi_init(struct exynos_dsi *dsi) |
948 | { | 1105 | { |
949 | exynos_dsi_enable_clock(dsi); | ||
950 | exynos_dsi_reset(dsi); | 1106 | exynos_dsi_reset(dsi); |
951 | enable_irq(dsi->irq); | 1107 | exynos_dsi_enable_irq(dsi); |
1108 | exynos_dsi_enable_clock(dsi); | ||
952 | exynos_dsi_wait_for_reset(dsi); | 1109 | exynos_dsi_wait_for_reset(dsi); |
1110 | exynos_dsi_set_phy_ctrl(dsi); | ||
953 | exynos_dsi_init_link(dsi); | 1111 | exynos_dsi_init_link(dsi); |
954 | 1112 | ||
955 | return 0; | 1113 | return 0; |
956 | } | 1114 | } |
957 | 1115 | ||
1116 | static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) | ||
1117 | { | ||
1118 | int ret; | ||
1119 | |||
1120 | dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0); | ||
1121 | if (!gpio_is_valid(dsi->te_gpio)) { | ||
1122 | dev_err(dsi->dev, "no te-gpios specified\n"); | ||
1123 | ret = dsi->te_gpio; | ||
1124 | goto out; | ||
1125 | } | ||
1126 | |||
1127 | ret = gpio_request_one(dsi->te_gpio, GPIOF_IN, "te_gpio"); | ||
1128 | if (ret) { | ||
1129 | dev_err(dsi->dev, "gpio request failed with %d\n", ret); | ||
1130 | goto out; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * This TE GPIO IRQ should not be set to IRQ_NOAUTOEN, because panel | ||
1135 | * calls drm_panel_init() first then calls mipi_dsi_attach() in probe(). | ||
1136 | * It means that te_gpio is invalid when exynos_dsi_enable_irq() is | ||
1137 | * called by drm_panel_init() before panel is attached. | ||
1138 | */ | ||
1139 | ret = request_threaded_irq(gpio_to_irq(dsi->te_gpio), | ||
1140 | exynos_dsi_te_irq_handler, NULL, | ||
1141 | IRQF_TRIGGER_RISING, "TE", dsi); | ||
1142 | if (ret) { | ||
1143 | dev_err(dsi->dev, "request interrupt failed with %d\n", ret); | ||
1144 | gpio_free(dsi->te_gpio); | ||
1145 | goto out; | ||
1146 | } | ||
1147 | |||
1148 | out: | ||
1149 | return ret; | ||
1150 | } | ||
1151 | |||
1152 | static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) | ||
1153 | { | ||
1154 | if (gpio_is_valid(dsi->te_gpio)) { | ||
1155 | free_irq(gpio_to_irq(dsi->te_gpio), dsi); | ||
1156 | gpio_free(dsi->te_gpio); | ||
1157 | dsi->te_gpio = -ENOENT; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
958 | static int exynos_dsi_host_attach(struct mipi_dsi_host *host, | 1161 | static int exynos_dsi_host_attach(struct mipi_dsi_host *host, |
959 | struct mipi_dsi_device *device) | 1162 | struct mipi_dsi_device *device) |
960 | { | 1163 | { |
@@ -968,6 +1171,19 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, | |||
968 | if (dsi->connector.dev) | 1171 | if (dsi->connector.dev) |
969 | drm_helper_hpd_irq_event(dsi->connector.dev); | 1172 | drm_helper_hpd_irq_event(dsi->connector.dev); |
970 | 1173 | ||
1174 | /* | ||
1175 | * This is a temporary solution and should be made by more generic way. | ||
1176 | * | ||
1177 | * If attached panel device is for command mode one, dsi should register | ||
1178 | * TE interrupt handler. | ||
1179 | */ | ||
1180 | if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { | ||
1181 | int ret = exynos_dsi_register_te_irq(dsi); | ||
1182 | |||
1183 | if (ret) | ||
1184 | return ret; | ||
1185 | } | ||
1186 | |||
971 | return 0; | 1187 | return 0; |
972 | } | 1188 | } |
973 | 1189 | ||
@@ -976,6 +1192,8 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, | |||
976 | { | 1192 | { |
977 | struct exynos_dsi *dsi = host_to_dsi(host); | 1193 | struct exynos_dsi *dsi = host_to_dsi(host); |
978 | 1194 | ||
1195 | exynos_dsi_unregister_te_irq(dsi); | ||
1196 | |||
979 | dsi->panel_node = NULL; | 1197 | dsi->panel_node = NULL; |
980 | 1198 | ||
981 | if (dsi->connector.dev) | 1199 | if (dsi->connector.dev) |
@@ -1089,7 +1307,7 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi) | |||
1089 | 1307 | ||
1090 | exynos_dsi_disable_clock(dsi); | 1308 | exynos_dsi_disable_clock(dsi); |
1091 | 1309 | ||
1092 | disable_irq(dsi->irq); | 1310 | exynos_dsi_disable_irq(dsi); |
1093 | } | 1311 | } |
1094 | 1312 | ||
1095 | dsi->state &= ~DSIM_STATE_CMD_LPM; | 1313 | dsi->state &= ~DSIM_STATE_CMD_LPM; |
@@ -1278,6 +1496,7 @@ static struct exynos_drm_display exynos_dsi_display = { | |||
1278 | .type = EXYNOS_DISPLAY_TYPE_LCD, | 1496 | .type = EXYNOS_DISPLAY_TYPE_LCD, |
1279 | .ops = &exynos_dsi_display_ops, | 1497 | .ops = &exynos_dsi_display_ops, |
1280 | }; | 1498 | }; |
1499 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); | ||
1281 | 1500 | ||
1282 | /* of_* functions will be removed after merge of of_graph patches */ | 1501 | /* of_* functions will be removed after merge of of_graph patches */ |
1283 | static struct device_node * | 1502 | static struct device_node * |
@@ -1435,6 +1654,9 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
1435 | goto err_del_component; | 1654 | goto err_del_component; |
1436 | } | 1655 | } |
1437 | 1656 | ||
1657 | /* To be checked as invalid one */ | ||
1658 | dsi->te_gpio = -ENOENT; | ||
1659 | |||
1438 | init_completion(&dsi->completed); | 1660 | init_completion(&dsi->completed); |
1439 | spin_lock_init(&dsi->transfer_lock); | 1661 | spin_lock_init(&dsi->transfer_lock); |
1440 | INIT_LIST_HEAD(&dsi->transfer_list); | 1662 | INIT_LIST_HEAD(&dsi->transfer_list); |
@@ -1443,6 +1665,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
1443 | dsi->dsi_host.dev = &pdev->dev; | 1665 | dsi->dsi_host.dev = &pdev->dev; |
1444 | 1666 | ||
1445 | dsi->dev = &pdev->dev; | 1667 | dsi->dev = &pdev->dev; |
1668 | dsi->driver_data = exynos_dsi_get_driver_data(pdev); | ||
1446 | 1669 | ||
1447 | ret = exynos_dsi_parse_dt(dsi); | 1670 | ret = exynos_dsi_parse_dt(dsi); |
1448 | if (ret) | 1671 | if (ret) |
@@ -1525,11 +1748,6 @@ static int exynos_dsi_remove(struct platform_device *pdev) | |||
1525 | return 0; | 1748 | return 0; |
1526 | } | 1749 | } |
1527 | 1750 | ||
1528 | static struct of_device_id exynos_dsi_of_match[] = { | ||
1529 | { .compatible = "samsung,exynos4210-mipi-dsi" }, | ||
1530 | { } | ||
1531 | }; | ||
1532 | |||
1533 | struct platform_driver dsi_driver = { | 1751 | struct platform_driver dsi_driver = { |
1534 | .probe = exynos_dsi_probe, | 1752 | .probe = exynos_dsi_probe, |
1535 | .remove = exynos_dsi_remove, | 1753 | .remove = exynos_dsi_remove, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 831dde9034c6..ec7cc9ea50df 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c | |||
@@ -1887,6 +1887,7 @@ static const struct of_device_id fimc_of_match[] = { | |||
1887 | { .compatible = "samsung,exynos4212-fimc" }, | 1887 | { .compatible = "samsung,exynos4212-fimc" }, |
1888 | { }, | 1888 | { }, |
1889 | }; | 1889 | }; |
1890 | MODULE_DEVICE_TABLE(of, fimc_of_match); | ||
1890 | 1891 | ||
1891 | struct platform_driver fimc_driver = { | 1892 | struct platform_driver fimc_driver = { |
1892 | .probe = fimc_probe, | 1893 | .probe = fimc_probe, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 33161ad38201..5d09e33fef87 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -20,6 +20,8 @@ | |||
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 | #include <linux/component.h> |
23 | #include <linux/mfd/syscon.h> | ||
24 | #include <linux/regmap.h> | ||
23 | 25 | ||
24 | #include <video/of_display_timing.h> | 26 | #include <video/of_display_timing.h> |
25 | #include <video/of_videomode.h> | 27 | #include <video/of_videomode.h> |
@@ -61,6 +63,24 @@ | |||
61 | /* color key value register for hardware window 1 ~ 4. */ | 63 | /* color key value register for hardware window 1 ~ 4. */ |
62 | #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) | 64 | #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) |
63 | 65 | ||
66 | /* I80 / RGB trigger control register */ | ||
67 | #define TRIGCON 0x1A4 | ||
68 | #define TRGMODE_I80_RGB_ENABLE_I80 (1 << 0) | ||
69 | #define SWTRGCMD_I80_RGB_ENABLE (1 << 1) | ||
70 | |||
71 | /* display mode change control register except exynos4 */ | ||
72 | #define VIDOUT_CON 0x000 | ||
73 | #define VIDOUT_CON_F_I80_LDI0 (0x2 << 8) | ||
74 | |||
75 | /* I80 interface control for main LDI register */ | ||
76 | #define I80IFCONFAx(x) (0x1B0 + (x) * 4) | ||
77 | #define I80IFCONFBx(x) (0x1B8 + (x) * 4) | ||
78 | #define LCD_CS_SETUP(x) ((x) << 16) | ||
79 | #define LCD_WR_SETUP(x) ((x) << 12) | ||
80 | #define LCD_WR_ACTIVE(x) ((x) << 8) | ||
81 | #define LCD_WR_HOLD(x) ((x) << 4) | ||
82 | #define I80IFEN_ENABLE (1 << 0) | ||
83 | |||
64 | /* FIMD has totally five hardware windows. */ | 84 | /* FIMD has totally five hardware windows. */ |
65 | #define WINDOWS_NR 5 | 85 | #define WINDOWS_NR 5 |
66 | 86 | ||
@@ -68,10 +88,14 @@ | |||
68 | 88 | ||
69 | struct fimd_driver_data { | 89 | struct fimd_driver_data { |
70 | unsigned int timing_base; | 90 | unsigned int timing_base; |
91 | unsigned int lcdblk_offset; | ||
92 | unsigned int lcdblk_vt_shift; | ||
93 | unsigned int lcdblk_bypass_shift; | ||
71 | 94 | ||
72 | unsigned int has_shadowcon:1; | 95 | unsigned int has_shadowcon:1; |
73 | unsigned int has_clksel:1; | 96 | unsigned int has_clksel:1; |
74 | unsigned int has_limited_fmt:1; | 97 | unsigned int has_limited_fmt:1; |
98 | unsigned int has_vidoutcon:1; | ||
75 | }; | 99 | }; |
76 | 100 | ||
77 | static struct fimd_driver_data s3c64xx_fimd_driver_data = { | 101 | static struct fimd_driver_data s3c64xx_fimd_driver_data = { |
@@ -82,12 +106,19 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = { | |||
82 | 106 | ||
83 | static struct fimd_driver_data exynos4_fimd_driver_data = { | 107 | static struct fimd_driver_data exynos4_fimd_driver_data = { |
84 | .timing_base = 0x0, | 108 | .timing_base = 0x0, |
109 | .lcdblk_offset = 0x210, | ||
110 | .lcdblk_vt_shift = 10, | ||
111 | .lcdblk_bypass_shift = 1, | ||
85 | .has_shadowcon = 1, | 112 | .has_shadowcon = 1, |
86 | }; | 113 | }; |
87 | 114 | ||
88 | static struct fimd_driver_data exynos5_fimd_driver_data = { | 115 | static struct fimd_driver_data exynos5_fimd_driver_data = { |
89 | .timing_base = 0x20000, | 116 | .timing_base = 0x20000, |
117 | .lcdblk_offset = 0x214, | ||
118 | .lcdblk_vt_shift = 24, | ||
119 | .lcdblk_bypass_shift = 15, | ||
90 | .has_shadowcon = 1, | 120 | .has_shadowcon = 1, |
121 | .has_vidoutcon = 1, | ||
91 | }; | 122 | }; |
92 | 123 | ||
93 | struct fimd_win_data { | 124 | struct fimd_win_data { |
@@ -112,15 +143,22 @@ struct fimd_context { | |||
112 | struct clk *bus_clk; | 143 | struct clk *bus_clk; |
113 | struct clk *lcd_clk; | 144 | struct clk *lcd_clk; |
114 | void __iomem *regs; | 145 | void __iomem *regs; |
146 | struct regmap *sysreg; | ||
115 | struct drm_display_mode mode; | 147 | struct drm_display_mode mode; |
116 | struct fimd_win_data win_data[WINDOWS_NR]; | 148 | struct fimd_win_data win_data[WINDOWS_NR]; |
117 | unsigned int default_win; | 149 | unsigned int default_win; |
118 | unsigned long irq_flags; | 150 | unsigned long irq_flags; |
151 | u32 vidcon0; | ||
119 | u32 vidcon1; | 152 | u32 vidcon1; |
153 | u32 vidout_con; | ||
154 | u32 i80ifcon; | ||
155 | bool i80_if; | ||
120 | bool suspended; | 156 | bool suspended; |
121 | int pipe; | 157 | int pipe; |
122 | wait_queue_head_t wait_vsync_queue; | 158 | wait_queue_head_t wait_vsync_queue; |
123 | atomic_t wait_vsync_event; | 159 | atomic_t wait_vsync_event; |
160 | atomic_t win_updated; | ||
161 | atomic_t triggering; | ||
124 | 162 | ||
125 | struct exynos_drm_panel_info panel; | 163 | struct exynos_drm_panel_info panel; |
126 | struct fimd_driver_data *driver_data; | 164 | struct fimd_driver_data *driver_data; |
@@ -136,6 +174,7 @@ static const struct of_device_id fimd_driver_dt_match[] = { | |||
136 | .data = &exynos5_fimd_driver_data }, | 174 | .data = &exynos5_fimd_driver_data }, |
137 | {}, | 175 | {}, |
138 | }; | 176 | }; |
177 | MODULE_DEVICE_TABLE(of, fimd_driver_dt_match); | ||
139 | 178 | ||
140 | static inline struct fimd_driver_data *drm_fimd_get_driver_data( | 179 | static inline struct fimd_driver_data *drm_fimd_get_driver_data( |
141 | struct platform_device *pdev) | 180 | struct platform_device *pdev) |
@@ -243,6 +282,14 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, | |||
243 | unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; | 282 | unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; |
244 | u32 clkdiv; | 283 | u32 clkdiv; |
245 | 284 | ||
285 | if (ctx->i80_if) { | ||
286 | /* | ||
287 | * The frame done interrupt should be occurred prior to the | ||
288 | * next TE signal. | ||
289 | */ | ||
290 | ideal_clk *= 2; | ||
291 | } | ||
292 | |||
246 | /* Find the clock divider value that gets us closest to ideal_clk */ | 293 | /* Find the clock divider value that gets us closest to ideal_clk */ |
247 | clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); | 294 | clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); |
248 | 295 | ||
@@ -271,11 +318,10 @@ static void fimd_commit(struct exynos_drm_manager *mgr) | |||
271 | { | 318 | { |
272 | struct fimd_context *ctx = mgr->ctx; | 319 | struct fimd_context *ctx = mgr->ctx; |
273 | struct drm_display_mode *mode = &ctx->mode; | 320 | struct drm_display_mode *mode = &ctx->mode; |
274 | struct fimd_driver_data *driver_data; | 321 | struct fimd_driver_data *driver_data = ctx->driver_data; |
275 | u32 val, clkdiv, vidcon1; | 322 | void *timing_base = ctx->regs + driver_data->timing_base; |
276 | int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; | 323 | u32 val, clkdiv; |
277 | 324 | ||
278 | driver_data = ctx->driver_data; | ||
279 | if (ctx->suspended) | 325 | if (ctx->suspended) |
280 | return; | 326 | return; |
281 | 327 | ||
@@ -283,33 +329,65 @@ static void fimd_commit(struct exynos_drm_manager *mgr) | |||
283 | if (mode->htotal == 0 || mode->vtotal == 0) | 329 | if (mode->htotal == 0 || mode->vtotal == 0) |
284 | return; | 330 | return; |
285 | 331 | ||
286 | /* setup polarity values */ | 332 | if (ctx->i80_if) { |
287 | vidcon1 = ctx->vidcon1; | 333 | val = ctx->i80ifcon | I80IFEN_ENABLE; |
288 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 334 | writel(val, timing_base + I80IFCONFAx(0)); |
289 | vidcon1 |= VIDCON1_INV_VSYNC; | 335 | |
290 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 336 | /* disable auto frame rate */ |
291 | vidcon1 |= VIDCON1_INV_HSYNC; | 337 | writel(0, timing_base + I80IFCONFBx(0)); |
292 | writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); | 338 | |
293 | 339 | /* set video type selection to I80 interface */ | |
294 | /* setup vertical timing values. */ | 340 | if (ctx->sysreg && regmap_update_bits(ctx->sysreg, |
295 | vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | 341 | driver_data->lcdblk_offset, |
296 | vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; | 342 | 0x3 << driver_data->lcdblk_vt_shift, |
297 | vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; | 343 | 0x1 << driver_data->lcdblk_vt_shift)) { |
298 | 344 | DRM_ERROR("Failed to update sysreg for I80 i/f.\n"); | |
299 | val = VIDTCON0_VBPD(vbpd - 1) | | 345 | return; |
300 | VIDTCON0_VFPD(vfpd - 1) | | 346 | } |
301 | VIDTCON0_VSPW(vsync_len - 1); | 347 | } else { |
302 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); | 348 | int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; |
303 | 349 | u32 vidcon1; | |
304 | /* setup horizontal timing values. */ | 350 | |
305 | hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | 351 | /* setup polarity values */ |
306 | hbpd = mode->crtc_htotal - mode->crtc_hsync_end; | 352 | vidcon1 = ctx->vidcon1; |
307 | hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; | 353 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
308 | 354 | vidcon1 |= VIDCON1_INV_VSYNC; | |
309 | val = VIDTCON1_HBPD(hbpd - 1) | | 355 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
310 | VIDTCON1_HFPD(hfpd - 1) | | 356 | vidcon1 |= VIDCON1_INV_HSYNC; |
311 | VIDTCON1_HSPW(hsync_len - 1); | 357 | writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); |
312 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); | 358 | |
359 | /* setup vertical timing values. */ | ||
360 | vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
361 | vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; | ||
362 | vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; | ||
363 | |||
364 | val = VIDTCON0_VBPD(vbpd - 1) | | ||
365 | VIDTCON0_VFPD(vfpd - 1) | | ||
366 | VIDTCON0_VSPW(vsync_len - 1); | ||
367 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); | ||
368 | |||
369 | /* setup horizontal timing values. */ | ||
370 | hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
371 | hbpd = mode->crtc_htotal - mode->crtc_hsync_end; | ||
372 | hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; | ||
373 | |||
374 | val = VIDTCON1_HBPD(hbpd - 1) | | ||
375 | VIDTCON1_HFPD(hfpd - 1) | | ||
376 | VIDTCON1_HSPW(hsync_len - 1); | ||
377 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); | ||
378 | } | ||
379 | |||
380 | if (driver_data->has_vidoutcon) | ||
381 | writel(ctx->vidout_con, timing_base + VIDOUT_CON); | ||
382 | |||
383 | /* set bypass selection */ | ||
384 | if (ctx->sysreg && regmap_update_bits(ctx->sysreg, | ||
385 | driver_data->lcdblk_offset, | ||
386 | 0x1 << driver_data->lcdblk_bypass_shift, | ||
387 | 0x1 << driver_data->lcdblk_bypass_shift)) { | ||
388 | DRM_ERROR("Failed to update sysreg for bypass setting.\n"); | ||
389 | return; | ||
390 | } | ||
313 | 391 | ||
314 | /* setup horizontal and vertical display size. */ | 392 | /* setup horizontal and vertical display size. */ |
315 | val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | | 393 | val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | |
@@ -322,7 +400,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr) | |||
322 | * fields of register with prefix '_F' would be updated | 400 | * fields of register with prefix '_F' would be updated |
323 | * at vsync(same as dma start) | 401 | * at vsync(same as dma start) |
324 | */ | 402 | */ |
325 | val = VIDCON0_ENVID | VIDCON0_ENVID_F; | 403 | val = ctx->vidcon0; |
404 | val |= VIDCON0_ENVID | VIDCON0_ENVID_F; | ||
326 | 405 | ||
327 | if (ctx->driver_data->has_clksel) | 406 | if (ctx->driver_data->has_clksel) |
328 | val |= VIDCON0_CLKSEL_LCD; | 407 | val |= VIDCON0_CLKSEL_LCD; |
@@ -660,6 +739,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) | |||
660 | } | 739 | } |
661 | 740 | ||
662 | win_data->enabled = true; | 741 | win_data->enabled = true; |
742 | |||
743 | if (ctx->i80_if) | ||
744 | atomic_set(&ctx->win_updated, 1); | ||
663 | } | 745 | } |
664 | 746 | ||
665 | static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) | 747 | static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) |
@@ -838,6 +920,58 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) | |||
838 | } | 920 | } |
839 | } | 921 | } |
840 | 922 | ||
923 | static void fimd_trigger(struct device *dev) | ||
924 | { | ||
925 | struct exynos_drm_manager *mgr = get_fimd_manager(dev); | ||
926 | struct fimd_context *ctx = mgr->ctx; | ||
927 | struct fimd_driver_data *driver_data = ctx->driver_data; | ||
928 | void *timing_base = ctx->regs + driver_data->timing_base; | ||
929 | u32 reg; | ||
930 | |||
931 | atomic_set(&ctx->triggering, 1); | ||
932 | |||
933 | reg = readl(ctx->regs + VIDINTCON0); | ||
934 | reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE | | ||
935 | VIDINTCON0_INT_SYSMAINCON); | ||
936 | writel(reg, ctx->regs + VIDINTCON0); | ||
937 | |||
938 | reg = readl(timing_base + TRIGCON); | ||
939 | reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE); | ||
940 | writel(reg, timing_base + TRIGCON); | ||
941 | } | ||
942 | |||
943 | static void fimd_te_handler(struct exynos_drm_manager *mgr) | ||
944 | { | ||
945 | struct fimd_context *ctx = mgr->ctx; | ||
946 | |||
947 | /* Checks the crtc is detached already from encoder */ | ||
948 | if (ctx->pipe < 0 || !ctx->drm_dev) | ||
949 | return; | ||
950 | |||
951 | /* | ||
952 | * Skips to trigger if in triggering state, because multiple triggering | ||
953 | * requests can cause panel reset. | ||
954 | */ | ||
955 | if (atomic_read(&ctx->triggering)) | ||
956 | return; | ||
957 | |||
958 | /* | ||
959 | * If there is a page flip request, triggers and handles the page flip | ||
960 | * event so that current fb can be updated into panel GRAM. | ||
961 | */ | ||
962 | if (atomic_add_unless(&ctx->win_updated, -1, 0)) | ||
963 | fimd_trigger(ctx->dev); | ||
964 | |||
965 | /* Wakes up vsync event queue */ | ||
966 | if (atomic_read(&ctx->wait_vsync_event)) { | ||
967 | atomic_set(&ctx->wait_vsync_event, 0); | ||
968 | wake_up(&ctx->wait_vsync_queue); | ||
969 | |||
970 | if (!atomic_read(&ctx->triggering)) | ||
971 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | ||
972 | } | ||
973 | } | ||
974 | |||
841 | static struct exynos_drm_manager_ops fimd_manager_ops = { | 975 | static struct exynos_drm_manager_ops fimd_manager_ops = { |
842 | .dpms = fimd_dpms, | 976 | .dpms = fimd_dpms, |
843 | .mode_fixup = fimd_mode_fixup, | 977 | .mode_fixup = fimd_mode_fixup, |
@@ -849,6 +983,7 @@ static struct exynos_drm_manager_ops fimd_manager_ops = { | |||
849 | .win_mode_set = fimd_win_mode_set, | 983 | .win_mode_set = fimd_win_mode_set, |
850 | .win_commit = fimd_win_commit, | 984 | .win_commit = fimd_win_commit, |
851 | .win_disable = fimd_win_disable, | 985 | .win_disable = fimd_win_disable, |
986 | .te_handler = fimd_te_handler, | ||
852 | }; | 987 | }; |
853 | 988 | ||
854 | static struct exynos_drm_manager fimd_manager = { | 989 | static struct exynos_drm_manager fimd_manager = { |
@@ -859,26 +994,40 @@ static struct exynos_drm_manager fimd_manager = { | |||
859 | static irqreturn_t fimd_irq_handler(int irq, void *dev_id) | 994 | static irqreturn_t fimd_irq_handler(int irq, void *dev_id) |
860 | { | 995 | { |
861 | struct fimd_context *ctx = (struct fimd_context *)dev_id; | 996 | struct fimd_context *ctx = (struct fimd_context *)dev_id; |
862 | u32 val; | 997 | u32 val, clear_bit; |
863 | 998 | ||
864 | val = readl(ctx->regs + VIDINTCON1); | 999 | val = readl(ctx->regs + VIDINTCON1); |
865 | 1000 | ||
866 | if (val & VIDINTCON1_INT_FRAME) | 1001 | clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME; |
867 | /* VSYNC interrupt */ | 1002 | if (val & clear_bit) |
868 | writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); | 1003 | writel(clear_bit, ctx->regs + VIDINTCON1); |
869 | 1004 | ||
870 | /* check the crtc is detached already from encoder */ | 1005 | /* check the crtc is detached already from encoder */ |
871 | if (ctx->pipe < 0 || !ctx->drm_dev) | 1006 | if (ctx->pipe < 0 || !ctx->drm_dev) |
872 | goto out; | 1007 | goto out; |
873 | 1008 | ||
874 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 1009 | if (ctx->i80_if) { |
875 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 1010 | /* unset I80 frame done interrupt */ |
1011 | val = readl(ctx->regs + VIDINTCON0); | ||
1012 | val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON); | ||
1013 | writel(val, ctx->regs + VIDINTCON0); | ||
876 | 1014 | ||
877 | /* set wait vsync event to zero and wake up queue. */ | 1015 | /* exit triggering mode */ |
878 | if (atomic_read(&ctx->wait_vsync_event)) { | 1016 | atomic_set(&ctx->triggering, 0); |
879 | atomic_set(&ctx->wait_vsync_event, 0); | 1017 | |
880 | wake_up(&ctx->wait_vsync_queue); | 1018 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); |
1019 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | ||
1020 | } else { | ||
1021 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | ||
1022 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | ||
1023 | |||
1024 | /* set wait vsync event to zero and wake up queue. */ | ||
1025 | if (atomic_read(&ctx->wait_vsync_event)) { | ||
1026 | atomic_set(&ctx->wait_vsync_event, 0); | ||
1027 | wake_up(&ctx->wait_vsync_queue); | ||
1028 | } | ||
881 | } | 1029 | } |
1030 | |||
882 | out: | 1031 | out: |
883 | return IRQ_HANDLED; | 1032 | return IRQ_HANDLED; |
884 | } | 1033 | } |
@@ -923,6 +1072,7 @@ static int fimd_probe(struct platform_device *pdev) | |||
923 | { | 1072 | { |
924 | struct device *dev = &pdev->dev; | 1073 | struct device *dev = &pdev->dev; |
925 | struct fimd_context *ctx; | 1074 | struct fimd_context *ctx; |
1075 | struct device_node *i80_if_timings; | ||
926 | struct resource *res; | 1076 | struct resource *res; |
927 | int ret = -EINVAL; | 1077 | int ret = -EINVAL; |
928 | 1078 | ||
@@ -944,12 +1094,51 @@ static int fimd_probe(struct platform_device *pdev) | |||
944 | 1094 | ||
945 | ctx->dev = dev; | 1095 | ctx->dev = dev; |
946 | ctx->suspended = true; | 1096 | ctx->suspended = true; |
1097 | ctx->driver_data = drm_fimd_get_driver_data(pdev); | ||
947 | 1098 | ||
948 | if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) | 1099 | if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) |
949 | ctx->vidcon1 |= VIDCON1_INV_VDEN; | 1100 | ctx->vidcon1 |= VIDCON1_INV_VDEN; |
950 | if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) | 1101 | if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) |
951 | ctx->vidcon1 |= VIDCON1_INV_VCLK; | 1102 | ctx->vidcon1 |= VIDCON1_INV_VCLK; |
952 | 1103 | ||
1104 | i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings"); | ||
1105 | if (i80_if_timings) { | ||
1106 | u32 val; | ||
1107 | |||
1108 | ctx->i80_if = true; | ||
1109 | |||
1110 | if (ctx->driver_data->has_vidoutcon) | ||
1111 | ctx->vidout_con |= VIDOUT_CON_F_I80_LDI0; | ||
1112 | else | ||
1113 | ctx->vidcon0 |= VIDCON0_VIDOUT_I80_LDI0; | ||
1114 | /* | ||
1115 | * The user manual describes that this "DSI_EN" bit is required | ||
1116 | * to enable I80 24-bit data interface. | ||
1117 | */ | ||
1118 | ctx->vidcon0 |= VIDCON0_DSI_EN; | ||
1119 | |||
1120 | if (of_property_read_u32(i80_if_timings, "cs-setup", &val)) | ||
1121 | val = 0; | ||
1122 | ctx->i80ifcon = LCD_CS_SETUP(val); | ||
1123 | if (of_property_read_u32(i80_if_timings, "wr-setup", &val)) | ||
1124 | val = 0; | ||
1125 | ctx->i80ifcon |= LCD_WR_SETUP(val); | ||
1126 | if (of_property_read_u32(i80_if_timings, "wr-active", &val)) | ||
1127 | val = 1; | ||
1128 | ctx->i80ifcon |= LCD_WR_ACTIVE(val); | ||
1129 | if (of_property_read_u32(i80_if_timings, "wr-hold", &val)) | ||
1130 | val = 0; | ||
1131 | ctx->i80ifcon |= LCD_WR_HOLD(val); | ||
1132 | } | ||
1133 | of_node_put(i80_if_timings); | ||
1134 | |||
1135 | ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
1136 | "samsung,sysreg"); | ||
1137 | if (IS_ERR(ctx->sysreg)) { | ||
1138 | dev_warn(dev, "failed to get system register.\n"); | ||
1139 | ctx->sysreg = NULL; | ||
1140 | } | ||
1141 | |||
953 | ctx->bus_clk = devm_clk_get(dev, "fimd"); | 1142 | ctx->bus_clk = devm_clk_get(dev, "fimd"); |
954 | if (IS_ERR(ctx->bus_clk)) { | 1143 | if (IS_ERR(ctx->bus_clk)) { |
955 | dev_err(dev, "failed to get bus clock\n"); | 1144 | dev_err(dev, "failed to get bus clock\n"); |
@@ -972,7 +1161,8 @@ static int fimd_probe(struct platform_device *pdev) | |||
972 | goto err_del_component; | 1161 | goto err_del_component; |
973 | } | 1162 | } |
974 | 1163 | ||
975 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); | 1164 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, |
1165 | ctx->i80_if ? "lcd_sys" : "vsync"); | ||
976 | if (!res) { | 1166 | if (!res) { |
977 | dev_err(dev, "irq request failed.\n"); | 1167 | dev_err(dev, "irq request failed.\n"); |
978 | ret = -ENXIO; | 1168 | ret = -ENXIO; |
@@ -986,7 +1176,6 @@ static int fimd_probe(struct platform_device *pdev) | |||
986 | goto err_del_component; | 1176 | goto err_del_component; |
987 | } | 1177 | } |
988 | 1178 | ||
989 | ctx->driver_data = drm_fimd_get_driver_data(pdev); | ||
990 | init_waitqueue_head(&ctx->wait_vsync_queue); | 1179 | init_waitqueue_head(&ctx->wait_vsync_queue); |
991 | atomic_set(&ctx->wait_vsync_event, 0); | 1180 | atomic_set(&ctx->wait_vsync_event, 0); |
992 | 1181 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 800158714473..df7a77d3eff8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
@@ -1042,8 +1042,23 @@ err: | |||
1042 | int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, | 1042 | int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, |
1043 | struct drm_file *file) | 1043 | struct drm_file *file) |
1044 | { | 1044 | { |
1045 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
1046 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
1047 | struct device *dev; | ||
1048 | struct g2d_data *g2d; | ||
1045 | struct drm_exynos_g2d_get_ver *ver = data; | 1049 | struct drm_exynos_g2d_get_ver *ver = data; |
1046 | 1050 | ||
1051 | if (!g2d_priv) | ||
1052 | return -ENODEV; | ||
1053 | |||
1054 | dev = g2d_priv->dev; | ||
1055 | if (!dev) | ||
1056 | return -ENODEV; | ||
1057 | |||
1058 | g2d = dev_get_drvdata(dev); | ||
1059 | if (!g2d) | ||
1060 | return -EFAULT; | ||
1061 | |||
1047 | ver->major = G2D_HW_MAJOR_VER; | 1062 | ver->major = G2D_HW_MAJOR_VER; |
1048 | ver->minor = G2D_HW_MINOR_VER; | 1063 | ver->minor = G2D_HW_MINOR_VER; |
1049 | 1064 | ||
@@ -1056,7 +1071,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1056 | { | 1071 | { |
1057 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1072 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1058 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | 1073 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; |
1059 | struct device *dev = g2d_priv->dev; | 1074 | struct device *dev; |
1060 | struct g2d_data *g2d; | 1075 | struct g2d_data *g2d; |
1061 | struct drm_exynos_g2d_set_cmdlist *req = data; | 1076 | struct drm_exynos_g2d_set_cmdlist *req = data; |
1062 | struct drm_exynos_g2d_cmd *cmd; | 1077 | struct drm_exynos_g2d_cmd *cmd; |
@@ -1067,6 +1082,10 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1067 | int size; | 1082 | int size; |
1068 | int ret; | 1083 | int ret; |
1069 | 1084 | ||
1085 | if (!g2d_priv) | ||
1086 | return -ENODEV; | ||
1087 | |||
1088 | dev = g2d_priv->dev; | ||
1070 | if (!dev) | 1089 | if (!dev) |
1071 | return -ENODEV; | 1090 | return -ENODEV; |
1072 | 1091 | ||
@@ -1223,13 +1242,17 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, | |||
1223 | { | 1242 | { |
1224 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1243 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1225 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | 1244 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; |
1226 | struct device *dev = g2d_priv->dev; | 1245 | struct device *dev; |
1227 | struct g2d_data *g2d; | 1246 | struct g2d_data *g2d; |
1228 | struct drm_exynos_g2d_exec *req = data; | 1247 | struct drm_exynos_g2d_exec *req = data; |
1229 | struct g2d_runqueue_node *runqueue_node; | 1248 | struct g2d_runqueue_node *runqueue_node; |
1230 | struct list_head *run_cmdlist; | 1249 | struct list_head *run_cmdlist; |
1231 | struct list_head *event_list; | 1250 | struct list_head *event_list; |
1232 | 1251 | ||
1252 | if (!g2d_priv) | ||
1253 | return -ENODEV; | ||
1254 | |||
1255 | dev = g2d_priv->dev; | ||
1233 | if (!dev) | 1256 | if (!dev) |
1234 | return -ENODEV; | 1257 | return -ENODEV; |
1235 | 1258 | ||
@@ -1544,8 +1567,10 @@ static const struct dev_pm_ops g2d_pm_ops = { | |||
1544 | 1567 | ||
1545 | static const struct of_device_id exynos_g2d_match[] = { | 1568 | static const struct of_device_id exynos_g2d_match[] = { |
1546 | { .compatible = "samsung,exynos5250-g2d" }, | 1569 | { .compatible = "samsung,exynos5250-g2d" }, |
1570 | { .compatible = "samsung,exynos4212-g2d" }, | ||
1547 | {}, | 1571 | {}, |
1548 | }; | 1572 | }; |
1573 | MODULE_DEVICE_TABLE(of, exynos_g2d_match); | ||
1549 | 1574 | ||
1550 | struct platform_driver g2d_driver = { | 1575 | struct platform_driver g2d_driver = { |
1551 | .probe = g2d_probe, | 1576 | .probe = g2d_probe, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 163a054922cb..15db80138382 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
@@ -301,7 +301,6 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev, | |||
301 | unsigned int gem_handle, | 301 | unsigned int gem_handle, |
302 | struct drm_file *filp) | 302 | struct drm_file *filp) |
303 | { | 303 | { |
304 | struct exynos_drm_gem_obj *exynos_gem_obj; | ||
305 | struct drm_gem_object *obj; | 304 | struct drm_gem_object *obj; |
306 | 305 | ||
307 | obj = drm_gem_object_lookup(dev, filp, gem_handle); | 306 | obj = drm_gem_object_lookup(dev, filp, gem_handle); |
@@ -310,8 +309,6 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev, | |||
310 | return; | 309 | return; |
311 | } | 310 | } |
312 | 311 | ||
313 | exynos_gem_obj = to_exynos_gem_obj(obj); | ||
314 | |||
315 | drm_gem_object_unreference_unlocked(obj); | 312 | drm_gem_object_unreference_unlocked(obj); |
316 | 313 | ||
317 | /* | 314 | /* |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index a1888e128f1d..c411399070d6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c | |||
@@ -129,9 +129,6 @@ void exynos_platform_device_ipp_unregister(void) | |||
129 | 129 | ||
130 | int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) | 130 | int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) |
131 | { | 131 | { |
132 | if (!ippdrv) | ||
133 | return -EINVAL; | ||
134 | |||
135 | mutex_lock(&exynos_drm_ippdrv_lock); | 132 | mutex_lock(&exynos_drm_ippdrv_lock); |
136 | list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list); | 133 | list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list); |
137 | mutex_unlock(&exynos_drm_ippdrv_lock); | 134 | mutex_unlock(&exynos_drm_ippdrv_lock); |
@@ -141,9 +138,6 @@ int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) | |||
141 | 138 | ||
142 | int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) | 139 | int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) |
143 | { | 140 | { |
144 | if (!ippdrv) | ||
145 | return -EINVAL; | ||
146 | |||
147 | mutex_lock(&exynos_drm_ippdrv_lock); | 141 | mutex_lock(&exynos_drm_ippdrv_lock); |
148 | list_del(&ippdrv->drv_list); | 142 | list_del(&ippdrv->drv_list); |
149 | mutex_unlock(&exynos_drm_ippdrv_lock); | 143 | mutex_unlock(&exynos_drm_ippdrv_lock); |
@@ -151,20 +145,15 @@ int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) | |||
151 | return 0; | 145 | return 0; |
152 | } | 146 | } |
153 | 147 | ||
154 | static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj, | 148 | static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj) |
155 | u32 *idp) | ||
156 | { | 149 | { |
157 | int ret; | 150 | int ret; |
158 | 151 | ||
159 | /* do the allocation under our mutexlock */ | ||
160 | mutex_lock(lock); | 152 | mutex_lock(lock); |
161 | ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL); | 153 | ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL); |
162 | mutex_unlock(lock); | 154 | mutex_unlock(lock); |
163 | if (ret < 0) | ||
164 | return ret; | ||
165 | 155 | ||
166 | *idp = ret; | 156 | return ret; |
167 | return 0; | ||
168 | } | 157 | } |
169 | 158 | ||
170 | static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) | 159 | static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) |
@@ -178,35 +167,25 @@ static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) | |||
178 | { | 167 | { |
179 | void *obj; | 168 | void *obj; |
180 | 169 | ||
181 | DRM_DEBUG_KMS("id[%d]\n", id); | ||
182 | |||
183 | mutex_lock(lock); | 170 | mutex_lock(lock); |
184 | |||
185 | /* find object using handle */ | ||
186 | obj = idr_find(id_idr, id); | 171 | obj = idr_find(id_idr, id); |
187 | if (!obj) { | ||
188 | DRM_ERROR("failed to find object.\n"); | ||
189 | mutex_unlock(lock); | ||
190 | return ERR_PTR(-ENODEV); | ||
191 | } | ||
192 | |||
193 | mutex_unlock(lock); | 172 | mutex_unlock(lock); |
194 | 173 | ||
195 | return obj; | 174 | return obj; |
196 | } | 175 | } |
197 | 176 | ||
198 | static inline bool ipp_check_dedicated(struct exynos_drm_ippdrv *ippdrv, | 177 | static int ipp_check_driver(struct exynos_drm_ippdrv *ippdrv, |
199 | enum drm_exynos_ipp_cmd cmd) | 178 | struct drm_exynos_ipp_property *property) |
200 | { | 179 | { |
201 | /* | 180 | if (ippdrv->dedicated || (!ipp_is_m2m_cmd(property->cmd) && |
202 | * check dedicated flag and WB, OUTPUT operation with | 181 | !pm_runtime_suspended(ippdrv->dev))) |
203 | * power on state. | 182 | return -EBUSY; |
204 | */ | ||
205 | if (ippdrv->dedicated || (!ipp_is_m2m_cmd(cmd) && | ||
206 | !pm_runtime_suspended(ippdrv->dev))) | ||
207 | return true; | ||
208 | 183 | ||
209 | return false; | 184 | if (ippdrv->check_property && |
185 | ippdrv->check_property(ippdrv->dev, property)) | ||
186 | return -EINVAL; | ||
187 | |||
188 | return 0; | ||
210 | } | 189 | } |
211 | 190 | ||
212 | static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, | 191 | static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, |
@@ -214,62 +193,30 @@ static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, | |||
214 | { | 193 | { |
215 | struct exynos_drm_ippdrv *ippdrv; | 194 | struct exynos_drm_ippdrv *ippdrv; |
216 | u32 ipp_id = property->ipp_id; | 195 | u32 ipp_id = property->ipp_id; |
217 | 196 | int ret; | |
218 | DRM_DEBUG_KMS("ipp_id[%d]\n", ipp_id); | ||
219 | 197 | ||
220 | if (ipp_id) { | 198 | if (ipp_id) { |
221 | /* find ipp driver using idr */ | 199 | ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id); |
222 | ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, | 200 | if (!ippdrv) { |
223 | ipp_id); | 201 | DRM_DEBUG("ipp%d driver not found\n", ipp_id); |
224 | if (IS_ERR(ippdrv)) { | 202 | return ERR_PTR(-ENODEV); |
225 | DRM_ERROR("not found ipp%d driver.\n", ipp_id); | ||
226 | return ippdrv; | ||
227 | } | 203 | } |
228 | 204 | ||
229 | /* | 205 | ret = ipp_check_driver(ippdrv, property); |
230 | * WB, OUTPUT opertion not supported multi-operation. | 206 | if (ret < 0) { |
231 | * so, make dedicated state at set property ioctl. | 207 | DRM_DEBUG("ipp%d driver check error %d\n", ipp_id, ret); |
232 | * when ipp driver finished operations, clear dedicated flags. | 208 | return ERR_PTR(ret); |
233 | */ | ||
234 | if (ipp_check_dedicated(ippdrv, property->cmd)) { | ||
235 | DRM_ERROR("already used choose device.\n"); | ||
236 | return ERR_PTR(-EBUSY); | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * This is necessary to find correct device in ipp drivers. | ||
241 | * ipp drivers have different abilities, | ||
242 | * so need to check property. | ||
243 | */ | ||
244 | if (ippdrv->check_property && | ||
245 | ippdrv->check_property(ippdrv->dev, property)) { | ||
246 | DRM_ERROR("not support property.\n"); | ||
247 | return ERR_PTR(-EINVAL); | ||
248 | } | 209 | } |
249 | 210 | ||
250 | return ippdrv; | 211 | return ippdrv; |
251 | } else { | 212 | } else { |
252 | /* | ||
253 | * This case is search all ipp driver for finding. | ||
254 | * user application don't set ipp_id in this case, | ||
255 | * so ipp subsystem search correct driver in driver list. | ||
256 | */ | ||
257 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 213 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
258 | if (ipp_check_dedicated(ippdrv, property->cmd)) { | 214 | ret = ipp_check_driver(ippdrv, property); |
259 | DRM_DEBUG_KMS("used device.\n"); | 215 | if (ret == 0) |
260 | continue; | 216 | return ippdrv; |
261 | } | ||
262 | |||
263 | if (ippdrv->check_property && | ||
264 | ippdrv->check_property(ippdrv->dev, property)) { | ||
265 | DRM_DEBUG_KMS("not support property.\n"); | ||
266 | continue; | ||
267 | } | ||
268 | |||
269 | return ippdrv; | ||
270 | } | 217 | } |
271 | 218 | ||
272 | DRM_ERROR("not support ipp driver operations.\n"); | 219 | DRM_DEBUG("cannot find driver suitable for given property.\n"); |
273 | } | 220 | } |
274 | 221 | ||
275 | return ERR_PTR(-ENODEV); | 222 | return ERR_PTR(-ENODEV); |
@@ -308,8 +255,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, | |||
308 | struct drm_file *file) | 255 | struct drm_file *file) |
309 | { | 256 | { |
310 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 257 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
311 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; | 258 | struct device *dev = file_priv->ipp_dev; |
312 | struct device *dev = priv->dev; | ||
313 | struct ipp_context *ctx = get_ipp_context(dev); | 259 | struct ipp_context *ctx = get_ipp_context(dev); |
314 | struct drm_exynos_ipp_prop_list *prop_list = data; | 260 | struct drm_exynos_ipp_prop_list *prop_list = data; |
315 | struct exynos_drm_ippdrv *ippdrv; | 261 | struct exynos_drm_ippdrv *ippdrv; |
@@ -346,10 +292,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, | |||
346 | */ | 292 | */ |
347 | ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, | 293 | ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, |
348 | prop_list->ipp_id); | 294 | prop_list->ipp_id); |
349 | if (IS_ERR(ippdrv)) { | 295 | if (!ippdrv) { |
350 | DRM_ERROR("not found ipp%d driver.\n", | 296 | DRM_ERROR("not found ipp%d driver.\n", |
351 | prop_list->ipp_id); | 297 | prop_list->ipp_id); |
352 | return PTR_ERR(ippdrv); | 298 | return -ENODEV; |
353 | } | 299 | } |
354 | 300 | ||
355 | *prop_list = ippdrv->prop_list; | 301 | *prop_list = ippdrv->prop_list; |
@@ -432,7 +378,7 @@ static struct drm_exynos_ipp_event_work *ipp_create_event_work(void) | |||
432 | if (!event_work) | 378 | if (!event_work) |
433 | return ERR_PTR(-ENOMEM); | 379 | return ERR_PTR(-ENOMEM); |
434 | 380 | ||
435 | INIT_WORK((struct work_struct *)event_work, ipp_sched_event); | 381 | INIT_WORK(&event_work->work, ipp_sched_event); |
436 | 382 | ||
437 | return event_work; | 383 | return event_work; |
438 | } | 384 | } |
@@ -441,8 +387,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, | |||
441 | struct drm_file *file) | 387 | struct drm_file *file) |
442 | { | 388 | { |
443 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 389 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
444 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; | 390 | struct device *dev = file_priv->ipp_dev; |
445 | struct device *dev = priv->dev; | ||
446 | struct ipp_context *ctx = get_ipp_context(dev); | 391 | struct ipp_context *ctx = get_ipp_context(dev); |
447 | struct drm_exynos_ipp_property *property = data; | 392 | struct drm_exynos_ipp_property *property = data; |
448 | struct exynos_drm_ippdrv *ippdrv; | 393 | struct exynos_drm_ippdrv *ippdrv; |
@@ -489,19 +434,18 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, | |||
489 | if (!c_node) | 434 | if (!c_node) |
490 | return -ENOMEM; | 435 | return -ENOMEM; |
491 | 436 | ||
492 | /* create property id */ | 437 | ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node); |
493 | ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node, | 438 | if (ret < 0) { |
494 | &property->prop_id); | ||
495 | if (ret) { | ||
496 | DRM_ERROR("failed to create id.\n"); | 439 | DRM_ERROR("failed to create id.\n"); |
497 | goto err_clear; | 440 | goto err_clear; |
498 | } | 441 | } |
442 | property->prop_id = ret; | ||
499 | 443 | ||
500 | DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n", | 444 | DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n", |
501 | property->prop_id, property->cmd, (int)ippdrv); | 445 | property->prop_id, property->cmd, (int)ippdrv); |
502 | 446 | ||
503 | /* stored property information and ippdrv in private data */ | 447 | /* stored property information and ippdrv in private data */ |
504 | c_node->priv = priv; | 448 | c_node->dev = dev; |
505 | c_node->property = *property; | 449 | c_node->property = *property; |
506 | c_node->state = IPP_STATE_IDLE; | 450 | c_node->state = IPP_STATE_IDLE; |
507 | 451 | ||
@@ -534,7 +478,6 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, | |||
534 | INIT_LIST_HEAD(&c_node->mem_list[i]); | 478 | INIT_LIST_HEAD(&c_node->mem_list[i]); |
535 | 479 | ||
536 | INIT_LIST_HEAD(&c_node->event_list); | 480 | INIT_LIST_HEAD(&c_node->event_list); |
537 | list_splice_init(&priv->event_list, &c_node->event_list); | ||
538 | mutex_lock(&ippdrv->cmd_lock); | 481 | mutex_lock(&ippdrv->cmd_lock); |
539 | list_add_tail(&c_node->list, &ippdrv->cmd_list); | 482 | list_add_tail(&c_node->list, &ippdrv->cmd_list); |
540 | mutex_unlock(&ippdrv->cmd_lock); | 483 | mutex_unlock(&ippdrv->cmd_lock); |
@@ -577,42 +520,18 @@ static void ipp_clean_cmd_node(struct ipp_context *ctx, | |||
577 | kfree(c_node); | 520 | kfree(c_node); |
578 | } | 521 | } |
579 | 522 | ||
580 | static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) | 523 | static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) |
581 | { | 524 | { |
582 | struct drm_exynos_ipp_property *property = &c_node->property; | 525 | switch (c_node->property.cmd) { |
583 | struct drm_exynos_ipp_mem_node *m_node; | 526 | case IPP_CMD_WB: |
584 | struct list_head *head; | 527 | return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); |
585 | int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, }; | 528 | case IPP_CMD_OUTPUT: |
586 | 529 | return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]); | |
587 | for_each_ipp_ops(i) { | 530 | case IPP_CMD_M2M: |
588 | /* source/destination memory list */ | 531 | default: |
589 | head = &c_node->mem_list[i]; | 532 | return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) && |
590 | 533 | !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); | |
591 | /* find memory node entry */ | ||
592 | list_for_each_entry(m_node, head, list) { | ||
593 | DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n", | ||
594 | i ? "dst" : "src", count[i], (int)m_node); | ||
595 | count[i]++; | ||
596 | } | ||
597 | } | 534 | } |
598 | |||
599 | DRM_DEBUG_KMS("min[%d]max[%d]\n", | ||
600 | min(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST]), | ||
601 | max(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST])); | ||
602 | |||
603 | /* | ||
604 | * M2M operations should be need paired memory address. | ||
605 | * so, need to check minimum count about src, dst. | ||
606 | * other case not use paired memory, so use maximum count | ||
607 | */ | ||
608 | if (ipp_is_m2m_cmd(property->cmd)) | ||
609 | ret = min(count[EXYNOS_DRM_OPS_SRC], | ||
610 | count[EXYNOS_DRM_OPS_DST]); | ||
611 | else | ||
612 | ret = max(count[EXYNOS_DRM_OPS_SRC], | ||
613 | count[EXYNOS_DRM_OPS_DST]); | ||
614 | |||
615 | return ret; | ||
616 | } | 535 | } |
617 | 536 | ||
618 | static struct drm_exynos_ipp_mem_node | 537 | static struct drm_exynos_ipp_mem_node |
@@ -683,16 +602,14 @@ static struct drm_exynos_ipp_mem_node | |||
683 | struct drm_exynos_ipp_queue_buf *qbuf) | 602 | struct drm_exynos_ipp_queue_buf *qbuf) |
684 | { | 603 | { |
685 | struct drm_exynos_ipp_mem_node *m_node; | 604 | struct drm_exynos_ipp_mem_node *m_node; |
686 | struct drm_exynos_ipp_buf_info buf_info; | 605 | struct drm_exynos_ipp_buf_info *buf_info; |
687 | void *addr; | ||
688 | int i; | 606 | int i; |
689 | 607 | ||
690 | m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); | 608 | m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); |
691 | if (!m_node) | 609 | if (!m_node) |
692 | return ERR_PTR(-ENOMEM); | 610 | return ERR_PTR(-ENOMEM); |
693 | 611 | ||
694 | /* clear base address for error handling */ | 612 | buf_info = &m_node->buf_info; |
695 | memset(&buf_info, 0x0, sizeof(buf_info)); | ||
696 | 613 | ||
697 | /* operations, buffer id */ | 614 | /* operations, buffer id */ |
698 | m_node->ops_id = qbuf->ops_id; | 615 | m_node->ops_id = qbuf->ops_id; |
@@ -707,6 +624,8 @@ static struct drm_exynos_ipp_mem_node | |||
707 | 624 | ||
708 | /* get dma address by handle */ | 625 | /* get dma address by handle */ |
709 | if (qbuf->handle[i]) { | 626 | if (qbuf->handle[i]) { |
627 | dma_addr_t *addr; | ||
628 | |||
710 | addr = exynos_drm_gem_get_dma_addr(drm_dev, | 629 | addr = exynos_drm_gem_get_dma_addr(drm_dev, |
711 | qbuf->handle[i], file); | 630 | qbuf->handle[i], file); |
712 | if (IS_ERR(addr)) { | 631 | if (IS_ERR(addr)) { |
@@ -714,15 +633,14 @@ static struct drm_exynos_ipp_mem_node | |||
714 | goto err_clear; | 633 | goto err_clear; |
715 | } | 634 | } |
716 | 635 | ||
717 | buf_info.handles[i] = qbuf->handle[i]; | 636 | buf_info->handles[i] = qbuf->handle[i]; |
718 | buf_info.base[i] = *(dma_addr_t *) addr; | 637 | buf_info->base[i] = *addr; |
719 | DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%x]\n", | 638 | DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%lx]\n", i, |
720 | i, buf_info.base[i], (int)buf_info.handles[i]); | 639 | buf_info->base[i], buf_info->handles[i]); |
721 | } | 640 | } |
722 | } | 641 | } |
723 | 642 | ||
724 | m_node->filp = file; | 643 | m_node->filp = file; |
725 | m_node->buf_info = buf_info; | ||
726 | mutex_lock(&c_node->mem_lock); | 644 | mutex_lock(&c_node->mem_lock); |
727 | list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); | 645 | list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); |
728 | mutex_unlock(&c_node->mem_lock); | 646 | mutex_unlock(&c_node->mem_lock); |
@@ -930,8 +848,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, | |||
930 | struct drm_file *file) | 848 | struct drm_file *file) |
931 | { | 849 | { |
932 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 850 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
933 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; | 851 | struct device *dev = file_priv->ipp_dev; |
934 | struct device *dev = priv->dev; | ||
935 | struct ipp_context *ctx = get_ipp_context(dev); | 852 | struct ipp_context *ctx = get_ipp_context(dev); |
936 | struct drm_exynos_ipp_queue_buf *qbuf = data; | 853 | struct drm_exynos_ipp_queue_buf *qbuf = data; |
937 | struct drm_exynos_ipp_cmd_node *c_node; | 854 | struct drm_exynos_ipp_cmd_node *c_node; |
@@ -955,9 +872,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, | |||
955 | /* find command node */ | 872 | /* find command node */ |
956 | c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, | 873 | c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, |
957 | qbuf->prop_id); | 874 | qbuf->prop_id); |
958 | if (IS_ERR(c_node)) { | 875 | if (!c_node) { |
959 | DRM_ERROR("failed to get command node.\n"); | 876 | DRM_ERROR("failed to get command node.\n"); |
960 | return PTR_ERR(c_node); | 877 | return -ENODEV; |
961 | } | 878 | } |
962 | 879 | ||
963 | /* buffer control */ | 880 | /* buffer control */ |
@@ -1062,9 +979,8 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, | |||
1062 | struct drm_file *file) | 979 | struct drm_file *file) |
1063 | { | 980 | { |
1064 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 981 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1065 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; | ||
1066 | struct exynos_drm_ippdrv *ippdrv = NULL; | 982 | struct exynos_drm_ippdrv *ippdrv = NULL; |
1067 | struct device *dev = priv->dev; | 983 | struct device *dev = file_priv->ipp_dev; |
1068 | struct ipp_context *ctx = get_ipp_context(dev); | 984 | struct ipp_context *ctx = get_ipp_context(dev); |
1069 | struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data; | 985 | struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data; |
1070 | struct drm_exynos_ipp_cmd_work *cmd_work; | 986 | struct drm_exynos_ipp_cmd_work *cmd_work; |
@@ -1091,9 +1007,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, | |||
1091 | 1007 | ||
1092 | c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, | 1008 | c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, |
1093 | cmd_ctrl->prop_id); | 1009 | cmd_ctrl->prop_id); |
1094 | if (IS_ERR(c_node)) { | 1010 | if (!c_node) { |
1095 | DRM_ERROR("invalid command node list.\n"); | 1011 | DRM_ERROR("invalid command node list.\n"); |
1096 | return PTR_ERR(c_node); | 1012 | return -ENODEV; |
1097 | } | 1013 | } |
1098 | 1014 | ||
1099 | if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, | 1015 | if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, |
@@ -1198,7 +1114,6 @@ static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, | |||
1198 | /* reset h/w block */ | 1114 | /* reset h/w block */ |
1199 | if (ippdrv->reset && | 1115 | if (ippdrv->reset && |
1200 | ippdrv->reset(ippdrv->dev)) { | 1116 | ippdrv->reset(ippdrv->dev)) { |
1201 | DRM_ERROR("failed to reset.\n"); | ||
1202 | return -EINVAL; | 1117 | return -EINVAL; |
1203 | } | 1118 | } |
1204 | 1119 | ||
@@ -1216,30 +1131,24 @@ static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, | |||
1216 | /* set format */ | 1131 | /* set format */ |
1217 | if (ops->set_fmt) { | 1132 | if (ops->set_fmt) { |
1218 | ret = ops->set_fmt(ippdrv->dev, config->fmt); | 1133 | ret = ops->set_fmt(ippdrv->dev, config->fmt); |
1219 | if (ret) { | 1134 | if (ret) |
1220 | DRM_ERROR("not support format.\n"); | ||
1221 | return ret; | 1135 | return ret; |
1222 | } | ||
1223 | } | 1136 | } |
1224 | 1137 | ||
1225 | /* set transform for rotation, flip */ | 1138 | /* set transform for rotation, flip */ |
1226 | if (ops->set_transf) { | 1139 | if (ops->set_transf) { |
1227 | ret = ops->set_transf(ippdrv->dev, config->degree, | 1140 | ret = ops->set_transf(ippdrv->dev, config->degree, |
1228 | config->flip, &swap); | 1141 | config->flip, &swap); |
1229 | if (ret) { | 1142 | if (ret) |
1230 | DRM_ERROR("not support tranf.\n"); | 1143 | return ret; |
1231 | return -EINVAL; | ||
1232 | } | ||
1233 | } | 1144 | } |
1234 | 1145 | ||
1235 | /* set size */ | 1146 | /* set size */ |
1236 | if (ops->set_size) { | 1147 | if (ops->set_size) { |
1237 | ret = ops->set_size(ippdrv->dev, swap, &config->pos, | 1148 | ret = ops->set_size(ippdrv->dev, swap, &config->pos, |
1238 | &config->sz); | 1149 | &config->sz); |
1239 | if (ret) { | 1150 | if (ret) |
1240 | DRM_ERROR("not support size.\n"); | ||
1241 | return ret; | 1151 | return ret; |
1242 | } | ||
1243 | } | 1152 | } |
1244 | } | 1153 | } |
1245 | 1154 | ||
@@ -1283,11 +1192,6 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, | |||
1283 | 1192 | ||
1284 | m_node = list_first_entry(head, | 1193 | m_node = list_first_entry(head, |
1285 | struct drm_exynos_ipp_mem_node, list); | 1194 | struct drm_exynos_ipp_mem_node, list); |
1286 | if (!m_node) { | ||
1287 | DRM_ERROR("failed to get node.\n"); | ||
1288 | ret = -EFAULT; | ||
1289 | goto err_unlock; | ||
1290 | } | ||
1291 | 1195 | ||
1292 | DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node); | 1196 | DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node); |
1293 | 1197 | ||
@@ -1545,11 +1449,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1545 | 1449 | ||
1546 | m_node = list_first_entry(head, | 1450 | m_node = list_first_entry(head, |
1547 | struct drm_exynos_ipp_mem_node, list); | 1451 | struct drm_exynos_ipp_mem_node, list); |
1548 | if (!m_node) { | ||
1549 | DRM_ERROR("empty memory node.\n"); | ||
1550 | ret = -ENOMEM; | ||
1551 | goto err_mem_unlock; | ||
1552 | } | ||
1553 | 1452 | ||
1554 | tbuf_id[i] = m_node->buf_id; | 1453 | tbuf_id[i] = m_node->buf_id; |
1555 | DRM_DEBUG_KMS("%s buf_id[%d]\n", | 1454 | DRM_DEBUG_KMS("%s buf_id[%d]\n", |
@@ -1586,11 +1485,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, | |||
1586 | 1485 | ||
1587 | m_node = list_first_entry(head, | 1486 | m_node = list_first_entry(head, |
1588 | struct drm_exynos_ipp_mem_node, list); | 1487 | struct drm_exynos_ipp_mem_node, list); |
1589 | if (!m_node) { | ||
1590 | DRM_ERROR("empty memory node.\n"); | ||
1591 | ret = -ENOMEM; | ||
1592 | goto err_mem_unlock; | ||
1593 | } | ||
1594 | 1488 | ||
1595 | tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; | 1489 | tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; |
1596 | 1490 | ||
@@ -1704,21 +1598,17 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
1704 | 1598 | ||
1705 | /* get ipp driver entry */ | 1599 | /* get ipp driver entry */ |
1706 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 1600 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
1707 | u32 ipp_id; | ||
1708 | |||
1709 | ippdrv->drm_dev = drm_dev; | 1601 | ippdrv->drm_dev = drm_dev; |
1710 | 1602 | ||
1711 | ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv, | 1603 | ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv); |
1712 | &ipp_id); | 1604 | if (ret < 0) { |
1713 | if (ret || ipp_id == 0) { | ||
1714 | DRM_ERROR("failed to create id.\n"); | 1605 | DRM_ERROR("failed to create id.\n"); |
1715 | goto err; | 1606 | goto err; |
1716 | } | 1607 | } |
1608 | ippdrv->prop_list.ipp_id = ret; | ||
1717 | 1609 | ||
1718 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n", | 1610 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n", |
1719 | count++, (int)ippdrv, ipp_id); | 1611 | count++, (int)ippdrv, ret); |
1720 | |||
1721 | ippdrv->prop_list.ipp_id = ipp_id; | ||
1722 | 1612 | ||
1723 | /* store parent device for node */ | 1613 | /* store parent device for node */ |
1724 | ippdrv->parent_dev = dev; | 1614 | ippdrv->parent_dev = dev; |
@@ -1776,17 +1666,10 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev, | |||
1776 | struct drm_file *file) | 1666 | struct drm_file *file) |
1777 | { | 1667 | { |
1778 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1668 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1779 | struct exynos_drm_ipp_private *priv; | ||
1780 | |||
1781 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
1782 | if (!priv) | ||
1783 | return -ENOMEM; | ||
1784 | priv->dev = dev; | ||
1785 | file_priv->ipp_priv = priv; | ||
1786 | 1669 | ||
1787 | INIT_LIST_HEAD(&priv->event_list); | 1670 | file_priv->ipp_dev = dev; |
1788 | 1671 | ||
1789 | DRM_DEBUG_KMS("done priv[0x%x]\n", (int)priv); | 1672 | DRM_DEBUG_KMS("done priv[0x%x]\n", (int)dev); |
1790 | 1673 | ||
1791 | return 0; | 1674 | return 0; |
1792 | } | 1675 | } |
@@ -1795,13 +1678,12 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, | |||
1795 | struct drm_file *file) | 1678 | struct drm_file *file) |
1796 | { | 1679 | { |
1797 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1680 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1798 | struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; | ||
1799 | struct exynos_drm_ippdrv *ippdrv = NULL; | 1681 | struct exynos_drm_ippdrv *ippdrv = NULL; |
1800 | struct ipp_context *ctx = get_ipp_context(dev); | 1682 | struct ipp_context *ctx = get_ipp_context(dev); |
1801 | struct drm_exynos_ipp_cmd_node *c_node, *tc_node; | 1683 | struct drm_exynos_ipp_cmd_node *c_node, *tc_node; |
1802 | int count = 0; | 1684 | int count = 0; |
1803 | 1685 | ||
1804 | DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv); | 1686 | DRM_DEBUG_KMS("for priv[0x%x]\n", (int)file_priv->ipp_dev); |
1805 | 1687 | ||
1806 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { | 1688 | list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { |
1807 | mutex_lock(&ippdrv->cmd_lock); | 1689 | mutex_lock(&ippdrv->cmd_lock); |
@@ -1810,7 +1692,7 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, | |||
1810 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", | 1692 | DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", |
1811 | count++, (int)ippdrv); | 1693 | count++, (int)ippdrv); |
1812 | 1694 | ||
1813 | if (c_node->priv == priv) { | 1695 | if (c_node->dev == file_priv->ipp_dev) { |
1814 | /* | 1696 | /* |
1815 | * userland goto unnormal state. process killed. | 1697 | * userland goto unnormal state. process killed. |
1816 | * and close the file. | 1698 | * and close the file. |
@@ -1832,7 +1714,6 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, | |||
1832 | mutex_unlock(&ippdrv->cmd_lock); | 1714 | mutex_unlock(&ippdrv->cmd_lock); |
1833 | } | 1715 | } |
1834 | 1716 | ||
1835 | kfree(priv); | ||
1836 | return; | 1717 | return; |
1837 | } | 1718 | } |
1838 | 1719 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h index 7aaeaae757c2..6f48d62aeb30 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.h | |||
@@ -48,7 +48,7 @@ struct drm_exynos_ipp_cmd_work { | |||
48 | /* | 48 | /* |
49 | * A structure of command node. | 49 | * A structure of command node. |
50 | * | 50 | * |
51 | * @priv: IPP private information. | 51 | * @dev: IPP device. |
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. |
@@ -64,7 +64,7 @@ struct drm_exynos_ipp_cmd_work { | |||
64 | * @state: state of command node. | 64 | * @state: state of command node. |
65 | */ | 65 | */ |
66 | struct drm_exynos_ipp_cmd_node { | 66 | struct drm_exynos_ipp_cmd_node { |
67 | struct exynos_drm_ipp_private *priv; | 67 | struct device *dev; |
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]; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index f01fbb6dc1f0..55af6b41c1df 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c | |||
@@ -691,6 +691,7 @@ static const struct of_device_id exynos_rotator_match[] = { | |||
691 | }, | 691 | }, |
692 | {}, | 692 | {}, |
693 | }; | 693 | }; |
694 | MODULE_DEVICE_TABLE(of, exynos_rotator_match); | ||
694 | 695 | ||
695 | static int rotator_probe(struct platform_device *pdev) | 696 | static int rotator_probe(struct platform_device *pdev) |
696 | { | 697 | { |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 81df11d57673..562966db2aa1 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -84,6 +84,7 @@ struct hdmi_resources { | |||
84 | struct clk *sclk_hdmiphy; | 84 | struct clk *sclk_hdmiphy; |
85 | struct clk *mout_hdmi; | 85 | struct clk *mout_hdmi; |
86 | struct regulator_bulk_data *regul_bulk; | 86 | struct regulator_bulk_data *regul_bulk; |
87 | struct regulator *reg_hdmi_en; | ||
87 | int regul_count; | 88 | int regul_count; |
88 | }; | 89 | }; |
89 | 90 | ||
@@ -592,6 +593,13 @@ static struct hdmi_driver_data exynos4212_hdmi_driver_data = { | |||
592 | .is_apb_phy = 0, | 593 | .is_apb_phy = 0, |
593 | }; | 594 | }; |
594 | 595 | ||
596 | static struct hdmi_driver_data exynos4210_hdmi_driver_data = { | ||
597 | .type = HDMI_TYPE13, | ||
598 | .phy_confs = hdmiphy_v13_configs, | ||
599 | .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), | ||
600 | .is_apb_phy = 0, | ||
601 | }; | ||
602 | |||
595 | static struct hdmi_driver_data exynos5_hdmi_driver_data = { | 603 | static struct hdmi_driver_data exynos5_hdmi_driver_data = { |
596 | .type = HDMI_TYPE14, | 604 | .type = HDMI_TYPE14, |
597 | .phy_confs = hdmiphy_v13_configs, | 605 | .phy_confs = hdmiphy_v13_configs, |
@@ -1241,14 +1249,13 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) | |||
1241 | 1249 | ||
1242 | static void hdmi_audio_init(struct hdmi_context *hdata) | 1250 | static void hdmi_audio_init(struct hdmi_context *hdata) |
1243 | { | 1251 | { |
1244 | u32 sample_rate, bits_per_sample, frame_size_code; | 1252 | u32 sample_rate, bits_per_sample; |
1245 | u32 data_num, bit_ch, sample_frq; | 1253 | u32 data_num, bit_ch, sample_frq; |
1246 | u32 val; | 1254 | u32 val; |
1247 | u8 acr[7]; | 1255 | u8 acr[7]; |
1248 | 1256 | ||
1249 | sample_rate = 44100; | 1257 | sample_rate = 44100; |
1250 | bits_per_sample = 16; | 1258 | bits_per_sample = 16; |
1251 | frame_size_code = 0; | ||
1252 | 1259 | ||
1253 | switch (bits_per_sample) { | 1260 | switch (bits_per_sample) { |
1254 | case 20: | 1261 | case 20: |
@@ -2168,7 +2175,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) | |||
2168 | struct device *dev = hdata->dev; | 2175 | struct device *dev = hdata->dev; |
2169 | struct hdmi_resources *res = &hdata->res; | 2176 | struct hdmi_resources *res = &hdata->res; |
2170 | static char *supply[] = { | 2177 | static char *supply[] = { |
2171 | "hdmi-en", | ||
2172 | "vdd", | 2178 | "vdd", |
2173 | "vdd_osc", | 2179 | "vdd_osc", |
2174 | "vdd_pll", | 2180 | "vdd_pll", |
@@ -2228,6 +2234,20 @@ static int hdmi_resources_init(struct hdmi_context *hdata) | |||
2228 | } | 2234 | } |
2229 | res->regul_count = ARRAY_SIZE(supply); | 2235 | res->regul_count = ARRAY_SIZE(supply); |
2230 | 2236 | ||
2237 | res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en"); | ||
2238 | if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) { | ||
2239 | DRM_ERROR("failed to get hdmi-en regulator\n"); | ||
2240 | return PTR_ERR(res->reg_hdmi_en); | ||
2241 | } | ||
2242 | if (!IS_ERR(res->reg_hdmi_en)) { | ||
2243 | ret = regulator_enable(res->reg_hdmi_en); | ||
2244 | if (ret) { | ||
2245 | DRM_ERROR("failed to enable hdmi-en regulator\n"); | ||
2246 | return ret; | ||
2247 | } | ||
2248 | } else | ||
2249 | res->reg_hdmi_en = NULL; | ||
2250 | |||
2231 | return ret; | 2251 | return ret; |
2232 | fail: | 2252 | fail: |
2233 | DRM_ERROR("HDMI resource init - failed\n"); | 2253 | DRM_ERROR("HDMI resource init - failed\n"); |
@@ -2263,6 +2283,9 @@ static struct of_device_id hdmi_match_types[] = { | |||
2263 | .compatible = "samsung,exynos5-hdmi", | 2283 | .compatible = "samsung,exynos5-hdmi", |
2264 | .data = &exynos5_hdmi_driver_data, | 2284 | .data = &exynos5_hdmi_driver_data, |
2265 | }, { | 2285 | }, { |
2286 | .compatible = "samsung,exynos4210-hdmi", | ||
2287 | .data = &exynos4210_hdmi_driver_data, | ||
2288 | }, { | ||
2266 | .compatible = "samsung,exynos4212-hdmi", | 2289 | .compatible = "samsung,exynos4212-hdmi", |
2267 | .data = &exynos4212_hdmi_driver_data, | 2290 | .data = &exynos4212_hdmi_driver_data, |
2268 | }, { | 2291 | }, { |
@@ -2272,6 +2295,7 @@ static struct of_device_id hdmi_match_types[] = { | |||
2272 | /* end node */ | 2295 | /* end node */ |
2273 | } | 2296 | } |
2274 | }; | 2297 | }; |
2298 | MODULE_DEVICE_TABLE (of, hdmi_match_types); | ||
2275 | 2299 | ||
2276 | static int hdmi_bind(struct device *dev, struct device *master, void *data) | 2300 | static int hdmi_bind(struct device *dev, struct device *master, void *data) |
2277 | { | 2301 | { |
@@ -2494,7 +2518,11 @@ static int hdmi_remove(struct platform_device *pdev) | |||
2494 | 2518 | ||
2495 | cancel_delayed_work_sync(&hdata->hotplug_work); | 2519 | cancel_delayed_work_sync(&hdata->hotplug_work); |
2496 | 2520 | ||
2497 | put_device(&hdata->hdmiphy_port->dev); | 2521 | if (hdata->res.reg_hdmi_en) |
2522 | regulator_disable(hdata->res.reg_hdmi_en); | ||
2523 | |||
2524 | if (hdata->hdmiphy_port) | ||
2525 | put_device(&hdata->hdmiphy_port->dev); | ||
2498 | put_device(&hdata->ddc_adpt->dev); | 2526 | put_device(&hdata->ddc_adpt->dev); |
2499 | 2527 | ||
2500 | pm_runtime_disable(&pdev->dev); | 2528 | pm_runtime_disable(&pdev->dev); |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 7529946d0a74..e8b4ec84b312 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -76,7 +76,7 @@ struct mixer_resources { | |||
76 | struct clk *vp; | 76 | struct clk *vp; |
77 | struct clk *sclk_mixer; | 77 | struct clk *sclk_mixer; |
78 | struct clk *sclk_hdmi; | 78 | struct clk *sclk_hdmi; |
79 | struct clk *sclk_dac; | 79 | struct clk *mout_mixer; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | enum mixer_version_id { | 82 | enum mixer_version_id { |
@@ -93,6 +93,7 @@ struct mixer_context { | |||
93 | bool interlace; | 93 | bool interlace; |
94 | bool powered; | 94 | bool powered; |
95 | bool vp_enabled; | 95 | bool vp_enabled; |
96 | bool has_sclk; | ||
96 | u32 int_en; | 97 | u32 int_en; |
97 | 98 | ||
98 | struct mutex mixer_mutex; | 99 | struct mutex mixer_mutex; |
@@ -106,6 +107,7 @@ struct mixer_context { | |||
106 | struct mixer_drv_data { | 107 | struct mixer_drv_data { |
107 | enum mixer_version_id version; | 108 | enum mixer_version_id version; |
108 | bool is_vp_enabled; | 109 | bool is_vp_enabled; |
110 | bool has_sclk; | ||
109 | }; | 111 | }; |
110 | 112 | ||
111 | static const u8 filter_y_horiz_tap8[] = { | 113 | static const u8 filter_y_horiz_tap8[] = { |
@@ -363,6 +365,11 @@ static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable) | |||
363 | vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); | 365 | vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); |
364 | mixer_reg_writemask(res, MXR_CFG, val, | 366 | mixer_reg_writemask(res, MXR_CFG, val, |
365 | MXR_CFG_VP_ENABLE); | 367 | MXR_CFG_VP_ENABLE); |
368 | |||
369 | /* control blending of graphic layer 0 */ | ||
370 | mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val, | ||
371 | MXR_GRP_CFG_BLEND_PRE_MUL | | ||
372 | MXR_GRP_CFG_PIXEL_BLEND_EN); | ||
366 | } | 373 | } |
367 | break; | 374 | break; |
368 | } | 375 | } |
@@ -809,19 +816,23 @@ static int vp_resources_init(struct mixer_context *mixer_ctx) | |||
809 | dev_err(dev, "failed to get clock 'vp'\n"); | 816 | dev_err(dev, "failed to get clock 'vp'\n"); |
810 | return -ENODEV; | 817 | return -ENODEV; |
811 | } | 818 | } |
812 | mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); | ||
813 | if (IS_ERR(mixer_res->sclk_mixer)) { | ||
814 | dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | ||
815 | return -ENODEV; | ||
816 | } | ||
817 | mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac"); | ||
818 | if (IS_ERR(mixer_res->sclk_dac)) { | ||
819 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); | ||
820 | return -ENODEV; | ||
821 | } | ||
822 | 819 | ||
823 | if (mixer_res->sclk_hdmi) | 820 | if (mixer_ctx->has_sclk) { |
824 | clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); | 821 | mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); |
822 | if (IS_ERR(mixer_res->sclk_mixer)) { | ||
823 | dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | ||
824 | return -ENODEV; | ||
825 | } | ||
826 | mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer"); | ||
827 | if (IS_ERR(mixer_res->mout_mixer)) { | ||
828 | dev_err(dev, "failed to get clock 'mout_mixer'\n"); | ||
829 | return -ENODEV; | ||
830 | } | ||
831 | |||
832 | if (mixer_res->sclk_hdmi && mixer_res->mout_mixer) | ||
833 | clk_set_parent(mixer_res->mout_mixer, | ||
834 | mixer_res->sclk_hdmi); | ||
835 | } | ||
825 | 836 | ||
826 | res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1); | 837 | res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1); |
827 | if (res == NULL) { | 838 | if (res == NULL) { |
@@ -1082,7 +1093,8 @@ static void mixer_poweron(struct exynos_drm_manager *mgr) | |||
1082 | clk_prepare_enable(res->mixer); | 1093 | clk_prepare_enable(res->mixer); |
1083 | if (ctx->vp_enabled) { | 1094 | if (ctx->vp_enabled) { |
1084 | clk_prepare_enable(res->vp); | 1095 | clk_prepare_enable(res->vp); |
1085 | clk_prepare_enable(res->sclk_mixer); | 1096 | if (ctx->has_sclk) |
1097 | clk_prepare_enable(res->sclk_mixer); | ||
1086 | } | 1098 | } |
1087 | 1099 | ||
1088 | mutex_lock(&ctx->mixer_mutex); | 1100 | mutex_lock(&ctx->mixer_mutex); |
@@ -1121,7 +1133,8 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr) | |||
1121 | clk_disable_unprepare(res->mixer); | 1133 | clk_disable_unprepare(res->mixer); |
1122 | if (ctx->vp_enabled) { | 1134 | if (ctx->vp_enabled) { |
1123 | clk_disable_unprepare(res->vp); | 1135 | clk_disable_unprepare(res->vp); |
1124 | clk_disable_unprepare(res->sclk_mixer); | 1136 | if (ctx->has_sclk) |
1137 | clk_disable_unprepare(res->sclk_mixer); | ||
1125 | } | 1138 | } |
1126 | 1139 | ||
1127 | pm_runtime_put_sync(ctx->dev); | 1140 | pm_runtime_put_sync(ctx->dev); |
@@ -1189,9 +1202,15 @@ static struct mixer_drv_data exynos5250_mxr_drv_data = { | |||
1189 | .is_vp_enabled = 0, | 1202 | .is_vp_enabled = 0, |
1190 | }; | 1203 | }; |
1191 | 1204 | ||
1205 | static struct mixer_drv_data exynos4212_mxr_drv_data = { | ||
1206 | .version = MXR_VER_0_0_0_16, | ||
1207 | .is_vp_enabled = 1, | ||
1208 | }; | ||
1209 | |||
1192 | static struct mixer_drv_data exynos4210_mxr_drv_data = { | 1210 | static struct mixer_drv_data exynos4210_mxr_drv_data = { |
1193 | .version = MXR_VER_0_0_0_16, | 1211 | .version = MXR_VER_0_0_0_16, |
1194 | .is_vp_enabled = 1, | 1212 | .is_vp_enabled = 1, |
1213 | .has_sclk = 1, | ||
1195 | }; | 1214 | }; |
1196 | 1215 | ||
1197 | static struct platform_device_id mixer_driver_types[] = { | 1216 | static struct platform_device_id mixer_driver_types[] = { |
@@ -1208,6 +1227,12 @@ static struct platform_device_id mixer_driver_types[] = { | |||
1208 | 1227 | ||
1209 | static struct of_device_id mixer_match_types[] = { | 1228 | static struct of_device_id mixer_match_types[] = { |
1210 | { | 1229 | { |
1230 | .compatible = "samsung,exynos4210-mixer", | ||
1231 | .data = &exynos4210_mxr_drv_data, | ||
1232 | }, { | ||
1233 | .compatible = "samsung,exynos4212-mixer", | ||
1234 | .data = &exynos4212_mxr_drv_data, | ||
1235 | }, { | ||
1211 | .compatible = "samsung,exynos5-mixer", | 1236 | .compatible = "samsung,exynos5-mixer", |
1212 | .data = &exynos5250_mxr_drv_data, | 1237 | .data = &exynos5250_mxr_drv_data, |
1213 | }, { | 1238 | }, { |
@@ -1220,6 +1245,7 @@ static struct of_device_id mixer_match_types[] = { | |||
1220 | /* end node */ | 1245 | /* end node */ |
1221 | } | 1246 | } |
1222 | }; | 1247 | }; |
1248 | MODULE_DEVICE_TABLE(of, mixer_match_types); | ||
1223 | 1249 | ||
1224 | static int mixer_bind(struct device *dev, struct device *manager, void *data) | 1250 | static int mixer_bind(struct device *dev, struct device *manager, void *data) |
1225 | { | 1251 | { |
@@ -1251,6 +1277,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) | |||
1251 | ctx->pdev = pdev; | 1277 | ctx->pdev = pdev; |
1252 | ctx->dev = dev; | 1278 | ctx->dev = dev; |
1253 | ctx->vp_enabled = drv->is_vp_enabled; | 1279 | ctx->vp_enabled = drv->is_vp_enabled; |
1280 | ctx->has_sclk = drv->has_sclk; | ||
1254 | ctx->mxr_ver = drv->version; | 1281 | ctx->mxr_ver = drv->version; |
1255 | init_waitqueue_head(&ctx->wait_vsync_queue); | 1282 | init_waitqueue_head(&ctx->wait_vsync_queue); |
1256 | atomic_set(&ctx->wait_vsync_event, 0); | 1283 | atomic_set(&ctx->wait_vsync_event, 0); |
diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index b0393209679b..eaad58b5be4a 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h | |||
@@ -19,6 +19,7 @@ | |||
19 | /* VIDCON0 */ | 19 | /* VIDCON0 */ |
20 | 20 | ||
21 | #define VIDCON0 0x00 | 21 | #define VIDCON0 0x00 |
22 | #define VIDCON0_DSI_EN (1 << 30) | ||
22 | #define VIDCON0_INTERLACE (1 << 29) | 23 | #define VIDCON0_INTERLACE (1 << 29) |
23 | #define VIDCON0_VIDOUT_MASK (0x7 << 26) | 24 | #define VIDCON0_VIDOUT_MASK (0x7 << 26) |
24 | #define VIDCON0_VIDOUT_SHIFT 26 | 25 | #define VIDCON0_VIDOUT_SHIFT 26 |
@@ -355,7 +356,7 @@ | |||
355 | #define VIDINTCON0_INT_ENABLE (1 << 0) | 356 | #define VIDINTCON0_INT_ENABLE (1 << 0) |
356 | 357 | ||
357 | #define VIDINTCON1 0x134 | 358 | #define VIDINTCON1 0x134 |
358 | #define VIDINTCON1_INT_I180 (1 << 2) | 359 | #define VIDINTCON1_INT_I80 (1 << 2) |
359 | #define VIDINTCON1_INT_FRAME (1 << 1) | 360 | #define VIDINTCON1_INT_FRAME (1 << 1) |
360 | #define VIDINTCON1_INT_FIFO (1 << 0) | 361 | #define VIDINTCON1_INT_FIFO (1 << 0) |
361 | 362 | ||