diff options
24 files changed, 324 insertions, 548 deletions
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 3b323f1e0475..2ad146bbf4f5 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. | 4 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. |
5 | 5 | ||
6 | exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \ | 6 | exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \ |
7 | exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o | 7 | exynos_drm_gem.o exynos_drm_plane.o |
8 | 8 | ||
9 | exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o | 9 | exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o |
10 | exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o | 10 | exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o |
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 82c95c34447f..94529aa82339 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c | |||
@@ -265,7 +265,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, | |||
265 | unsigned long val; | 265 | unsigned long val; |
266 | 266 | ||
267 | val = readl(ctx->addr + DECON_WINCONx(win)); | 267 | val = readl(ctx->addr + DECON_WINCONx(win)); |
268 | val &= ~WINCONx_BPPMODE_MASK; | 268 | val &= WINCONx_ENWIN_F; |
269 | 269 | ||
270 | switch (fb->format->format) { | 270 | switch (fb->format->format) { |
271 | case DRM_FORMAT_XRGB1555: | 271 | case DRM_FORMAT_XRGB1555: |
@@ -356,8 +356,8 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, | |||
356 | writel(val, ctx->addr + DECON_VIDOSDxB(win)); | 356 | writel(val, ctx->addr + DECON_VIDOSDxB(win)); |
357 | } | 357 | } |
358 | 358 | ||
359 | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | | 359 | val = VIDOSD_Wx_ALPHA_R_F(0xff) | VIDOSD_Wx_ALPHA_G_F(0xff) | |
360 | VIDOSD_Wx_ALPHA_B_F(0x0); | 360 | VIDOSD_Wx_ALPHA_B_F(0xff); |
361 | writel(val, ctx->addr + DECON_VIDOSDxC(win)); | 361 | writel(val, ctx->addr + DECON_VIDOSDxC(win)); |
362 | 362 | ||
363 | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | | 363 | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | |
@@ -673,6 +673,8 @@ err: | |||
673 | static const struct dev_pm_ops exynos5433_decon_pm_ops = { | 673 | static const struct dev_pm_ops exynos5433_decon_pm_ops = { |
674 | SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume, | 674 | SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume, |
675 | NULL) | 675 | NULL) |
676 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
677 | pm_runtime_force_resume) | ||
676 | }; | 678 | }; |
677 | 679 | ||
678 | static const struct of_device_id exynos5433_decon_driver_dt_match[] = { | 680 | static const struct of_device_id exynos5433_decon_driver_dt_match[] = { |
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 3931d5e33fe0..88cbd000eb09 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c | |||
@@ -832,6 +832,8 @@ static int exynos7_decon_resume(struct device *dev) | |||
832 | static const struct dev_pm_ops exynos7_decon_pm_ops = { | 832 | static const struct dev_pm_ops exynos7_decon_pm_ops = { |
833 | SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume, | 833 | SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume, |
834 | NULL) | 834 | NULL) |
835 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
836 | pm_runtime_force_resume) | ||
835 | }; | 837 | }; |
836 | 838 | ||
837 | struct platform_driver decon_driver = { | 839 | struct platform_driver decon_driver = { |
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index af7ab1ceb50f..c8449ae4f4fe 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/of_graph.h> | 17 | #include <linux/of_graph.h> |
18 | #include <linux/component.h> | 18 | #include <linux/component.h> |
19 | #include <linux/pm_runtime.h> | ||
19 | #include <video/of_display_timing.h> | 20 | #include <video/of_display_timing.h> |
20 | #include <video/of_videomode.h> | 21 | #include <video/of_videomode.h> |
21 | #include <video/videomode.h> | 22 | #include <video/videomode.h> |
@@ -278,6 +279,8 @@ static int exynos_dp_resume(struct device *dev) | |||
278 | 279 | ||
279 | static const struct dev_pm_ops exynos_dp_pm_ops = { | 280 | static const struct dev_pm_ops exynos_dp_pm_ops = { |
280 | SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) | 281 | SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) |
282 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
283 | pm_runtime_force_resume) | ||
281 | }; | 284 | }; |
282 | 285 | ||
283 | static const struct of_device_id exynos_dp_match[] = { | 286 | static const struct of_device_id exynos_dp_match[] = { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c deleted file mode 100644 index b0c0621fcdf7..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ /dev/null | |||
@@ -1,119 +0,0 @@ | |||
1 | /* exynos_drm_core.c | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * Author: | ||
5 | * Inki Dae <inki.dae@samsung.com> | ||
6 | * Joonyoung Shim <jy0922.shim@samsung.com> | ||
7 | * Seung-Woo Kim <sw0312.kim@samsung.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <drm/drmP.h> | ||
16 | |||
17 | #include "exynos_drm_drv.h" | ||
18 | #include "exynos_drm_crtc.h" | ||
19 | |||
20 | static LIST_HEAD(exynos_drm_subdrv_list); | ||
21 | |||
22 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) | ||
23 | { | ||
24 | if (!subdrv) | ||
25 | return -EINVAL; | ||
26 | |||
27 | list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); | ||
28 | |||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) | ||
33 | { | ||
34 | if (!subdrv) | ||
35 | return -EINVAL; | ||
36 | |||
37 | list_del(&subdrv->list); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | int exynos_drm_device_subdrv_probe(struct drm_device *dev) | ||
43 | { | ||
44 | struct exynos_drm_subdrv *subdrv, *n; | ||
45 | int err; | ||
46 | |||
47 | if (!dev) | ||
48 | return -EINVAL; | ||
49 | |||
50 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { | ||
51 | if (subdrv->probe) { | ||
52 | subdrv->drm_dev = dev; | ||
53 | |||
54 | /* | ||
55 | * this probe callback would be called by sub driver | ||
56 | * after setting of all resources to this sub driver, | ||
57 | * such as clock, irq and register map are done. | ||
58 | */ | ||
59 | err = subdrv->probe(dev, subdrv->dev); | ||
60 | if (err) { | ||
61 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); | ||
62 | list_del(&subdrv->list); | ||
63 | continue; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int exynos_drm_device_subdrv_remove(struct drm_device *dev) | ||
72 | { | ||
73 | struct exynos_drm_subdrv *subdrv; | ||
74 | |||
75 | if (!dev) { | ||
76 | WARN(1, "Unexpected drm device unregister!\n"); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { | ||
81 | if (subdrv->remove) | ||
82 | subdrv->remove(dev, subdrv->dev); | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) | ||
89 | { | ||
90 | struct exynos_drm_subdrv *subdrv; | ||
91 | int ret; | ||
92 | |||
93 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { | ||
94 | if (subdrv->open) { | ||
95 | ret = subdrv->open(dev, subdrv->dev, file); | ||
96 | if (ret) | ||
97 | goto err; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | |||
103 | err: | ||
104 | list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) { | ||
105 | if (subdrv->close) | ||
106 | subdrv->close(dev, subdrv->dev, file); | ||
107 | } | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) | ||
112 | { | ||
113 | struct exynos_drm_subdrv *subdrv; | ||
114 | |||
115 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { | ||
116 | if (subdrv->close) | ||
117 | subdrv->close(dev, subdrv->dev, file); | ||
118 | } | ||
119 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index a81b4a5e24a7..b599f74692e5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -55,8 +55,7 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) | |||
55 | return -ENOMEM; | 55 | return -ENOMEM; |
56 | 56 | ||
57 | file->driver_priv = file_priv; | 57 | file->driver_priv = file_priv; |
58 | 58 | ret = g2d_open(dev, file); | |
59 | ret = exynos_drm_subdrv_open(dev, file); | ||
60 | if (ret) | 59 | if (ret) |
61 | goto err_file_priv_free; | 60 | goto err_file_priv_free; |
62 | 61 | ||
@@ -70,7 +69,7 @@ err_file_priv_free: | |||
70 | 69 | ||
71 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) | 70 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) |
72 | { | 71 | { |
73 | exynos_drm_subdrv_close(dev, file); | 72 | g2d_close(dev, file); |
74 | kfree(file->driver_priv); | 73 | kfree(file->driver_priv); |
75 | file->driver_priv = NULL; | 74 | file->driver_priv = NULL; |
76 | } | 75 | } |
@@ -147,13 +146,12 @@ static struct drm_driver exynos_drm_driver = { | |||
147 | .minor = DRIVER_MINOR, | 146 | .minor = DRIVER_MINOR, |
148 | }; | 147 | }; |
149 | 148 | ||
150 | #ifdef CONFIG_PM_SLEEP | ||
151 | static int exynos_drm_suspend(struct device *dev) | 149 | static int exynos_drm_suspend(struct device *dev) |
152 | { | 150 | { |
153 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 151 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
154 | struct exynos_drm_private *private; | 152 | struct exynos_drm_private *private; |
155 | 153 | ||
156 | if (pm_runtime_suspended(dev) || !drm_dev) | 154 | if (!drm_dev) |
157 | return 0; | 155 | return 0; |
158 | 156 | ||
159 | private = drm_dev->dev_private; | 157 | private = drm_dev->dev_private; |
@@ -170,25 +168,23 @@ static int exynos_drm_suspend(struct device *dev) | |||
170 | return 0; | 168 | return 0; |
171 | } | 169 | } |
172 | 170 | ||
173 | static int exynos_drm_resume(struct device *dev) | 171 | static void exynos_drm_resume(struct device *dev) |
174 | { | 172 | { |
175 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 173 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
176 | struct exynos_drm_private *private; | 174 | struct exynos_drm_private *private; |
177 | 175 | ||
178 | if (pm_runtime_suspended(dev) || !drm_dev) | 176 | if (!drm_dev) |
179 | return 0; | 177 | return; |
180 | 178 | ||
181 | private = drm_dev->dev_private; | 179 | private = drm_dev->dev_private; |
182 | drm_atomic_helper_resume(drm_dev, private->suspend_state); | 180 | drm_atomic_helper_resume(drm_dev, private->suspend_state); |
183 | exynos_drm_fbdev_resume(drm_dev); | 181 | exynos_drm_fbdev_resume(drm_dev); |
184 | drm_kms_helper_poll_enable(drm_dev); | 182 | drm_kms_helper_poll_enable(drm_dev); |
185 | |||
186 | return 0; | ||
187 | } | 183 | } |
188 | #endif | ||
189 | 184 | ||
190 | static const struct dev_pm_ops exynos_drm_pm_ops = { | 185 | static const struct dev_pm_ops exynos_drm_pm_ops = { |
191 | SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume) | 186 | .prepare = exynos_drm_suspend, |
187 | .complete = exynos_drm_resume, | ||
192 | }; | 188 | }; |
193 | 189 | ||
194 | /* forward declaration */ | 190 | /* forward declaration */ |
@@ -240,6 +236,7 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = { | |||
240 | DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE | 236 | DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE |
241 | }, { | 237 | }, { |
242 | DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D), | 238 | DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D), |
239 | DRM_COMPONENT_DRIVER | ||
243 | }, { | 240 | }, { |
244 | DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC), | 241 | DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC), |
245 | DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE, | 242 | DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE, |
@@ -376,11 +373,6 @@ static int exynos_drm_bind(struct device *dev) | |||
376 | if (ret) | 373 | if (ret) |
377 | goto err_unbind_all; | 374 | goto err_unbind_all; |
378 | 375 | ||
379 | /* Probe non kms sub drivers and virtual display driver. */ | ||
380 | ret = exynos_drm_device_subdrv_probe(drm); | ||
381 | if (ret) | ||
382 | goto err_unbind_all; | ||
383 | |||
384 | drm_mode_config_reset(drm); | 376 | drm_mode_config_reset(drm); |
385 | 377 | ||
386 | /* | 378 | /* |
@@ -411,7 +403,6 @@ err_cleanup_fbdev: | |||
411 | exynos_drm_fbdev_fini(drm); | 403 | exynos_drm_fbdev_fini(drm); |
412 | err_cleanup_poll: | 404 | err_cleanup_poll: |
413 | drm_kms_helper_poll_fini(drm); | 405 | drm_kms_helper_poll_fini(drm); |
414 | exynos_drm_device_subdrv_remove(drm); | ||
415 | err_unbind_all: | 406 | err_unbind_all: |
416 | component_unbind_all(drm->dev, drm); | 407 | component_unbind_all(drm->dev, drm); |
417 | err_mode_config_cleanup: | 408 | err_mode_config_cleanup: |
@@ -420,7 +411,7 @@ err_mode_config_cleanup: | |||
420 | err_free_private: | 411 | err_free_private: |
421 | kfree(private); | 412 | kfree(private); |
422 | err_free_drm: | 413 | err_free_drm: |
423 | drm_dev_unref(drm); | 414 | drm_dev_put(drm); |
424 | 415 | ||
425 | return ret; | 416 | return ret; |
426 | } | 417 | } |
@@ -431,8 +422,6 @@ static void exynos_drm_unbind(struct device *dev) | |||
431 | 422 | ||
432 | drm_dev_unregister(drm); | 423 | drm_dev_unregister(drm); |
433 | 424 | ||
434 | exynos_drm_device_subdrv_remove(drm); | ||
435 | |||
436 | exynos_drm_fbdev_fini(drm); | 425 | exynos_drm_fbdev_fini(drm); |
437 | drm_kms_helper_poll_fini(drm); | 426 | drm_kms_helper_poll_fini(drm); |
438 | 427 | ||
@@ -444,7 +433,7 @@ static void exynos_drm_unbind(struct device *dev) | |||
444 | drm->dev_private = NULL; | 433 | drm->dev_private = NULL; |
445 | dev_set_drvdata(dev, NULL); | 434 | dev_set_drvdata(dev, NULL); |
446 | 435 | ||
447 | drm_dev_unref(drm); | 436 | drm_dev_put(drm); |
448 | } | 437 | } |
449 | 438 | ||
450 | static const struct component_master_ops exynos_drm_ops = { | 439 | static const struct component_master_ops exynos_drm_ops = { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 0f6d079a55c9..c737c4bd2c19 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -179,17 +179,13 @@ static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc, | |||
179 | crtc->pipe_clk->enable(crtc->pipe_clk, enable); | 179 | crtc->pipe_clk->enable(crtc->pipe_clk, enable); |
180 | } | 180 | } |
181 | 181 | ||
182 | struct exynos_drm_g2d_private { | 182 | struct drm_exynos_file_private { |
183 | struct device *dev; | 183 | /* for g2d api */ |
184 | struct list_head inuse_cmdlist; | 184 | struct list_head inuse_cmdlist; |
185 | struct list_head event_list; | 185 | struct list_head event_list; |
186 | struct list_head userptr_list; | 186 | struct list_head userptr_list; |
187 | }; | 187 | }; |
188 | 188 | ||
189 | struct drm_exynos_file_private { | ||
190 | struct exynos_drm_g2d_private *g2d_priv; | ||
191 | }; | ||
192 | |||
193 | /* | 189 | /* |
194 | * Exynos drm private structure. | 190 | * Exynos drm private structure. |
195 | * | 191 | * |
@@ -201,6 +197,7 @@ struct exynos_drm_private { | |||
201 | struct drm_fb_helper *fb_helper; | 197 | struct drm_fb_helper *fb_helper; |
202 | struct drm_atomic_state *suspend_state; | 198 | struct drm_atomic_state *suspend_state; |
203 | 199 | ||
200 | struct device *g2d_dev; | ||
204 | struct device *dma_dev; | 201 | struct device *dma_dev; |
205 | void *mapping; | 202 | void *mapping; |
206 | 203 | ||
@@ -217,44 +214,6 @@ static inline struct device *to_dma_dev(struct drm_device *dev) | |||
217 | return priv->dma_dev; | 214 | return priv->dma_dev; |
218 | } | 215 | } |
219 | 216 | ||
220 | /* | ||
221 | * Exynos drm sub driver structure. | ||
222 | * | ||
223 | * @list: sub driver has its own list object to register to exynos drm driver. | ||
224 | * @dev: pointer to device object for subdrv device driver. | ||
225 | * @drm_dev: pointer to drm_device and this pointer would be set | ||
226 | * when sub driver calls exynos_drm_subdrv_register(). | ||
227 | * @probe: this callback would be called by exynos drm driver after | ||
228 | * subdrv is registered to it. | ||
229 | * @remove: this callback is used to release resources created | ||
230 | * by probe callback. | ||
231 | * @open: this would be called with drm device file open. | ||
232 | * @close: this would be called with drm device file close. | ||
233 | */ | ||
234 | struct exynos_drm_subdrv { | ||
235 | struct list_head list; | ||
236 | struct device *dev; | ||
237 | struct drm_device *drm_dev; | ||
238 | |||
239 | int (*probe)(struct drm_device *drm_dev, struct device *dev); | ||
240 | void (*remove)(struct drm_device *drm_dev, struct device *dev); | ||
241 | int (*open)(struct drm_device *drm_dev, struct device *dev, | ||
242 | struct drm_file *file); | ||
243 | void (*close)(struct drm_device *drm_dev, struct device *dev, | ||
244 | struct drm_file *file); | ||
245 | }; | ||
246 | |||
247 | /* This function would be called by non kms drivers such as g2d and ipp. */ | ||
248 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); | ||
249 | |||
250 | /* this function removes subdrv list from exynos drm driver */ | ||
251 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); | ||
252 | |||
253 | int exynos_drm_device_subdrv_probe(struct drm_device *dev); | ||
254 | int exynos_drm_device_subdrv_remove(struct drm_device *dev); | ||
255 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); | ||
256 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); | ||
257 | |||
258 | #ifdef CONFIG_DRM_EXYNOS_DPI | 217 | #ifdef CONFIG_DRM_EXYNOS_DPI |
259 | struct drm_encoder *exynos_dpi_probe(struct device *dev); | 218 | struct drm_encoder *exynos_dpi_probe(struct device *dev); |
260 | int exynos_dpi_remove(struct drm_encoder *encoder); | 219 | int exynos_dpi_remove(struct drm_encoder *encoder); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index a1ed6146a3b5..781b82c2c579 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c | |||
@@ -1863,6 +1863,8 @@ err_clk: | |||
1863 | 1863 | ||
1864 | static const struct dev_pm_ops exynos_dsi_pm_ops = { | 1864 | static const struct dev_pm_ops exynos_dsi_pm_ops = { |
1865 | SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL) | 1865 | SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL) |
1866 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
1867 | pm_runtime_force_resume) | ||
1866 | }; | 1868 | }; |
1867 | 1869 | ||
1868 | struct platform_driver dsi_driver = { | 1870 | struct platform_driver dsi_driver = { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 7fcc1a7ab1a0..9f52382e19ee 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c | |||
@@ -101,7 +101,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |||
101 | { | 101 | { |
102 | const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd); | 102 | const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd); |
103 | struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; | 103 | struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; |
104 | struct drm_gem_object *obj; | ||
105 | struct drm_framebuffer *fb; | 104 | struct drm_framebuffer *fb; |
106 | int i; | 105 | int i; |
107 | int ret; | 106 | int ret; |
@@ -112,15 +111,14 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |||
112 | unsigned long size = height * mode_cmd->pitches[i] + | 111 | unsigned long size = height * mode_cmd->pitches[i] + |
113 | mode_cmd->offsets[i]; | 112 | mode_cmd->offsets[i]; |
114 | 113 | ||
115 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); | 114 | exynos_gem[i] = exynos_drm_gem_get(file_priv, |
116 | if (!obj) { | 115 | mode_cmd->handles[i]); |
116 | if (!exynos_gem[i]) { | ||
117 | DRM_ERROR("failed to lookup gem object\n"); | 117 | DRM_ERROR("failed to lookup gem object\n"); |
118 | ret = -ENOENT; | 118 | ret = -ENOENT; |
119 | goto err; | 119 | goto err; |
120 | } | 120 | } |
121 | 121 | ||
122 | exynos_gem[i] = to_exynos_gem(obj); | ||
123 | |||
124 | if (size > exynos_gem[i]->size) { | 122 | if (size > exynos_gem[i]->size) { |
125 | i++; | 123 | i++; |
126 | ret = -EINVAL; | 124 | ret = -EINVAL; |
@@ -138,7 +136,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |||
138 | 136 | ||
139 | err: | 137 | err: |
140 | while (i--) | 138 | while (i--) |
141 | drm_gem_object_unreference_unlocked(&exynos_gem[i]->base); | 139 | exynos_drm_gem_put(exynos_gem[i]); |
142 | 140 | ||
143 | return ERR_PTR(ret); | 141 | return ERR_PTR(ret); |
144 | } | 142 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 6127ef25acd6..e8d0670bb5f8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c | |||
@@ -470,17 +470,18 @@ static void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation) | |||
470 | static void fimc_set_window(struct fimc_context *ctx, | 470 | static void fimc_set_window(struct fimc_context *ctx, |
471 | struct exynos_drm_ipp_buffer *buf) | 471 | struct exynos_drm_ipp_buffer *buf) |
472 | { | 472 | { |
473 | unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; | ||
473 | u32 cfg, h1, h2, v1, v2; | 474 | u32 cfg, h1, h2, v1, v2; |
474 | 475 | ||
475 | /* cropped image */ | 476 | /* cropped image */ |
476 | h1 = buf->rect.x; | 477 | h1 = buf->rect.x; |
477 | h2 = buf->buf.width - buf->rect.w - buf->rect.x; | 478 | h2 = real_width - buf->rect.w - buf->rect.x; |
478 | v1 = buf->rect.y; | 479 | v1 = buf->rect.y; |
479 | v2 = buf->buf.height - buf->rect.h - buf->rect.y; | 480 | v2 = buf->buf.height - buf->rect.h - buf->rect.y; |
480 | 481 | ||
481 | DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n", | 482 | DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n", |
482 | buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h, | 483 | buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h, |
483 | buf->buf.width, buf->buf.height); | 484 | real_width, buf->buf.height); |
484 | DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2); | 485 | DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2); |
485 | 486 | ||
486 | /* | 487 | /* |
@@ -503,12 +504,13 @@ static void fimc_set_window(struct fimc_context *ctx, | |||
503 | static void fimc_src_set_size(struct fimc_context *ctx, | 504 | static void fimc_src_set_size(struct fimc_context *ctx, |
504 | struct exynos_drm_ipp_buffer *buf) | 505 | struct exynos_drm_ipp_buffer *buf) |
505 | { | 506 | { |
507 | unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; | ||
506 | u32 cfg; | 508 | u32 cfg; |
507 | 509 | ||
508 | DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height); | 510 | DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", real_width, buf->buf.height); |
509 | 511 | ||
510 | /* original size */ | 512 | /* original size */ |
511 | cfg = (EXYNOS_ORGISIZE_HORIZONTAL(buf->buf.width) | | 513 | cfg = (EXYNOS_ORGISIZE_HORIZONTAL(real_width) | |
512 | EXYNOS_ORGISIZE_VERTICAL(buf->buf.height)); | 514 | EXYNOS_ORGISIZE_VERTICAL(buf->buf.height)); |
513 | 515 | ||
514 | fimc_write(ctx, cfg, EXYNOS_ORGISIZE); | 516 | fimc_write(ctx, cfg, EXYNOS_ORGISIZE); |
@@ -529,7 +531,7 @@ static void fimc_src_set_size(struct fimc_context *ctx, | |||
529 | * for now, we support only ITU601 8 bit mode | 531 | * for now, we support only ITU601 8 bit mode |
530 | */ | 532 | */ |
531 | cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | | 533 | cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | |
532 | EXYNOS_CISRCFMT_SOURCEHSIZE(buf->buf.width) | | 534 | EXYNOS_CISRCFMT_SOURCEHSIZE(real_width) | |
533 | EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height)); | 535 | EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height)); |
534 | fimc_write(ctx, cfg, EXYNOS_CISRCFMT); | 536 | fimc_write(ctx, cfg, EXYNOS_CISRCFMT); |
535 | 537 | ||
@@ -842,12 +844,13 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc) | |||
842 | static void fimc_dst_set_size(struct fimc_context *ctx, | 844 | static void fimc_dst_set_size(struct fimc_context *ctx, |
843 | struct exynos_drm_ipp_buffer *buf) | 845 | struct exynos_drm_ipp_buffer *buf) |
844 | { | 846 | { |
847 | unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; | ||
845 | u32 cfg, cfg_ext; | 848 | u32 cfg, cfg_ext; |
846 | 849 | ||
847 | DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height); | 850 | DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", real_width, buf->buf.height); |
848 | 851 | ||
849 | /* original size */ | 852 | /* original size */ |
850 | cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(buf->buf.width) | | 853 | cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(real_width) | |
851 | EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height)); | 854 | EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height)); |
852 | 855 | ||
853 | fimc_write(ctx, cfg, EXYNOS_ORGOSIZE); | 856 | fimc_write(ctx, cfg, EXYNOS_ORGOSIZE); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 01b1570d0c3a..b7f56935a46b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -1192,6 +1192,8 @@ static int exynos_fimd_resume(struct device *dev) | |||
1192 | 1192 | ||
1193 | static const struct dev_pm_ops exynos_fimd_pm_ops = { | 1193 | static const struct dev_pm_ops exynos_fimd_pm_ops = { |
1194 | SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL) | 1194 | SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL) |
1195 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
1196 | pm_runtime_force_resume) | ||
1195 | }; | 1197 | }; |
1196 | 1198 | ||
1197 | struct platform_driver fimd_driver = { | 1199 | struct platform_driver fimd_driver = { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index f68ef1b3a28c..f2481a2014bb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
12 | #include <linux/component.h> | ||
12 | #include <linux/err.h> | 13 | #include <linux/err.h> |
13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
14 | #include <linux/io.h> | 15 | #include <linux/io.h> |
@@ -190,7 +191,7 @@ struct g2d_buf_desc { | |||
190 | struct g2d_buf_info { | 191 | struct g2d_buf_info { |
191 | unsigned int map_nr; | 192 | unsigned int map_nr; |
192 | enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; | 193 | enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; |
193 | unsigned long handles[MAX_REG_TYPE_NR]; | 194 | void *obj[MAX_REG_TYPE_NR]; |
194 | unsigned int types[MAX_REG_TYPE_NR]; | 195 | unsigned int types[MAX_REG_TYPE_NR]; |
195 | struct g2d_buf_desc descs[MAX_REG_TYPE_NR]; | 196 | struct g2d_buf_desc descs[MAX_REG_TYPE_NR]; |
196 | }; | 197 | }; |
@@ -237,7 +238,7 @@ struct g2d_data { | |||
237 | int irq; | 238 | int irq; |
238 | struct workqueue_struct *g2d_workq; | 239 | struct workqueue_struct *g2d_workq; |
239 | struct work_struct runqueue_work; | 240 | struct work_struct runqueue_work; |
240 | struct exynos_drm_subdrv subdrv; | 241 | struct drm_device *drm_dev; |
241 | unsigned long flags; | 242 | unsigned long flags; |
242 | 243 | ||
243 | /* cmdlist */ | 244 | /* cmdlist */ |
@@ -268,14 +269,13 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
268 | { | 269 | { |
269 | struct device *dev = g2d->dev; | 270 | struct device *dev = g2d->dev; |
270 | struct g2d_cmdlist_node *node = g2d->cmdlist_node; | 271 | struct g2d_cmdlist_node *node = g2d->cmdlist_node; |
271 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | ||
272 | int nr; | 272 | int nr; |
273 | int ret; | 273 | int ret; |
274 | struct g2d_buf_info *buf_info; | 274 | struct g2d_buf_info *buf_info; |
275 | 275 | ||
276 | g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE; | 276 | g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE; |
277 | 277 | ||
278 | g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(subdrv->drm_dev), | 278 | g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev), |
279 | G2D_CMDLIST_POOL_SIZE, | 279 | G2D_CMDLIST_POOL_SIZE, |
280 | &g2d->cmdlist_pool, GFP_KERNEL, | 280 | &g2d->cmdlist_pool, GFP_KERNEL, |
281 | g2d->cmdlist_dma_attrs); | 281 | g2d->cmdlist_dma_attrs); |
@@ -308,7 +308,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
308 | return 0; | 308 | return 0; |
309 | 309 | ||
310 | err: | 310 | err: |
311 | dma_free_attrs(to_dma_dev(subdrv->drm_dev), G2D_CMDLIST_POOL_SIZE, | 311 | dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, |
312 | g2d->cmdlist_pool_virt, | 312 | g2d->cmdlist_pool_virt, |
313 | g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); | 313 | g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); |
314 | return ret; | 314 | return ret; |
@@ -316,12 +316,10 @@ err: | |||
316 | 316 | ||
317 | static void g2d_fini_cmdlist(struct g2d_data *g2d) | 317 | static void g2d_fini_cmdlist(struct g2d_data *g2d) |
318 | { | 318 | { |
319 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | ||
320 | |||
321 | kfree(g2d->cmdlist_node); | 319 | kfree(g2d->cmdlist_node); |
322 | 320 | ||
323 | if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { | 321 | if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { |
324 | dma_free_attrs(to_dma_dev(subdrv->drm_dev), | 322 | dma_free_attrs(to_dma_dev(g2d->drm_dev), |
325 | G2D_CMDLIST_POOL_SIZE, | 323 | G2D_CMDLIST_POOL_SIZE, |
326 | g2d->cmdlist_pool_virt, | 324 | g2d->cmdlist_pool_virt, |
327 | g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); | 325 | g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); |
@@ -355,32 +353,31 @@ static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node) | |||
355 | mutex_unlock(&g2d->cmdlist_mutex); | 353 | mutex_unlock(&g2d->cmdlist_mutex); |
356 | } | 354 | } |
357 | 355 | ||
358 | static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv, | 356 | static void g2d_add_cmdlist_to_inuse(struct drm_exynos_file_private *file_priv, |
359 | struct g2d_cmdlist_node *node) | 357 | struct g2d_cmdlist_node *node) |
360 | { | 358 | { |
361 | struct g2d_cmdlist_node *lnode; | 359 | struct g2d_cmdlist_node *lnode; |
362 | 360 | ||
363 | if (list_empty(&g2d_priv->inuse_cmdlist)) | 361 | if (list_empty(&file_priv->inuse_cmdlist)) |
364 | goto add_to_list; | 362 | goto add_to_list; |
365 | 363 | ||
366 | /* this links to base address of new cmdlist */ | 364 | /* this links to base address of new cmdlist */ |
367 | lnode = list_entry(g2d_priv->inuse_cmdlist.prev, | 365 | lnode = list_entry(file_priv->inuse_cmdlist.prev, |
368 | struct g2d_cmdlist_node, list); | 366 | struct g2d_cmdlist_node, list); |
369 | lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr; | 367 | lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr; |
370 | 368 | ||
371 | add_to_list: | 369 | add_to_list: |
372 | list_add_tail(&node->list, &g2d_priv->inuse_cmdlist); | 370 | list_add_tail(&node->list, &file_priv->inuse_cmdlist); |
373 | 371 | ||
374 | if (node->event) | 372 | if (node->event) |
375 | list_add_tail(&node->event->base.link, &g2d_priv->event_list); | 373 | list_add_tail(&node->event->base.link, &file_priv->event_list); |
376 | } | 374 | } |
377 | 375 | ||
378 | static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, | 376 | static void g2d_userptr_put_dma_addr(struct g2d_data *g2d, |
379 | unsigned long obj, | 377 | void *obj, |
380 | bool force) | 378 | bool force) |
381 | { | 379 | { |
382 | struct g2d_cmdlist_userptr *g2d_userptr = | 380 | struct g2d_cmdlist_userptr *g2d_userptr = obj; |
383 | (struct g2d_cmdlist_userptr *)obj; | ||
384 | struct page **pages; | 381 | struct page **pages; |
385 | 382 | ||
386 | if (!obj) | 383 | if (!obj) |
@@ -398,7 +395,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, | |||
398 | return; | 395 | return; |
399 | 396 | ||
400 | out: | 397 | out: |
401 | dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl, | 398 | dma_unmap_sg(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt->sgl, |
402 | g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL); | 399 | g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL); |
403 | 400 | ||
404 | pages = frame_vector_pages(g2d_userptr->vec); | 401 | pages = frame_vector_pages(g2d_userptr->vec); |
@@ -419,16 +416,14 @@ out: | |||
419 | kfree(g2d_userptr); | 416 | kfree(g2d_userptr); |
420 | } | 417 | } |
421 | 418 | ||
422 | static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | 419 | static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, |
423 | unsigned long userptr, | 420 | unsigned long userptr, |
424 | unsigned long size, | 421 | unsigned long size, |
425 | struct drm_file *filp, | 422 | struct drm_file *filp, |
426 | unsigned long *obj) | 423 | void **obj) |
427 | { | 424 | { |
428 | struct drm_exynos_file_private *file_priv = filp->driver_priv; | 425 | struct drm_exynos_file_private *file_priv = filp->driver_priv; |
429 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
430 | struct g2d_cmdlist_userptr *g2d_userptr; | 426 | struct g2d_cmdlist_userptr *g2d_userptr; |
431 | struct g2d_data *g2d; | ||
432 | struct sg_table *sgt; | 427 | struct sg_table *sgt; |
433 | unsigned long start, end; | 428 | unsigned long start, end; |
434 | unsigned int npages, offset; | 429 | unsigned int npages, offset; |
@@ -439,10 +434,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | |||
439 | return ERR_PTR(-EINVAL); | 434 | return ERR_PTR(-EINVAL); |
440 | } | 435 | } |
441 | 436 | ||
442 | g2d = dev_get_drvdata(g2d_priv->dev); | ||
443 | |||
444 | /* check if userptr already exists in userptr_list. */ | 437 | /* check if userptr already exists in userptr_list. */ |
445 | list_for_each_entry(g2d_userptr, &g2d_priv->userptr_list, list) { | 438 | list_for_each_entry(g2d_userptr, &file_priv->userptr_list, list) { |
446 | if (g2d_userptr->userptr == userptr) { | 439 | if (g2d_userptr->userptr == userptr) { |
447 | /* | 440 | /* |
448 | * also check size because there could be same address | 441 | * also check size because there could be same address |
@@ -450,7 +443,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | |||
450 | */ | 443 | */ |
451 | if (g2d_userptr->size == size) { | 444 | if (g2d_userptr->size == size) { |
452 | atomic_inc(&g2d_userptr->refcount); | 445 | atomic_inc(&g2d_userptr->refcount); |
453 | *obj = (unsigned long)g2d_userptr; | 446 | *obj = g2d_userptr; |
454 | 447 | ||
455 | return &g2d_userptr->dma_addr; | 448 | return &g2d_userptr->dma_addr; |
456 | } | 449 | } |
@@ -517,7 +510,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | |||
517 | 510 | ||
518 | g2d_userptr->sgt = sgt; | 511 | g2d_userptr->sgt = sgt; |
519 | 512 | ||
520 | if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, | 513 | if (!dma_map_sg(to_dma_dev(g2d->drm_dev), sgt->sgl, sgt->nents, |
521 | DMA_BIDIRECTIONAL)) { | 514 | DMA_BIDIRECTIONAL)) { |
522 | DRM_ERROR("failed to map sgt with dma region.\n"); | 515 | DRM_ERROR("failed to map sgt with dma region.\n"); |
523 | ret = -ENOMEM; | 516 | ret = -ENOMEM; |
@@ -527,14 +520,14 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | |||
527 | g2d_userptr->dma_addr = sgt->sgl[0].dma_address; | 520 | g2d_userptr->dma_addr = sgt->sgl[0].dma_address; |
528 | g2d_userptr->userptr = userptr; | 521 | g2d_userptr->userptr = userptr; |
529 | 522 | ||
530 | list_add_tail(&g2d_userptr->list, &g2d_priv->userptr_list); | 523 | list_add_tail(&g2d_userptr->list, &file_priv->userptr_list); |
531 | 524 | ||
532 | if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) { | 525 | if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) { |
533 | g2d->current_pool += npages << PAGE_SHIFT; | 526 | g2d->current_pool += npages << PAGE_SHIFT; |
534 | g2d_userptr->in_pool = true; | 527 | g2d_userptr->in_pool = true; |
535 | } | 528 | } |
536 | 529 | ||
537 | *obj = (unsigned long)g2d_userptr; | 530 | *obj = g2d_userptr; |
538 | 531 | ||
539 | return &g2d_userptr->dma_addr; | 532 | return &g2d_userptr->dma_addr; |
540 | 533 | ||
@@ -556,19 +549,14 @@ err_free: | |||
556 | return ERR_PTR(ret); | 549 | return ERR_PTR(ret); |
557 | } | 550 | } |
558 | 551 | ||
559 | static void g2d_userptr_free_all(struct drm_device *drm_dev, | 552 | static void g2d_userptr_free_all(struct g2d_data *g2d, struct drm_file *filp) |
560 | struct g2d_data *g2d, | ||
561 | struct drm_file *filp) | ||
562 | { | 553 | { |
563 | struct drm_exynos_file_private *file_priv = filp->driver_priv; | 554 | struct drm_exynos_file_private *file_priv = filp->driver_priv; |
564 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
565 | struct g2d_cmdlist_userptr *g2d_userptr, *n; | 555 | struct g2d_cmdlist_userptr *g2d_userptr, *n; |
566 | 556 | ||
567 | list_for_each_entry_safe(g2d_userptr, n, &g2d_priv->userptr_list, list) | 557 | list_for_each_entry_safe(g2d_userptr, n, &file_priv->userptr_list, list) |
568 | if (g2d_userptr->in_pool) | 558 | if (g2d_userptr->in_pool) |
569 | g2d_userptr_put_dma_addr(drm_dev, | 559 | g2d_userptr_put_dma_addr(g2d, g2d_userptr, true); |
570 | (unsigned long)g2d_userptr, | ||
571 | true); | ||
572 | 560 | ||
573 | g2d->current_pool = 0; | 561 | g2d->current_pool = 0; |
574 | } | 562 | } |
@@ -723,26 +711,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | |||
723 | buf_desc = &buf_info->descs[reg_type]; | 711 | buf_desc = &buf_info->descs[reg_type]; |
724 | 712 | ||
725 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) { | 713 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) { |
726 | unsigned long size; | 714 | struct exynos_drm_gem *exynos_gem; |
727 | 715 | ||
728 | size = exynos_drm_gem_get_size(drm_dev, handle, file); | 716 | exynos_gem = exynos_drm_gem_get(file, handle); |
729 | if (!size) { | 717 | if (!exynos_gem) { |
730 | ret = -EFAULT; | 718 | ret = -EFAULT; |
731 | goto err; | 719 | goto err; |
732 | } | 720 | } |
733 | 721 | ||
734 | if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, | 722 | if (!g2d_check_buf_desc_is_valid(buf_desc, |
735 | size)) { | 723 | reg_type, exynos_gem->size)) { |
724 | exynos_drm_gem_put(exynos_gem); | ||
736 | ret = -EFAULT; | 725 | ret = -EFAULT; |
737 | goto err; | 726 | goto err; |
738 | } | 727 | } |
739 | 728 | ||
740 | addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, | 729 | addr = &exynos_gem->dma_addr; |
741 | file); | 730 | buf_info->obj[reg_type] = exynos_gem; |
742 | if (IS_ERR(addr)) { | ||
743 | ret = -EFAULT; | ||
744 | goto err; | ||
745 | } | ||
746 | } else { | 731 | } else { |
747 | struct drm_exynos_g2d_userptr g2d_userptr; | 732 | struct drm_exynos_g2d_userptr g2d_userptr; |
748 | 733 | ||
@@ -758,11 +743,11 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | |||
758 | goto err; | 743 | goto err; |
759 | } | 744 | } |
760 | 745 | ||
761 | addr = g2d_userptr_get_dma_addr(drm_dev, | 746 | addr = g2d_userptr_get_dma_addr(g2d, |
762 | g2d_userptr.userptr, | 747 | g2d_userptr.userptr, |
763 | g2d_userptr.size, | 748 | g2d_userptr.size, |
764 | file, | 749 | file, |
765 | &handle); | 750 | &buf_info->obj[reg_type]); |
766 | if (IS_ERR(addr)) { | 751 | if (IS_ERR(addr)) { |
767 | ret = -EFAULT; | 752 | ret = -EFAULT; |
768 | goto err; | 753 | goto err; |
@@ -771,7 +756,6 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | |||
771 | 756 | ||
772 | cmdlist->data[reg_pos + 1] = *addr; | 757 | cmdlist->data[reg_pos + 1] = *addr; |
773 | buf_info->reg_types[i] = reg_type; | 758 | buf_info->reg_types[i] = reg_type; |
774 | buf_info->handles[reg_type] = handle; | ||
775 | } | 759 | } |
776 | 760 | ||
777 | return 0; | 761 | return 0; |
@@ -785,29 +769,26 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, | |||
785 | struct g2d_cmdlist_node *node, | 769 | struct g2d_cmdlist_node *node, |
786 | struct drm_file *filp) | 770 | struct drm_file *filp) |
787 | { | 771 | { |
788 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | ||
789 | struct g2d_buf_info *buf_info = &node->buf_info; | 772 | struct g2d_buf_info *buf_info = &node->buf_info; |
790 | int i; | 773 | int i; |
791 | 774 | ||
792 | for (i = 0; i < buf_info->map_nr; i++) { | 775 | for (i = 0; i < buf_info->map_nr; i++) { |
793 | struct g2d_buf_desc *buf_desc; | 776 | struct g2d_buf_desc *buf_desc; |
794 | enum g2d_reg_type reg_type; | 777 | enum g2d_reg_type reg_type; |
795 | unsigned long handle; | 778 | void *obj; |
796 | 779 | ||
797 | reg_type = buf_info->reg_types[i]; | 780 | reg_type = buf_info->reg_types[i]; |
798 | 781 | ||
799 | buf_desc = &buf_info->descs[reg_type]; | 782 | buf_desc = &buf_info->descs[reg_type]; |
800 | handle = buf_info->handles[reg_type]; | 783 | obj = buf_info->obj[reg_type]; |
801 | 784 | ||
802 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) | 785 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) |
803 | exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, | 786 | exynos_drm_gem_put(obj); |
804 | filp); | ||
805 | else | 787 | else |
806 | g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, | 788 | g2d_userptr_put_dma_addr(g2d, obj, false); |
807 | false); | ||
808 | 789 | ||
809 | buf_info->reg_types[i] = REG_TYPE_NONE; | 790 | buf_info->reg_types[i] = REG_TYPE_NONE; |
810 | buf_info->handles[reg_type] = 0; | 791 | buf_info->obj[reg_type] = NULL; |
811 | buf_info->types[reg_type] = 0; | 792 | buf_info->types[reg_type] = 0; |
812 | memset(buf_desc, 0x00, sizeof(*buf_desc)); | 793 | memset(buf_desc, 0x00, sizeof(*buf_desc)); |
813 | } | 794 | } |
@@ -922,7 +903,7 @@ static void g2d_runqueue_worker(struct work_struct *work) | |||
922 | 903 | ||
923 | static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) | 904 | static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) |
924 | { | 905 | { |
925 | struct drm_device *drm_dev = g2d->subdrv.drm_dev; | 906 | struct drm_device *drm_dev = g2d->drm_dev; |
926 | struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; | 907 | struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; |
927 | struct drm_exynos_pending_g2d_event *e; | 908 | struct drm_exynos_pending_g2d_event *e; |
928 | struct timespec64 now; | 909 | struct timespec64 now; |
@@ -1031,7 +1012,7 @@ out: | |||
1031 | mutex_unlock(&g2d->runqueue_mutex); | 1012 | mutex_unlock(&g2d->runqueue_mutex); |
1032 | } | 1013 | } |
1033 | 1014 | ||
1034 | static int g2d_check_reg_offset(struct device *dev, | 1015 | static int g2d_check_reg_offset(struct g2d_data *g2d, |
1035 | struct g2d_cmdlist_node *node, | 1016 | struct g2d_cmdlist_node *node, |
1036 | int nr, bool for_addr) | 1017 | int nr, bool for_addr) |
1037 | { | 1018 | { |
@@ -1131,7 +1112,7 @@ static int g2d_check_reg_offset(struct device *dev, | |||
1131 | return 0; | 1112 | return 0; |
1132 | 1113 | ||
1133 | err: | 1114 | err: |
1134 | dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); | 1115 | dev_err(g2d->dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); |
1135 | return -EINVAL; | 1116 | return -EINVAL; |
1136 | } | 1117 | } |
1137 | 1118 | ||
@@ -1139,23 +1120,8 @@ err: | |||
1139 | int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, | 1120 | int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, |
1140 | struct drm_file *file) | 1121 | struct drm_file *file) |
1141 | { | 1122 | { |
1142 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
1143 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
1144 | struct device *dev; | ||
1145 | struct g2d_data *g2d; | ||
1146 | struct drm_exynos_g2d_get_ver *ver = data; | 1123 | struct drm_exynos_g2d_get_ver *ver = data; |
1147 | 1124 | ||
1148 | if (!g2d_priv) | ||
1149 | return -ENODEV; | ||
1150 | |||
1151 | dev = g2d_priv->dev; | ||
1152 | if (!dev) | ||
1153 | return -ENODEV; | ||
1154 | |||
1155 | g2d = dev_get_drvdata(dev); | ||
1156 | if (!g2d) | ||
1157 | return -EFAULT; | ||
1158 | |||
1159 | ver->major = G2D_HW_MAJOR_VER; | 1125 | ver->major = G2D_HW_MAJOR_VER; |
1160 | ver->minor = G2D_HW_MINOR_VER; | 1126 | ver->minor = G2D_HW_MINOR_VER; |
1161 | 1127 | ||
@@ -1166,9 +1132,8 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1166 | struct drm_file *file) | 1132 | struct drm_file *file) |
1167 | { | 1133 | { |
1168 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1134 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1169 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | 1135 | struct exynos_drm_private *priv = drm_dev->dev_private; |
1170 | struct device *dev; | 1136 | struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev); |
1171 | struct g2d_data *g2d; | ||
1172 | struct drm_exynos_g2d_set_cmdlist *req = data; | 1137 | struct drm_exynos_g2d_set_cmdlist *req = data; |
1173 | struct drm_exynos_g2d_cmd *cmd; | 1138 | struct drm_exynos_g2d_cmd *cmd; |
1174 | struct drm_exynos_pending_g2d_event *e; | 1139 | struct drm_exynos_pending_g2d_event *e; |
@@ -1177,17 +1142,6 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1177 | int size; | 1142 | int size; |
1178 | int ret; | 1143 | int ret; |
1179 | 1144 | ||
1180 | if (!g2d_priv) | ||
1181 | return -ENODEV; | ||
1182 | |||
1183 | dev = g2d_priv->dev; | ||
1184 | if (!dev) | ||
1185 | return -ENODEV; | ||
1186 | |||
1187 | g2d = dev_get_drvdata(dev); | ||
1188 | if (!g2d) | ||
1189 | return -EFAULT; | ||
1190 | |||
1191 | node = g2d_get_cmdlist(g2d); | 1145 | node = g2d_get_cmdlist(g2d); |
1192 | if (!node) | 1146 | if (!node) |
1193 | return -ENOMEM; | 1147 | return -ENOMEM; |
@@ -1199,7 +1153,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1199 | */ | 1153 | */ |
1200 | if (req->cmd_nr > G2D_CMDLIST_DATA_NUM || | 1154 | if (req->cmd_nr > G2D_CMDLIST_DATA_NUM || |
1201 | req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) { | 1155 | req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) { |
1202 | dev_err(dev, "number of submitted G2D commands exceeds limit\n"); | 1156 | dev_err(g2d->dev, "number of submitted G2D commands exceeds limit\n"); |
1203 | return -EINVAL; | 1157 | return -EINVAL; |
1204 | } | 1158 | } |
1205 | 1159 | ||
@@ -1267,7 +1221,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1267 | */ | 1221 | */ |
1268 | size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2; | 1222 | size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2; |
1269 | if (size > G2D_CMDLIST_DATA_NUM) { | 1223 | if (size > G2D_CMDLIST_DATA_NUM) { |
1270 | dev_err(dev, "cmdlist size is too big\n"); | 1224 | dev_err(g2d->dev, "cmdlist size is too big\n"); |
1271 | ret = -EINVAL; | 1225 | ret = -EINVAL; |
1272 | goto err_free_event; | 1226 | goto err_free_event; |
1273 | } | 1227 | } |
@@ -1282,7 +1236,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1282 | } | 1236 | } |
1283 | cmdlist->last += req->cmd_nr * 2; | 1237 | cmdlist->last += req->cmd_nr * 2; |
1284 | 1238 | ||
1285 | ret = g2d_check_reg_offset(dev, node, req->cmd_nr, false); | 1239 | ret = g2d_check_reg_offset(g2d, node, req->cmd_nr, false); |
1286 | if (ret < 0) | 1240 | if (ret < 0) |
1287 | goto err_free_event; | 1241 | goto err_free_event; |
1288 | 1242 | ||
@@ -1301,7 +1255,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1301 | } | 1255 | } |
1302 | cmdlist->last += req->cmd_buf_nr * 2; | 1256 | cmdlist->last += req->cmd_buf_nr * 2; |
1303 | 1257 | ||
1304 | ret = g2d_check_reg_offset(dev, node, req->cmd_buf_nr, true); | 1258 | ret = g2d_check_reg_offset(g2d, node, req->cmd_buf_nr, true); |
1305 | if (ret < 0) | 1259 | if (ret < 0) |
1306 | goto err_free_event; | 1260 | goto err_free_event; |
1307 | 1261 | ||
@@ -1319,7 +1273,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
1319 | /* tail */ | 1273 | /* tail */ |
1320 | cmdlist->data[cmdlist->last] = 0; | 1274 | cmdlist->data[cmdlist->last] = 0; |
1321 | 1275 | ||
1322 | g2d_add_cmdlist_to_inuse(g2d_priv, node); | 1276 | g2d_add_cmdlist_to_inuse(file_priv, node); |
1323 | 1277 | ||
1324 | return 0; | 1278 | return 0; |
1325 | 1279 | ||
@@ -1337,25 +1291,13 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, | |||
1337 | struct drm_file *file) | 1291 | struct drm_file *file) |
1338 | { | 1292 | { |
1339 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1293 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1340 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | 1294 | struct exynos_drm_private *priv = drm_dev->dev_private; |
1341 | struct device *dev; | 1295 | struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev); |
1342 | struct g2d_data *g2d; | ||
1343 | struct drm_exynos_g2d_exec *req = data; | 1296 | struct drm_exynos_g2d_exec *req = data; |
1344 | struct g2d_runqueue_node *runqueue_node; | 1297 | struct g2d_runqueue_node *runqueue_node; |
1345 | struct list_head *run_cmdlist; | 1298 | struct list_head *run_cmdlist; |
1346 | struct list_head *event_list; | 1299 | struct list_head *event_list; |
1347 | 1300 | ||
1348 | if (!g2d_priv) | ||
1349 | return -ENODEV; | ||
1350 | |||
1351 | dev = g2d_priv->dev; | ||
1352 | if (!dev) | ||
1353 | return -ENODEV; | ||
1354 | |||
1355 | g2d = dev_get_drvdata(dev); | ||
1356 | if (!g2d) | ||
1357 | return -EFAULT; | ||
1358 | |||
1359 | runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); | 1301 | runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); |
1360 | if (!runqueue_node) | 1302 | if (!runqueue_node) |
1361 | return -ENOMEM; | 1303 | return -ENOMEM; |
@@ -1367,11 +1309,11 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, | |||
1367 | init_completion(&runqueue_node->complete); | 1309 | init_completion(&runqueue_node->complete); |
1368 | runqueue_node->async = req->async; | 1310 | runqueue_node->async = req->async; |
1369 | 1311 | ||
1370 | list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist); | 1312 | list_splice_init(&file_priv->inuse_cmdlist, run_cmdlist); |
1371 | list_splice_init(&g2d_priv->event_list, event_list); | 1313 | list_splice_init(&file_priv->event_list, event_list); |
1372 | 1314 | ||
1373 | if (list_empty(run_cmdlist)) { | 1315 | if (list_empty(run_cmdlist)) { |
1374 | dev_err(dev, "there is no inuse cmdlist\n"); | 1316 | dev_err(g2d->dev, "there is no inuse cmdlist\n"); |
1375 | kmem_cache_free(g2d->runqueue_slab, runqueue_node); | 1317 | kmem_cache_free(g2d->runqueue_slab, runqueue_node); |
1376 | return -EPERM; | 1318 | return -EPERM; |
1377 | } | 1319 | } |
@@ -1395,71 +1337,28 @@ out: | |||
1395 | return 0; | 1337 | return 0; |
1396 | } | 1338 | } |
1397 | 1339 | ||
1398 | static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | 1340 | int g2d_open(struct drm_device *drm_dev, struct drm_file *file) |
1399 | { | ||
1400 | struct g2d_data *g2d; | ||
1401 | int ret; | ||
1402 | |||
1403 | g2d = dev_get_drvdata(dev); | ||
1404 | if (!g2d) | ||
1405 | return -EFAULT; | ||
1406 | |||
1407 | /* allocate dma-aware cmdlist buffer. */ | ||
1408 | ret = g2d_init_cmdlist(g2d); | ||
1409 | if (ret < 0) { | ||
1410 | dev_err(dev, "cmdlist init failed\n"); | ||
1411 | return ret; | ||
1412 | } | ||
1413 | |||
1414 | ret = drm_iommu_attach_device(drm_dev, dev); | ||
1415 | if (ret < 0) { | ||
1416 | dev_err(dev, "failed to enable iommu.\n"); | ||
1417 | g2d_fini_cmdlist(g2d); | ||
1418 | } | ||
1419 | |||
1420 | return ret; | ||
1421 | |||
1422 | } | ||
1423 | |||
1424 | static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) | ||
1425 | { | ||
1426 | drm_iommu_detach_device(drm_dev, dev); | ||
1427 | } | ||
1428 | |||
1429 | static int g2d_open(struct drm_device *drm_dev, struct device *dev, | ||
1430 | struct drm_file *file) | ||
1431 | { | 1341 | { |
1432 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1342 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1433 | struct exynos_drm_g2d_private *g2d_priv; | ||
1434 | |||
1435 | g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL); | ||
1436 | if (!g2d_priv) | ||
1437 | return -ENOMEM; | ||
1438 | 1343 | ||
1439 | g2d_priv->dev = dev; | 1344 | INIT_LIST_HEAD(&file_priv->inuse_cmdlist); |
1440 | file_priv->g2d_priv = g2d_priv; | 1345 | INIT_LIST_HEAD(&file_priv->event_list); |
1441 | 1346 | INIT_LIST_HEAD(&file_priv->userptr_list); | |
1442 | INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist); | ||
1443 | INIT_LIST_HEAD(&g2d_priv->event_list); | ||
1444 | INIT_LIST_HEAD(&g2d_priv->userptr_list); | ||
1445 | 1347 | ||
1446 | return 0; | 1348 | return 0; |
1447 | } | 1349 | } |
1448 | 1350 | ||
1449 | static void g2d_close(struct drm_device *drm_dev, struct device *dev, | 1351 | void g2d_close(struct drm_device *drm_dev, struct drm_file *file) |
1450 | struct drm_file *file) | ||
1451 | { | 1352 | { |
1452 | struct drm_exynos_file_private *file_priv = file->driver_priv; | 1353 | struct drm_exynos_file_private *file_priv = file->driver_priv; |
1453 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | 1354 | struct exynos_drm_private *priv = drm_dev->dev_private; |
1454 | struct g2d_data *g2d; | 1355 | struct g2d_data *g2d; |
1455 | struct g2d_cmdlist_node *node, *n; | 1356 | struct g2d_cmdlist_node *node, *n; |
1456 | 1357 | ||
1457 | if (!dev) | 1358 | if (!priv->g2d_dev) |
1458 | return; | 1359 | return; |
1459 | 1360 | ||
1460 | g2d = dev_get_drvdata(dev); | 1361 | g2d = dev_get_drvdata(priv->g2d_dev); |
1461 | if (!g2d) | ||
1462 | return; | ||
1463 | 1362 | ||
1464 | /* Remove the runqueue nodes that belong to us. */ | 1363 | /* Remove the runqueue nodes that belong to us. */ |
1465 | mutex_lock(&g2d->runqueue_mutex); | 1364 | mutex_lock(&g2d->runqueue_mutex); |
@@ -1480,24 +1379,70 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev, | |||
1480 | * Properly unmap these buffers here. | 1379 | * Properly unmap these buffers here. |
1481 | */ | 1380 | */ |
1482 | mutex_lock(&g2d->cmdlist_mutex); | 1381 | mutex_lock(&g2d->cmdlist_mutex); |
1483 | list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) { | 1382 | list_for_each_entry_safe(node, n, &file_priv->inuse_cmdlist, list) { |
1484 | g2d_unmap_cmdlist_gem(g2d, node, file); | 1383 | g2d_unmap_cmdlist_gem(g2d, node, file); |
1485 | list_move_tail(&node->list, &g2d->free_cmdlist); | 1384 | list_move_tail(&node->list, &g2d->free_cmdlist); |
1486 | } | 1385 | } |
1487 | mutex_unlock(&g2d->cmdlist_mutex); | 1386 | mutex_unlock(&g2d->cmdlist_mutex); |
1488 | 1387 | ||
1489 | /* release all g2d_userptr in pool. */ | 1388 | /* release all g2d_userptr in pool. */ |
1490 | g2d_userptr_free_all(drm_dev, g2d, file); | 1389 | g2d_userptr_free_all(g2d, file); |
1390 | } | ||
1391 | |||
1392 | static int g2d_bind(struct device *dev, struct device *master, void *data) | ||
1393 | { | ||
1394 | struct g2d_data *g2d = dev_get_drvdata(dev); | ||
1395 | struct drm_device *drm_dev = data; | ||
1396 | struct exynos_drm_private *priv = drm_dev->dev_private; | ||
1397 | int ret; | ||
1398 | |||
1399 | g2d->drm_dev = drm_dev; | ||
1491 | 1400 | ||
1492 | kfree(file_priv->g2d_priv); | 1401 | /* allocate dma-aware cmdlist buffer. */ |
1402 | ret = g2d_init_cmdlist(g2d); | ||
1403 | if (ret < 0) { | ||
1404 | dev_err(dev, "cmdlist init failed\n"); | ||
1405 | return ret; | ||
1406 | } | ||
1407 | |||
1408 | ret = drm_iommu_attach_device(drm_dev, dev); | ||
1409 | if (ret < 0) { | ||
1410 | dev_err(dev, "failed to enable iommu.\n"); | ||
1411 | g2d_fini_cmdlist(g2d); | ||
1412 | return ret; | ||
1413 | } | ||
1414 | priv->g2d_dev = dev; | ||
1415 | |||
1416 | dev_info(dev, "The Exynos G2D (ver %d.%d) successfully registered.\n", | ||
1417 | G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); | ||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1421 | static void g2d_unbind(struct device *dev, struct device *master, void *data) | ||
1422 | { | ||
1423 | struct g2d_data *g2d = dev_get_drvdata(dev); | ||
1424 | struct drm_device *drm_dev = data; | ||
1425 | struct exynos_drm_private *priv = drm_dev->dev_private; | ||
1426 | |||
1427 | /* Suspend operation and wait for engine idle. */ | ||
1428 | set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); | ||
1429 | g2d_wait_finish(g2d, NULL); | ||
1430 | priv->g2d_dev = NULL; | ||
1431 | |||
1432 | cancel_work_sync(&g2d->runqueue_work); | ||
1433 | drm_iommu_detach_device(g2d->drm_dev, dev); | ||
1493 | } | 1434 | } |
1494 | 1435 | ||
1436 | static const struct component_ops g2d_component_ops = { | ||
1437 | .bind = g2d_bind, | ||
1438 | .unbind = g2d_unbind, | ||
1439 | }; | ||
1440 | |||
1495 | static int g2d_probe(struct platform_device *pdev) | 1441 | static int g2d_probe(struct platform_device *pdev) |
1496 | { | 1442 | { |
1497 | struct device *dev = &pdev->dev; | 1443 | struct device *dev = &pdev->dev; |
1498 | struct resource *res; | 1444 | struct resource *res; |
1499 | struct g2d_data *g2d; | 1445 | struct g2d_data *g2d; |
1500 | struct exynos_drm_subdrv *subdrv; | ||
1501 | int ret; | 1446 | int ret; |
1502 | 1447 | ||
1503 | g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL); | 1448 | g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL); |
@@ -1564,22 +1509,12 @@ static int g2d_probe(struct platform_device *pdev) | |||
1564 | 1509 | ||
1565 | platform_set_drvdata(pdev, g2d); | 1510 | platform_set_drvdata(pdev, g2d); |
1566 | 1511 | ||
1567 | subdrv = &g2d->subdrv; | 1512 | ret = component_add(dev, &g2d_component_ops); |
1568 | subdrv->dev = dev; | ||
1569 | subdrv->probe = g2d_subdrv_probe; | ||
1570 | subdrv->remove = g2d_subdrv_remove; | ||
1571 | subdrv->open = g2d_open; | ||
1572 | subdrv->close = g2d_close; | ||
1573 | |||
1574 | ret = exynos_drm_subdrv_register(subdrv); | ||
1575 | if (ret < 0) { | 1513 | if (ret < 0) { |
1576 | dev_err(dev, "failed to register drm g2d device\n"); | 1514 | dev_err(dev, "failed to register drm g2d device\n"); |
1577 | goto err_put_clk; | 1515 | goto err_put_clk; |
1578 | } | 1516 | } |
1579 | 1517 | ||
1580 | dev_info(dev, "The Exynos G2D (ver %d.%d) successfully probed.\n", | ||
1581 | G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); | ||
1582 | |||
1583 | return 0; | 1518 | return 0; |
1584 | 1519 | ||
1585 | err_put_clk: | 1520 | err_put_clk: |
@@ -1595,12 +1530,7 @@ static int g2d_remove(struct platform_device *pdev) | |||
1595 | { | 1530 | { |
1596 | struct g2d_data *g2d = platform_get_drvdata(pdev); | 1531 | struct g2d_data *g2d = platform_get_drvdata(pdev); |
1597 | 1532 | ||
1598 | /* Suspend operation and wait for engine idle. */ | 1533 | component_del(&pdev->dev, &g2d_component_ops); |
1599 | set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); | ||
1600 | g2d_wait_finish(g2d, NULL); | ||
1601 | |||
1602 | cancel_work_sync(&g2d->runqueue_work); | ||
1603 | exynos_drm_subdrv_unregister(&g2d->subdrv); | ||
1604 | 1534 | ||
1605 | /* There should be no locking needed here. */ | 1535 | /* There should be no locking needed here. */ |
1606 | g2d_remove_runqueue_nodes(g2d, NULL); | 1536 | g2d_remove_runqueue_nodes(g2d, NULL); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h index 1a9c7ca8c15b..287b2ed8f178 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.h +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h | |||
@@ -14,6 +14,9 @@ extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data, | |||
14 | struct drm_file *file_priv); | 14 | struct drm_file *file_priv); |
15 | extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, | 15 | extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, |
16 | struct drm_file *file_priv); | 16 | struct drm_file *file_priv); |
17 | |||
18 | extern int g2d_open(struct drm_device *drm_dev, struct drm_file *file); | ||
19 | extern void g2d_close(struct drm_device *drm_dev, struct drm_file *file); | ||
17 | #else | 20 | #else |
18 | static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data, | 21 | static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data, |
19 | struct drm_file *file_priv) | 22 | struct drm_file *file_priv) |
@@ -33,4 +36,12 @@ static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, | |||
33 | { | 36 | { |
34 | return -ENODEV; | 37 | return -ENODEV; |
35 | } | 38 | } |
39 | |||
40 | int g2d_open(struct drm_device *drm_dev, struct drm_file *file) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | void g2d_close(struct drm_device *drm_dev, struct drm_file *file) | ||
46 | { } | ||
36 | #endif | 47 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 6e1494fa71b4..34ace85feb68 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
@@ -143,7 +143,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, | |||
143 | DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); | 143 | DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); |
144 | 144 | ||
145 | /* drop reference from allocate - handle holds it now. */ | 145 | /* drop reference from allocate - handle holds it now. */ |
146 | drm_gem_object_unreference_unlocked(obj); | 146 | drm_gem_object_put_unlocked(obj); |
147 | 147 | ||
148 | return 0; | 148 | return 0; |
149 | } | 149 | } |
@@ -171,26 +171,6 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) | |||
171 | kfree(exynos_gem); | 171 | kfree(exynos_gem); |
172 | } | 172 | } |
173 | 173 | ||
174 | unsigned long exynos_drm_gem_get_size(struct drm_device *dev, | ||
175 | unsigned int gem_handle, | ||
176 | struct drm_file *file_priv) | ||
177 | { | ||
178 | struct exynos_drm_gem *exynos_gem; | ||
179 | struct drm_gem_object *obj; | ||
180 | |||
181 | obj = drm_gem_object_lookup(file_priv, gem_handle); | ||
182 | if (!obj) { | ||
183 | DRM_ERROR("failed to lookup gem object.\n"); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | exynos_gem = to_exynos_gem(obj); | ||
188 | |||
189 | drm_gem_object_unreference_unlocked(obj); | ||
190 | |||
191 | return exynos_gem->size; | ||
192 | } | ||
193 | |||
194 | static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, | 174 | static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, |
195 | unsigned long size) | 175 | unsigned long size) |
196 | { | 176 | { |
@@ -299,43 +279,15 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data, | |||
299 | &args->offset); | 279 | &args->offset); |
300 | } | 280 | } |
301 | 281 | ||
302 | dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, | 282 | struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, |
303 | unsigned int gem_handle, | 283 | unsigned int gem_handle) |
304 | struct drm_file *filp) | ||
305 | { | ||
306 | struct exynos_drm_gem *exynos_gem; | ||
307 | struct drm_gem_object *obj; | ||
308 | |||
309 | obj = drm_gem_object_lookup(filp, gem_handle); | ||
310 | if (!obj) { | ||
311 | DRM_ERROR("failed to lookup gem object.\n"); | ||
312 | return ERR_PTR(-EINVAL); | ||
313 | } | ||
314 | |||
315 | exynos_gem = to_exynos_gem(obj); | ||
316 | |||
317 | return &exynos_gem->dma_addr; | ||
318 | } | ||
319 | |||
320 | void exynos_drm_gem_put_dma_addr(struct drm_device *dev, | ||
321 | unsigned int gem_handle, | ||
322 | struct drm_file *filp) | ||
323 | { | 284 | { |
324 | struct drm_gem_object *obj; | 285 | struct drm_gem_object *obj; |
325 | 286 | ||
326 | obj = drm_gem_object_lookup(filp, gem_handle); | 287 | obj = drm_gem_object_lookup(filp, gem_handle); |
327 | if (!obj) { | 288 | if (!obj) |
328 | DRM_ERROR("failed to lookup gem object.\n"); | 289 | return NULL; |
329 | return; | 290 | return to_exynos_gem(obj); |
330 | } | ||
331 | |||
332 | drm_gem_object_unreference_unlocked(obj); | ||
333 | |||
334 | /* | ||
335 | * decrease obj->refcount one more time because we has already | ||
336 | * increased it at exynos_drm_gem_get_dma_addr(). | ||
337 | */ | ||
338 | drm_gem_object_unreference_unlocked(obj); | ||
339 | } | 291 | } |
340 | 292 | ||
341 | static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, | 293 | static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, |
@@ -383,7 +335,7 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, | |||
383 | args->flags = exynos_gem->flags; | 335 | args->flags = exynos_gem->flags; |
384 | args->size = exynos_gem->size; | 336 | args->size = exynos_gem->size; |
385 | 337 | ||
386 | drm_gem_object_unreference_unlocked(obj); | 338 | drm_gem_object_put_unlocked(obj); |
387 | 339 | ||
388 | return 0; | 340 | return 0; |
389 | } | 341 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 9057d7f1d6ed..d46a62c30812 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h | |||
@@ -77,32 +77,26 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data, | |||
77 | struct drm_file *file_priv); | 77 | struct drm_file *file_priv); |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * get dma address from gem handle and this function could be used for | 80 | * get exynos drm object from gem handle, this function could be used for |
81 | * other drivers such as 2d/3d acceleration drivers. | 81 | * other drivers such as 2d/3d acceleration drivers. |
82 | * with this function call, gem object reference count would be increased. | 82 | * with this function call, gem object reference count would be increased. |
83 | */ | 83 | */ |
84 | dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, | 84 | struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, |
85 | unsigned int gem_handle, | 85 | unsigned int gem_handle); |
86 | struct drm_file *filp); | ||
87 | 86 | ||
88 | /* | 87 | /* |
89 | * put dma address from gem handle and this function could be used for | 88 | * put exynos drm object acquired from exynos_drm_gem_get(), |
90 | * other drivers such as 2d/3d acceleration drivers. | 89 | * gem object reference count would be decreased. |
91 | * with this function call, gem object reference count would be decreased. | ||
92 | */ | 90 | */ |
93 | void exynos_drm_gem_put_dma_addr(struct drm_device *dev, | 91 | static inline void exynos_drm_gem_put(struct exynos_drm_gem *exynos_gem) |
94 | unsigned int gem_handle, | 92 | { |
95 | struct drm_file *filp); | 93 | drm_gem_object_put_unlocked(&exynos_gem->base); |
94 | } | ||
96 | 95 | ||
97 | /* get buffer information to memory region allocated by gem. */ | 96 | /* get buffer information to memory region allocated by gem. */ |
98 | int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, | 97 | int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, |
99 | struct drm_file *file_priv); | 98 | struct drm_file *file_priv); |
100 | 99 | ||
101 | /* get buffer size to gem handle. */ | ||
102 | unsigned long exynos_drm_gem_get_size(struct drm_device *dev, | ||
103 | unsigned int gem_handle, | ||
104 | struct drm_file *file_priv); | ||
105 | |||
106 | /* free gem object. */ | 100 | /* free gem object. */ |
107 | void exynos_drm_gem_free_object(struct drm_gem_object *obj); | 101 | void exynos_drm_gem_free_object(struct drm_gem_object *obj); |
108 | 102 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 35ac66730563..7ba414b52faa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c | |||
@@ -492,21 +492,25 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt) | |||
492 | GSC_IN_CHROMA_ORDER_CRCB); | 492 | GSC_IN_CHROMA_ORDER_CRCB); |
493 | break; | 493 | break; |
494 | case DRM_FORMAT_NV21: | 494 | case DRM_FORMAT_NV21: |
495 | cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P); | ||
496 | break; | ||
495 | case DRM_FORMAT_NV61: | 497 | case DRM_FORMAT_NV61: |
496 | cfg |= (GSC_IN_CHROMA_ORDER_CRCB | | 498 | cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P); |
497 | GSC_IN_YUV420_2P); | ||
498 | break; | 499 | break; |
499 | case DRM_FORMAT_YUV422: | 500 | case DRM_FORMAT_YUV422: |
500 | cfg |= GSC_IN_YUV422_3P; | 501 | cfg |= GSC_IN_YUV422_3P; |
501 | break; | 502 | break; |
502 | case DRM_FORMAT_YUV420: | 503 | case DRM_FORMAT_YUV420: |
504 | cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); | ||
505 | break; | ||
503 | case DRM_FORMAT_YVU420: | 506 | case DRM_FORMAT_YVU420: |
504 | cfg |= GSC_IN_YUV420_3P; | 507 | cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P); |
505 | break; | 508 | break; |
506 | case DRM_FORMAT_NV12: | 509 | case DRM_FORMAT_NV12: |
510 | cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); | ||
511 | break; | ||
507 | case DRM_FORMAT_NV16: | 512 | case DRM_FORMAT_NV16: |
508 | cfg |= (GSC_IN_CHROMA_ORDER_CBCR | | 513 | cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P); |
509 | GSC_IN_YUV420_2P); | ||
510 | break; | 514 | break; |
511 | } | 515 | } |
512 | 516 | ||
@@ -523,30 +527,30 @@ static void gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation) | |||
523 | 527 | ||
524 | switch (degree) { | 528 | switch (degree) { |
525 | case DRM_MODE_ROTATE_0: | 529 | case DRM_MODE_ROTATE_0: |
526 | if (rotation & DRM_MODE_REFLECT_Y) | ||
527 | cfg |= GSC_IN_ROT_XFLIP; | ||
528 | if (rotation & DRM_MODE_REFLECT_X) | 530 | if (rotation & DRM_MODE_REFLECT_X) |
531 | cfg |= GSC_IN_ROT_XFLIP; | ||
532 | if (rotation & DRM_MODE_REFLECT_Y) | ||
529 | cfg |= GSC_IN_ROT_YFLIP; | 533 | cfg |= GSC_IN_ROT_YFLIP; |
530 | break; | 534 | break; |
531 | case DRM_MODE_ROTATE_90: | 535 | case DRM_MODE_ROTATE_90: |
532 | cfg |= GSC_IN_ROT_90; | 536 | cfg |= GSC_IN_ROT_90; |
533 | if (rotation & DRM_MODE_REFLECT_Y) | ||
534 | cfg |= GSC_IN_ROT_XFLIP; | ||
535 | if (rotation & DRM_MODE_REFLECT_X) | 537 | if (rotation & DRM_MODE_REFLECT_X) |
538 | cfg |= GSC_IN_ROT_XFLIP; | ||
539 | if (rotation & DRM_MODE_REFLECT_Y) | ||
536 | cfg |= GSC_IN_ROT_YFLIP; | 540 | cfg |= GSC_IN_ROT_YFLIP; |
537 | break; | 541 | break; |
538 | case DRM_MODE_ROTATE_180: | 542 | case DRM_MODE_ROTATE_180: |
539 | cfg |= GSC_IN_ROT_180; | 543 | cfg |= GSC_IN_ROT_180; |
540 | if (rotation & DRM_MODE_REFLECT_Y) | ||
541 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
542 | if (rotation & DRM_MODE_REFLECT_X) | 544 | if (rotation & DRM_MODE_REFLECT_X) |
545 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
546 | if (rotation & DRM_MODE_REFLECT_Y) | ||
543 | cfg &= ~GSC_IN_ROT_YFLIP; | 547 | cfg &= ~GSC_IN_ROT_YFLIP; |
544 | break; | 548 | break; |
545 | case DRM_MODE_ROTATE_270: | 549 | case DRM_MODE_ROTATE_270: |
546 | cfg |= GSC_IN_ROT_270; | 550 | cfg |= GSC_IN_ROT_270; |
547 | if (rotation & DRM_MODE_REFLECT_Y) | ||
548 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
549 | if (rotation & DRM_MODE_REFLECT_X) | 551 | if (rotation & DRM_MODE_REFLECT_X) |
552 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
553 | if (rotation & DRM_MODE_REFLECT_Y) | ||
550 | cfg &= ~GSC_IN_ROT_YFLIP; | 554 | cfg &= ~GSC_IN_ROT_YFLIP; |
551 | break; | 555 | break; |
552 | } | 556 | } |
@@ -577,7 +581,7 @@ static void gsc_src_set_size(struct gsc_context *ctx, | |||
577 | cfg &= ~(GSC_SRCIMG_HEIGHT_MASK | | 581 | cfg &= ~(GSC_SRCIMG_HEIGHT_MASK | |
578 | GSC_SRCIMG_WIDTH_MASK); | 582 | GSC_SRCIMG_WIDTH_MASK); |
579 | 583 | ||
580 | cfg |= (GSC_SRCIMG_WIDTH(buf->buf.width) | | 584 | cfg |= (GSC_SRCIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) | |
581 | GSC_SRCIMG_HEIGHT(buf->buf.height)); | 585 | GSC_SRCIMG_HEIGHT(buf->buf.height)); |
582 | 586 | ||
583 | gsc_write(cfg, GSC_SRCIMG_SIZE); | 587 | gsc_write(cfg, GSC_SRCIMG_SIZE); |
@@ -672,18 +676,25 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt) | |||
672 | GSC_OUT_CHROMA_ORDER_CRCB); | 676 | GSC_OUT_CHROMA_ORDER_CRCB); |
673 | break; | 677 | break; |
674 | case DRM_FORMAT_NV21: | 678 | case DRM_FORMAT_NV21: |
675 | case DRM_FORMAT_NV61: | ||
676 | cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P); | 679 | cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P); |
677 | break; | 680 | break; |
681 | case DRM_FORMAT_NV61: | ||
682 | cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P); | ||
683 | break; | ||
678 | case DRM_FORMAT_YUV422: | 684 | case DRM_FORMAT_YUV422: |
685 | cfg |= GSC_OUT_YUV422_3P; | ||
686 | break; | ||
679 | case DRM_FORMAT_YUV420: | 687 | case DRM_FORMAT_YUV420: |
688 | cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); | ||
689 | break; | ||
680 | case DRM_FORMAT_YVU420: | 690 | case DRM_FORMAT_YVU420: |
681 | cfg |= GSC_OUT_YUV420_3P; | 691 | cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P); |
682 | break; | 692 | break; |
683 | case DRM_FORMAT_NV12: | 693 | case DRM_FORMAT_NV12: |
694 | cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); | ||
695 | break; | ||
684 | case DRM_FORMAT_NV16: | 696 | case DRM_FORMAT_NV16: |
685 | cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | | 697 | cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P); |
686 | GSC_OUT_YUV420_2P); | ||
687 | break; | 698 | break; |
688 | } | 699 | } |
689 | 700 | ||
@@ -868,7 +879,7 @@ static void gsc_dst_set_size(struct gsc_context *ctx, | |||
868 | /* original size */ | 879 | /* original size */ |
869 | cfg = gsc_read(GSC_DSTIMG_SIZE); | 880 | cfg = gsc_read(GSC_DSTIMG_SIZE); |
870 | cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK); | 881 | cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK); |
871 | cfg |= GSC_DSTIMG_WIDTH(buf->buf.width) | | 882 | cfg |= GSC_DSTIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) | |
872 | GSC_DSTIMG_HEIGHT(buf->buf.height); | 883 | GSC_DSTIMG_HEIGHT(buf->buf.height); |
873 | gsc_write(cfg, GSC_DSTIMG_SIZE); | 884 | gsc_write(cfg, GSC_DSTIMG_SIZE); |
874 | 885 | ||
@@ -1341,7 +1352,7 @@ static const struct drm_exynos_ipp_limit gsc_5420_limits[] = { | |||
1341 | }; | 1352 | }; |
1342 | 1353 | ||
1343 | static const struct drm_exynos_ipp_limit gsc_5433_limits[] = { | 1354 | static const struct drm_exynos_ipp_limit gsc_5433_limits[] = { |
1344 | { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 2 }, .v = { 16, 8191, 2 }) }, | 1355 | { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 16 }, .v = { 16, 8191, 2 }) }, |
1345 | { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) }, | 1356 | { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) }, |
1346 | { IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) }, | 1357 | { IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) }, |
1347 | { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 }, | 1358 | { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 }, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 26374e58c557..23226a0212e8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c | |||
@@ -345,39 +345,18 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf, | |||
345 | int ret = 0; | 345 | int ret = 0; |
346 | int i; | 346 | int i; |
347 | 347 | ||
348 | /* basic checks */ | ||
349 | if (buf->buf.width == 0 || buf->buf.height == 0) | ||
350 | return -EINVAL; | ||
351 | buf->format = drm_format_info(buf->buf.fourcc); | ||
352 | for (i = 0; i < buf->format->num_planes; i++) { | ||
353 | unsigned int width = (i == 0) ? buf->buf.width : | ||
354 | DIV_ROUND_UP(buf->buf.width, buf->format->hsub); | ||
355 | |||
356 | if (buf->buf.pitch[i] == 0) | ||
357 | buf->buf.pitch[i] = width * buf->format->cpp[i]; | ||
358 | if (buf->buf.pitch[i] < width * buf->format->cpp[i]) | ||
359 | return -EINVAL; | ||
360 | if (!buf->buf.gem_id[i]) | ||
361 | return -ENOENT; | ||
362 | } | ||
363 | |||
364 | /* pitch for additional planes must match */ | ||
365 | if (buf->format->num_planes > 2 && | ||
366 | buf->buf.pitch[1] != buf->buf.pitch[2]) | ||
367 | return -EINVAL; | ||
368 | |||
369 | /* get GEM buffers and check their size */ | 348 | /* get GEM buffers and check their size */ |
370 | for (i = 0; i < buf->format->num_planes; i++) { | 349 | for (i = 0; i < buf->format->num_planes; i++) { |
371 | unsigned int height = (i == 0) ? buf->buf.height : | 350 | unsigned int height = (i == 0) ? buf->buf.height : |
372 | DIV_ROUND_UP(buf->buf.height, buf->format->vsub); | 351 | DIV_ROUND_UP(buf->buf.height, buf->format->vsub); |
373 | unsigned long size = height * buf->buf.pitch[i]; | 352 | unsigned long size = height * buf->buf.pitch[i]; |
374 | struct drm_gem_object *obj = drm_gem_object_lookup(filp, | 353 | struct exynos_drm_gem *gem = exynos_drm_gem_get(filp, |
375 | buf->buf.gem_id[i]); | 354 | buf->buf.gem_id[i]); |
376 | if (!obj) { | 355 | if (!gem) { |
377 | ret = -ENOENT; | 356 | ret = -ENOENT; |
378 | goto gem_free; | 357 | goto gem_free; |
379 | } | 358 | } |
380 | buf->exynos_gem[i] = to_exynos_gem(obj); | 359 | buf->exynos_gem[i] = gem; |
381 | 360 | ||
382 | if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) { | 361 | if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) { |
383 | i++; | 362 | i++; |
@@ -391,7 +370,7 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf, | |||
391 | return 0; | 370 | return 0; |
392 | gem_free: | 371 | gem_free: |
393 | while (i--) { | 372 | while (i--) { |
394 | drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base); | 373 | exynos_drm_gem_put(buf->exynos_gem[i]); |
395 | buf->exynos_gem[i] = NULL; | 374 | buf->exynos_gem[i] = NULL; |
396 | } | 375 | } |
397 | return ret; | 376 | return ret; |
@@ -404,7 +383,7 @@ static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf) | |||
404 | if (!buf->exynos_gem[0]) | 383 | if (!buf->exynos_gem[0]) |
405 | return; | 384 | return; |
406 | for (i = 0; i < buf->format->num_planes; i++) | 385 | for (i = 0; i < buf->format->num_planes; i++) |
407 | drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base); | 386 | exynos_drm_gem_put(buf->exynos_gem[i]); |
408 | } | 387 | } |
409 | 388 | ||
410 | static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp, | 389 | static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp, |
@@ -428,7 +407,7 @@ enum drm_ipp_size_id { | |||
428 | IPP_LIMIT_BUFFER, IPP_LIMIT_AREA, IPP_LIMIT_ROTATED, IPP_LIMIT_MAX | 407 | IPP_LIMIT_BUFFER, IPP_LIMIT_AREA, IPP_LIMIT_ROTATED, IPP_LIMIT_MAX |
429 | }; | 408 | }; |
430 | 409 | ||
431 | static const enum drm_ipp_size_id limit_id_fallback[IPP_LIMIT_MAX][4] = { | 410 | static const enum drm_exynos_ipp_limit_type limit_id_fallback[IPP_LIMIT_MAX][4] = { |
432 | [IPP_LIMIT_BUFFER] = { DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER }, | 411 | [IPP_LIMIT_BUFFER] = { DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER }, |
433 | [IPP_LIMIT_AREA] = { DRM_EXYNOS_IPP_LIMIT_SIZE_AREA, | 412 | [IPP_LIMIT_AREA] = { DRM_EXYNOS_IPP_LIMIT_SIZE_AREA, |
434 | DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER }, | 413 | DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER }, |
@@ -495,12 +474,13 @@ static int exynos_drm_ipp_check_size_limits(struct exynos_drm_ipp_buffer *buf, | |||
495 | enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA; | 474 | enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA; |
496 | struct drm_ipp_limit l; | 475 | struct drm_ipp_limit l; |
497 | struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v; | 476 | struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v; |
477 | int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; | ||
498 | 478 | ||
499 | if (!limits) | 479 | if (!limits) |
500 | return 0; | 480 | return 0; |
501 | 481 | ||
502 | __get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l); | 482 | __get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l); |
503 | if (!__size_limit_check(buf->buf.width, &l.h) || | 483 | if (!__size_limit_check(real_width, &l.h) || |
504 | !__size_limit_check(buf->buf.height, &l.v)) | 484 | !__size_limit_check(buf->buf.height, &l.v)) |
505 | return -EINVAL; | 485 | return -EINVAL; |
506 | 486 | ||
@@ -560,10 +540,62 @@ static int exynos_drm_ipp_check_scale_limits( | |||
560 | return 0; | 540 | return 0; |
561 | } | 541 | } |
562 | 542 | ||
543 | static int exynos_drm_ipp_check_format(struct exynos_drm_ipp_task *task, | ||
544 | struct exynos_drm_ipp_buffer *buf, | ||
545 | struct exynos_drm_ipp_buffer *src, | ||
546 | struct exynos_drm_ipp_buffer *dst, | ||
547 | bool rotate, bool swap) | ||
548 | { | ||
549 | const struct exynos_drm_ipp_formats *fmt; | ||
550 | int ret, i; | ||
551 | |||
552 | fmt = __ipp_format_get(task->ipp, buf->buf.fourcc, buf->buf.modifier, | ||
553 | buf == src ? DRM_EXYNOS_IPP_FORMAT_SOURCE : | ||
554 | DRM_EXYNOS_IPP_FORMAT_DESTINATION); | ||
555 | if (!fmt) { | ||
556 | DRM_DEBUG_DRIVER("Task %pK: %s format not supported\n", task, | ||
557 | buf == src ? "src" : "dst"); | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | |||
561 | /* basic checks */ | ||
562 | if (buf->buf.width == 0 || buf->buf.height == 0) | ||
563 | return -EINVAL; | ||
564 | |||
565 | buf->format = drm_format_info(buf->buf.fourcc); | ||
566 | for (i = 0; i < buf->format->num_planes; i++) { | ||
567 | unsigned int width = (i == 0) ? buf->buf.width : | ||
568 | DIV_ROUND_UP(buf->buf.width, buf->format->hsub); | ||
569 | |||
570 | if (buf->buf.pitch[i] == 0) | ||
571 | buf->buf.pitch[i] = width * buf->format->cpp[i]; | ||
572 | if (buf->buf.pitch[i] < width * buf->format->cpp[i]) | ||
573 | return -EINVAL; | ||
574 | if (!buf->buf.gem_id[i]) | ||
575 | return -ENOENT; | ||
576 | } | ||
577 | |||
578 | /* pitch for additional planes must match */ | ||
579 | if (buf->format->num_planes > 2 && | ||
580 | buf->buf.pitch[1] != buf->buf.pitch[2]) | ||
581 | return -EINVAL; | ||
582 | |||
583 | /* check driver limits */ | ||
584 | ret = exynos_drm_ipp_check_size_limits(buf, fmt->limits, | ||
585 | fmt->num_limits, | ||
586 | rotate, | ||
587 | buf == dst ? swap : false); | ||
588 | if (ret) | ||
589 | return ret; | ||
590 | ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect, | ||
591 | fmt->limits, | ||
592 | fmt->num_limits, swap); | ||
593 | return ret; | ||
594 | } | ||
595 | |||
563 | static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task) | 596 | static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task) |
564 | { | 597 | { |
565 | struct exynos_drm_ipp *ipp = task->ipp; | 598 | struct exynos_drm_ipp *ipp = task->ipp; |
566 | const struct exynos_drm_ipp_formats *src_fmt, *dst_fmt; | ||
567 | struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst; | 599 | struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst; |
568 | unsigned int rotation = task->transform.rotation; | 600 | unsigned int rotation = task->transform.rotation; |
569 | int ret = 0; | 601 | int ret = 0; |
@@ -607,37 +639,11 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task) | |||
607 | return -EINVAL; | 639 | return -EINVAL; |
608 | } | 640 | } |
609 | 641 | ||
610 | src_fmt = __ipp_format_get(ipp, src->buf.fourcc, src->buf.modifier, | 642 | ret = exynos_drm_ipp_check_format(task, src, src, dst, rotate, swap); |
611 | DRM_EXYNOS_IPP_FORMAT_SOURCE); | ||
612 | if (!src_fmt) { | ||
613 | DRM_DEBUG_DRIVER("Task %pK: src format not supported\n", task); | ||
614 | return -EINVAL; | ||
615 | } | ||
616 | ret = exynos_drm_ipp_check_size_limits(src, src_fmt->limits, | ||
617 | src_fmt->num_limits, | ||
618 | rotate, false); | ||
619 | if (ret) | ||
620 | return ret; | ||
621 | ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect, | ||
622 | src_fmt->limits, | ||
623 | src_fmt->num_limits, swap); | ||
624 | if (ret) | 643 | if (ret) |
625 | return ret; | 644 | return ret; |
626 | 645 | ||
627 | dst_fmt = __ipp_format_get(ipp, dst->buf.fourcc, dst->buf.modifier, | 646 | ret = exynos_drm_ipp_check_format(task, dst, src, dst, false, swap); |
628 | DRM_EXYNOS_IPP_FORMAT_DESTINATION); | ||
629 | if (!dst_fmt) { | ||
630 | DRM_DEBUG_DRIVER("Task %pK: dst format not supported\n", task); | ||
631 | return -EINVAL; | ||
632 | } | ||
633 | ret = exynos_drm_ipp_check_size_limits(dst, dst_fmt->limits, | ||
634 | dst_fmt->num_limits, | ||
635 | false, swap); | ||
636 | if (ret) | ||
637 | return ret; | ||
638 | ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect, | ||
639 | dst_fmt->limits, | ||
640 | dst_fmt->num_limits, swap); | ||
641 | if (ret) | 647 | if (ret) |
642 | return ret; | 648 | return ret; |
643 | 649 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 2174814273e2..2fd299a58297 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c | |||
@@ -367,6 +367,8 @@ static int exynos_mic_resume(struct device *dev) | |||
367 | 367 | ||
368 | static const struct dev_pm_ops exynos_mic_pm_ops = { | 368 | static const struct dev_pm_ops exynos_mic_pm_ops = { |
369 | SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL) | 369 | SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL) |
370 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
371 | pm_runtime_force_resume) | ||
370 | }; | 372 | }; |
371 | 373 | ||
372 | static int exynos_mic_probe(struct platform_device *pdev) | 374 | static int exynos_mic_probe(struct platform_device *pdev) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index eb9915da7dec..dba29aec59b4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c | |||
@@ -132,7 +132,7 @@ static void exynos_drm_plane_reset(struct drm_plane *plane) | |||
132 | if (plane->state) { | 132 | if (plane->state) { |
133 | exynos_state = to_exynos_plane_state(plane->state); | 133 | exynos_state = to_exynos_plane_state(plane->state); |
134 | if (exynos_state->base.fb) | 134 | if (exynos_state->base.fb) |
135 | drm_framebuffer_unreference(exynos_state->base.fb); | 135 | drm_framebuffer_put(exynos_state->base.fb); |
136 | kfree(exynos_state); | 136 | kfree(exynos_state); |
137 | plane->state = NULL; | 137 | plane->state = NULL; |
138 | } | 138 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index 1a76dd3d52e1..a820a68429b9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c | |||
@@ -168,9 +168,9 @@ static void rotator_dst_set_transf(struct rot_context *rot, | |||
168 | val &= ~ROT_CONTROL_FLIP_MASK; | 168 | val &= ~ROT_CONTROL_FLIP_MASK; |
169 | 169 | ||
170 | if (rotation & DRM_MODE_REFLECT_X) | 170 | if (rotation & DRM_MODE_REFLECT_X) |
171 | val |= ROT_CONTROL_FLIP_HORIZONTAL; | ||
172 | if (rotation & DRM_MODE_REFLECT_Y) | ||
173 | val |= ROT_CONTROL_FLIP_VERTICAL; | 171 | val |= ROT_CONTROL_FLIP_VERTICAL; |
172 | if (rotation & DRM_MODE_REFLECT_Y) | ||
173 | val |= ROT_CONTROL_FLIP_HORIZONTAL; | ||
174 | 174 | ||
175 | val &= ~ROT_CONTROL_ROT_MASK; | 175 | val &= ~ROT_CONTROL_ROT_MASK; |
176 | 176 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c index 91d4382343d0..0ddb6eec7b11 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c +++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset)) | 30 | #define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset)) |
31 | #define SCALER_MAX_CLK 4 | 31 | #define SCALER_MAX_CLK 4 |
32 | #define SCALER_AUTOSUSPEND_DELAY 2000 | 32 | #define SCALER_AUTOSUSPEND_DELAY 2000 |
33 | #define SCALER_RESET_WAIT_RETRIES 100 | ||
33 | 34 | ||
34 | struct scaler_data { | 35 | struct scaler_data { |
35 | const char *clk_name[SCALER_MAX_CLK]; | 36 | const char *clk_name[SCALER_MAX_CLK]; |
@@ -51,9 +52,9 @@ struct scaler_context { | |||
51 | static u32 scaler_get_format(u32 drm_fmt) | 52 | static u32 scaler_get_format(u32 drm_fmt) |
52 | { | 53 | { |
53 | switch (drm_fmt) { | 54 | switch (drm_fmt) { |
54 | case DRM_FORMAT_NV21: | ||
55 | return SCALER_YUV420_2P_UV; | ||
56 | case DRM_FORMAT_NV12: | 55 | case DRM_FORMAT_NV12: |
56 | return SCALER_YUV420_2P_UV; | ||
57 | case DRM_FORMAT_NV21: | ||
57 | return SCALER_YUV420_2P_VU; | 58 | return SCALER_YUV420_2P_VU; |
58 | case DRM_FORMAT_YUV420: | 59 | case DRM_FORMAT_YUV420: |
59 | return SCALER_YUV420_3P; | 60 | return SCALER_YUV420_3P; |
@@ -63,15 +64,15 @@ static u32 scaler_get_format(u32 drm_fmt) | |||
63 | return SCALER_YUV422_1P_UYVY; | 64 | return SCALER_YUV422_1P_UYVY; |
64 | case DRM_FORMAT_YVYU: | 65 | case DRM_FORMAT_YVYU: |
65 | return SCALER_YUV422_1P_YVYU; | 66 | return SCALER_YUV422_1P_YVYU; |
66 | case DRM_FORMAT_NV61: | ||
67 | return SCALER_YUV422_2P_UV; | ||
68 | case DRM_FORMAT_NV16: | 67 | case DRM_FORMAT_NV16: |
68 | return SCALER_YUV422_2P_UV; | ||
69 | case DRM_FORMAT_NV61: | ||
69 | return SCALER_YUV422_2P_VU; | 70 | return SCALER_YUV422_2P_VU; |
70 | case DRM_FORMAT_YUV422: | 71 | case DRM_FORMAT_YUV422: |
71 | return SCALER_YUV422_3P; | 72 | return SCALER_YUV422_3P; |
72 | case DRM_FORMAT_NV42: | ||
73 | return SCALER_YUV444_2P_UV; | ||
74 | case DRM_FORMAT_NV24: | 73 | case DRM_FORMAT_NV24: |
74 | return SCALER_YUV444_2P_UV; | ||
75 | case DRM_FORMAT_NV42: | ||
75 | return SCALER_YUV444_2P_VU; | 76 | return SCALER_YUV444_2P_VU; |
76 | case DRM_FORMAT_YUV444: | 77 | case DRM_FORMAT_YUV444: |
77 | return SCALER_YUV444_3P; | 78 | return SCALER_YUV444_3P; |
@@ -100,6 +101,23 @@ static u32 scaler_get_format(u32 drm_fmt) | |||
100 | return 0; | 101 | return 0; |
101 | } | 102 | } |
102 | 103 | ||
104 | static inline int scaler_reset(struct scaler_context *scaler) | ||
105 | { | ||
106 | int retry = SCALER_RESET_WAIT_RETRIES; | ||
107 | |||
108 | scaler_write(SCALER_CFG_SOFT_RESET, SCALER_CFG); | ||
109 | do { | ||
110 | cpu_relax(); | ||
111 | } while (retry > 1 && | ||
112 | scaler_read(SCALER_CFG) & SCALER_CFG_SOFT_RESET); | ||
113 | do { | ||
114 | cpu_relax(); | ||
115 | scaler_write(1, SCALER_INT_EN); | ||
116 | } while (retry > 0 && scaler_read(SCALER_INT_EN) != 1); | ||
117 | |||
118 | return retry ? 0 : -EIO; | ||
119 | } | ||
120 | |||
103 | static inline void scaler_enable_int(struct scaler_context *scaler) | 121 | static inline void scaler_enable_int(struct scaler_context *scaler) |
104 | { | 122 | { |
105 | u32 val; | 123 | u32 val; |
@@ -354,9 +372,13 @@ static int scaler_commit(struct exynos_drm_ipp *ipp, | |||
354 | u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc); | 372 | u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc); |
355 | struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect; | 373 | struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect; |
356 | 374 | ||
357 | scaler->task = task; | ||
358 | |||
359 | pm_runtime_get_sync(scaler->dev); | 375 | pm_runtime_get_sync(scaler->dev); |
376 | if (scaler_reset(scaler)) { | ||
377 | pm_runtime_put(scaler->dev); | ||
378 | return -EIO; | ||
379 | } | ||
380 | |||
381 | scaler->task = task; | ||
360 | 382 | ||
361 | scaler_set_src_fmt(scaler, src_fmt); | 383 | scaler_set_src_fmt(scaler, src_fmt); |
362 | scaler_set_src_base(scaler, &task->src); | 384 | scaler_set_src_base(scaler, &task->src); |
@@ -394,7 +416,11 @@ static inline void scaler_disable_int(struct scaler_context *scaler) | |||
394 | 416 | ||
395 | static inline u32 scaler_get_int_status(struct scaler_context *scaler) | 417 | static inline u32 scaler_get_int_status(struct scaler_context *scaler) |
396 | { | 418 | { |
397 | return scaler_read(SCALER_INT_STATUS); | 419 | u32 val = scaler_read(SCALER_INT_STATUS); |
420 | |||
421 | scaler_write(val, SCALER_INT_STATUS); | ||
422 | |||
423 | return val; | ||
398 | } | 424 | } |
399 | 425 | ||
400 | static inline int scaler_task_done(u32 val) | 426 | static inline int scaler_task_done(u32 val) |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 3a11c719a580..2092a650df7d 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -2093,6 +2093,8 @@ static int __maybe_unused exynos_hdmi_resume(struct device *dev) | |||
2093 | 2093 | ||
2094 | static const struct dev_pm_ops exynos_hdmi_pm_ops = { | 2094 | static const struct dev_pm_ops exynos_hdmi_pm_ops = { |
2095 | SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL) | 2095 | SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL) |
2096 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
2097 | pm_runtime_force_resume) | ||
2096 | }; | 2098 | }; |
2097 | 2099 | ||
2098 | struct platform_driver hdmi_driver = { | 2100 | struct platform_driver hdmi_driver = { |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 272c79f5f5bf..ffbf4a950f69 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -837,8 +837,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, | |||
837 | struct drm_device *drm_dev) | 837 | struct drm_device *drm_dev) |
838 | { | 838 | { |
839 | int ret; | 839 | int ret; |
840 | struct exynos_drm_private *priv; | ||
841 | priv = drm_dev->dev_private; | ||
842 | 840 | ||
843 | mixer_ctx->drm_dev = drm_dev; | 841 | mixer_ctx->drm_dev = drm_dev; |
844 | 842 | ||
@@ -1271,6 +1269,8 @@ static int __maybe_unused exynos_mixer_resume(struct device *dev) | |||
1271 | 1269 | ||
1272 | static const struct dev_pm_ops exynos_mixer_pm_ops = { | 1270 | static const struct dev_pm_ops exynos_mixer_pm_ops = { |
1273 | SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL) | 1271 | SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL) |
1272 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
1273 | pm_runtime_force_resume) | ||
1274 | }; | 1274 | }; |
1275 | 1275 | ||
1276 | struct platform_driver mixer_driver = { | 1276 | struct platform_driver mixer_driver = { |
diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 4704a993cbb7..16b39734115c 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h | |||
@@ -138,6 +138,7 @@ | |||
138 | #define GSC_OUT_YUV420_3P (3 << 4) | 138 | #define GSC_OUT_YUV420_3P (3 << 4) |
139 | #define GSC_OUT_YUV422_1P (4 << 4) | 139 | #define GSC_OUT_YUV422_1P (4 << 4) |
140 | #define GSC_OUT_YUV422_2P (5 << 4) | 140 | #define GSC_OUT_YUV422_2P (5 << 4) |
141 | #define GSC_OUT_YUV422_3P (6 << 4) | ||
141 | #define GSC_OUT_YUV444 (7 << 4) | 142 | #define GSC_OUT_YUV444 (7 << 4) |
142 | #define GSC_OUT_TILE_TYPE_MASK (1 << 2) | 143 | #define GSC_OUT_TILE_TYPE_MASK (1 << 2) |
143 | #define GSC_OUT_TILE_C_16x8 (0 << 2) | 144 | #define GSC_OUT_TILE_C_16x8 (0 << 2) |