diff options
Diffstat (limited to 'drivers/gpu/drm/imx/imx-drm-core.c')
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 120 |
1 files changed, 78 insertions, 42 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 7746418a4c08..9f7dafce3a4c 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
@@ -15,10 +15,14 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/component.h> | 16 | #include <linux/component.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/dma-buf.h> | ||
18 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/reservation.h> | ||
21 | #include <drm/drmP.h> | 23 | #include <drm/drmP.h> |
24 | #include <drm/drm_atomic.h> | ||
25 | #include <drm/drm_atomic_helper.h> | ||
22 | #include <drm/drm_fb_helper.h> | 26 | #include <drm/drm_fb_helper.h> |
23 | #include <drm/drm_crtc_helper.h> | 27 | #include <drm/drm_crtc_helper.h> |
24 | #include <drm/drm_gem_cma_helper.h> | 28 | #include <drm/drm_gem_cma_helper.h> |
@@ -41,6 +45,7 @@ struct imx_drm_device { | |||
41 | struct imx_drm_crtc *crtc[MAX_CRTC]; | 45 | struct imx_drm_crtc *crtc[MAX_CRTC]; |
42 | unsigned int pipes; | 46 | unsigned int pipes; |
43 | struct drm_fbdev_cma *fbhelper; | 47 | struct drm_fbdev_cma *fbhelper; |
48 | struct drm_atomic_state *state; | ||
44 | }; | 49 | }; |
45 | 50 | ||
46 | struct imx_drm_crtc { | 51 | struct imx_drm_crtc { |
@@ -85,45 +90,6 @@ static int imx_drm_driver_unload(struct drm_device *drm) | |||
85 | return 0; | 90 | return 0; |
86 | } | 91 | } |
87 | 92 | ||
88 | static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) | ||
89 | { | ||
90 | struct imx_drm_device *imxdrm = crtc->dev->dev_private; | ||
91 | unsigned i; | ||
92 | |||
93 | for (i = 0; i < MAX_CRTC; i++) | ||
94 | if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc) | ||
95 | return imxdrm->crtc[i]; | ||
96 | |||
97 | return NULL; | ||
98 | } | ||
99 | |||
100 | int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format, | ||
101 | int hsync_pin, int vsync_pin, u32 bus_flags) | ||
102 | { | ||
103 | struct imx_drm_crtc_helper_funcs *helper; | ||
104 | struct imx_drm_crtc *imx_crtc; | ||
105 | |||
106 | imx_crtc = imx_drm_find_crtc(encoder->crtc); | ||
107 | if (!imx_crtc) | ||
108 | return -EINVAL; | ||
109 | |||
110 | helper = &imx_crtc->imx_drm_helper_funcs; | ||
111 | if (helper->set_interface_pix_fmt) | ||
112 | return helper->set_interface_pix_fmt(encoder->crtc, | ||
113 | bus_format, hsync_pin, vsync_pin, | ||
114 | bus_flags); | ||
115 | return 0; | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(imx_drm_set_bus_config); | ||
118 | |||
119 | int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) | ||
120 | { | ||
121 | return imx_drm_set_bus_config(encoder, bus_format, 2, 3, | ||
122 | DRM_BUS_FLAG_DE_HIGH | | ||
123 | DRM_BUS_FLAG_PIXDATA_NEGEDGE); | ||
124 | } | ||
125 | EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); | ||
126 | |||
127 | int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) | 93 | int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) |
128 | { | 94 | { |
129 | return drm_crtc_vblank_get(imx_drm_crtc->crtc); | 95 | return drm_crtc_vblank_get(imx_drm_crtc->crtc); |
@@ -208,6 +174,63 @@ static void imx_drm_output_poll_changed(struct drm_device *drm) | |||
208 | static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { | 174 | static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { |
209 | .fb_create = drm_fb_cma_create, | 175 | .fb_create = drm_fb_cma_create, |
210 | .output_poll_changed = imx_drm_output_poll_changed, | 176 | .output_poll_changed = imx_drm_output_poll_changed, |
177 | .atomic_check = drm_atomic_helper_check, | ||
178 | .atomic_commit = drm_atomic_helper_commit, | ||
179 | }; | ||
180 | |||
181 | static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) | ||
182 | { | ||
183 | struct drm_device *dev = state->dev; | ||
184 | struct drm_crtc *crtc; | ||
185 | struct drm_crtc_state *crtc_state; | ||
186 | struct drm_plane_state *plane_state; | ||
187 | struct drm_gem_cma_object *cma_obj; | ||
188 | struct fence *excl; | ||
189 | unsigned shared_count; | ||
190 | struct fence **shared; | ||
191 | unsigned int i, j; | ||
192 | int ret; | ||
193 | |||
194 | /* Wait for fences. */ | ||
195 | for_each_crtc_in_state(state, crtc, crtc_state, i) { | ||
196 | plane_state = crtc->primary->state; | ||
197 | if (plane_state->fb) { | ||
198 | cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0); | ||
199 | if (cma_obj->base.dma_buf) { | ||
200 | ret = reservation_object_get_fences_rcu( | ||
201 | cma_obj->base.dma_buf->resv, &excl, | ||
202 | &shared_count, &shared); | ||
203 | if (unlikely(ret)) | ||
204 | DRM_ERROR("failed to get fences " | ||
205 | "for buffer\n"); | ||
206 | |||
207 | if (excl) { | ||
208 | fence_wait(excl, false); | ||
209 | fence_put(excl); | ||
210 | } | ||
211 | for (j = 0; j < shared_count; i++) { | ||
212 | fence_wait(shared[j], false); | ||
213 | fence_put(shared[j]); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | drm_atomic_helper_commit_modeset_disables(dev, state); | ||
220 | |||
221 | drm_atomic_helper_commit_planes(dev, state, true); | ||
222 | |||
223 | drm_atomic_helper_commit_modeset_enables(dev, state); | ||
224 | |||
225 | drm_atomic_helper_commit_hw_done(state); | ||
226 | |||
227 | drm_atomic_helper_wait_for_vblanks(dev, state); | ||
228 | |||
229 | drm_atomic_helper_cleanup_planes(dev, state); | ||
230 | } | ||
231 | |||
232 | static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { | ||
233 | .atomic_commit_tail = imx_drm_atomic_commit_tail, | ||
211 | }; | 234 | }; |
212 | 235 | ||
213 | /* | 236 | /* |
@@ -249,6 +272,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
249 | drm->mode_config.max_width = 4096; | 272 | drm->mode_config.max_width = 4096; |
250 | drm->mode_config.max_height = 4096; | 273 | drm->mode_config.max_height = 4096; |
251 | drm->mode_config.funcs = &imx_drm_mode_config_funcs; | 274 | drm->mode_config.funcs = &imx_drm_mode_config_funcs; |
275 | drm->mode_config.helper_private = &imx_drm_mode_config_helpers; | ||
252 | 276 | ||
253 | drm_mode_config_init(drm); | 277 | drm_mode_config_init(drm); |
254 | 278 | ||
@@ -279,6 +303,8 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
279 | } | 303 | } |
280 | } | 304 | } |
281 | 305 | ||
306 | drm_mode_config_reset(drm); | ||
307 | |||
282 | /* | 308 | /* |
283 | * All components are now initialised, so setup the fb helper. | 309 | * All components are now initialised, so setup the fb helper. |
284 | * The fb helper takes copies of key hardware information, so the | 310 | * The fb helper takes copies of key hardware information, so the |
@@ -289,7 +315,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
289 | dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); | 315 | dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); |
290 | legacyfb_depth = 16; | 316 | legacyfb_depth = 16; |
291 | } | 317 | } |
292 | drm_helper_disable_unused_functions(drm); | ||
293 | imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, | 318 | imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, |
294 | drm->mode_config.num_crtc, MAX_CRTC); | 319 | drm->mode_config.num_crtc, MAX_CRTC); |
295 | if (IS_ERR(imxdrm->fbhelper)) { | 320 | if (IS_ERR(imxdrm->fbhelper)) { |
@@ -403,7 +428,8 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = { | |||
403 | }; | 428 | }; |
404 | 429 | ||
405 | static struct drm_driver imx_drm_driver = { | 430 | static struct drm_driver imx_drm_driver = { |
406 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, | 431 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | |
432 | DRIVER_ATOMIC, | ||
407 | .load = imx_drm_driver_load, | 433 | .load = imx_drm_driver_load, |
408 | .unload = imx_drm_driver_unload, | 434 | .unload = imx_drm_driver_unload, |
409 | .lastclose = imx_drm_driver_lastclose, | 435 | .lastclose = imx_drm_driver_lastclose, |
@@ -491,6 +517,7 @@ static int imx_drm_platform_remove(struct platform_device *pdev) | |||
491 | static int imx_drm_suspend(struct device *dev) | 517 | static int imx_drm_suspend(struct device *dev) |
492 | { | 518 | { |
493 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 519 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
520 | struct imx_drm_device *imxdrm; | ||
494 | 521 | ||
495 | /* The drm_dev is NULL before .load hook is called */ | 522 | /* The drm_dev is NULL before .load hook is called */ |
496 | if (drm_dev == NULL) | 523 | if (drm_dev == NULL) |
@@ -498,17 +525,26 @@ static int imx_drm_suspend(struct device *dev) | |||
498 | 525 | ||
499 | drm_kms_helper_poll_disable(drm_dev); | 526 | drm_kms_helper_poll_disable(drm_dev); |
500 | 527 | ||
528 | imxdrm = drm_dev->dev_private; | ||
529 | imxdrm->state = drm_atomic_helper_suspend(drm_dev); | ||
530 | if (IS_ERR(imxdrm->state)) { | ||
531 | drm_kms_helper_poll_enable(drm_dev); | ||
532 | return PTR_ERR(imxdrm->state); | ||
533 | } | ||
534 | |||
501 | return 0; | 535 | return 0; |
502 | } | 536 | } |
503 | 537 | ||
504 | static int imx_drm_resume(struct device *dev) | 538 | static int imx_drm_resume(struct device *dev) |
505 | { | 539 | { |
506 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 540 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
541 | struct imx_drm_device *imx_drm; | ||
507 | 542 | ||
508 | if (drm_dev == NULL) | 543 | if (drm_dev == NULL) |
509 | return 0; | 544 | return 0; |
510 | 545 | ||
511 | drm_helper_resume_force_mode(drm_dev); | 546 | imx_drm = drm_dev->dev_private; |
547 | drm_atomic_helper_resume(drm_dev, imx_drm->state); | ||
512 | drm_kms_helper_poll_enable(drm_dev); | 548 | drm_kms_helper_poll_enable(drm_dev); |
513 | 549 | ||
514 | return 0; | 550 | return 0; |