diff options
author | Liu Ying <gnuiyl@gmail.com> | 2016-07-08 05:40:59 -0400 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2016-07-12 12:24:03 -0400 |
commit | 5f2f911578fb13b0110e125d43775f08cf1dd281 (patch) | |
tree | 06cb1b02843dd9c874504e143af14d2546c2a985 /drivers/gpu/drm/imx | |
parent | 032003c5cd744e8e0baf5430fc5b3fd5462208e4 (diff) |
drm/imx: atomic phase 3 step 1: Use atomic configuration
Replacing drm_crtc_helper_set_config() by drm_atomic_helper_set_config()
and converting the suspend/resume operations to atomic make us be able
to use atomic configurations. All of these allow us to remove the
crtc_funcs->mode_set callback as it is no longer used. Also, change
the plane_funcs->update/disable_plane callbacks from the transitional
version to the atomic version. Furthermore, switching to the pure atomic
version of set_config callback means that we may implement CRTC/plane
atomic checks by using the new CRTC/plane states instead of the legacy
ones and we may remove the private ipu_crtc->enabled state which was left
there for the transitional atomic helpers in phase 1. Page flip is also
switched to the atomic version. Last, the legacy function
drm_helper_disable_unused_functions() is removed from ->load in order
not to confuse the atomic driver.
Signed-off-by: Liu Ying <gnuiyl@gmail.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers/gpu/drm/imx')
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-crtc.c | 209 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 135 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.h | 2 |
4 files changed, 114 insertions, 308 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index f6e44c220874..f14ad2bbc1d7 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 { |
@@ -169,6 +174,63 @@ static void imx_drm_output_poll_changed(struct drm_device *drm) | |||
169 | 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 = { |
170 | .fb_create = drm_fb_cma_create, | 175 | .fb_create = drm_fb_cma_create, |
171 | .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, | ||
172 | }; | 234 | }; |
173 | 235 | ||
174 | /* | 236 | /* |
@@ -210,6 +272,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
210 | drm->mode_config.max_width = 4096; | 272 | drm->mode_config.max_width = 4096; |
211 | drm->mode_config.max_height = 4096; | 273 | drm->mode_config.max_height = 4096; |
212 | 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; | ||
213 | 276 | ||
214 | drm_mode_config_init(drm); | 277 | drm_mode_config_init(drm); |
215 | 278 | ||
@@ -252,7 +315,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
252 | dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); | 315 | dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); |
253 | legacyfb_depth = 16; | 316 | legacyfb_depth = 16; |
254 | } | 317 | } |
255 | drm_helper_disable_unused_functions(drm); | ||
256 | imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, | 318 | imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, |
257 | drm->mode_config.num_crtc, MAX_CRTC); | 319 | drm->mode_config.num_crtc, MAX_CRTC); |
258 | if (IS_ERR(imxdrm->fbhelper)) { | 320 | if (IS_ERR(imxdrm->fbhelper)) { |
@@ -454,6 +516,7 @@ static int imx_drm_platform_remove(struct platform_device *pdev) | |||
454 | static int imx_drm_suspend(struct device *dev) | 516 | static int imx_drm_suspend(struct device *dev) |
455 | { | 517 | { |
456 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 518 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
519 | struct imx_drm_device *imxdrm; | ||
457 | 520 | ||
458 | /* The drm_dev is NULL before .load hook is called */ | 521 | /* The drm_dev is NULL before .load hook is called */ |
459 | if (drm_dev == NULL) | 522 | if (drm_dev == NULL) |
@@ -461,17 +524,26 @@ static int imx_drm_suspend(struct device *dev) | |||
461 | 524 | ||
462 | drm_kms_helper_poll_disable(drm_dev); | 525 | drm_kms_helper_poll_disable(drm_dev); |
463 | 526 | ||
527 | imxdrm = drm_dev->dev_private; | ||
528 | imxdrm->state = drm_atomic_helper_suspend(drm_dev); | ||
529 | if (IS_ERR(imxdrm->state)) { | ||
530 | drm_kms_helper_poll_enable(drm_dev); | ||
531 | return PTR_ERR(imxdrm->state); | ||
532 | } | ||
533 | |||
464 | return 0; | 534 | return 0; |
465 | } | 535 | } |
466 | 536 | ||
467 | static int imx_drm_resume(struct device *dev) | 537 | static int imx_drm_resume(struct device *dev) |
468 | { | 538 | { |
469 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 539 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
540 | struct imx_drm_device *imx_drm; | ||
470 | 541 | ||
471 | if (drm_dev == NULL) | 542 | if (drm_dev == NULL) |
472 | return 0; | 543 | return 0; |
473 | 544 | ||
474 | drm_helper_resume_force_mode(drm_dev); | 545 | imx_drm = drm_dev->dev_private; |
546 | drm_atomic_helper_resume(drm_dev, imx_drm->state); | ||
475 | drm_kms_helper_poll_enable(drm_dev); | 547 | drm_kms_helper_poll_enable(drm_dev); |
476 | 548 | ||
477 | return 0; | 549 | return 0; |
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index f9d5d7c5cd79..3e8253455121 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c | |||
@@ -24,8 +24,6 @@ | |||
24 | #include <linux/fb.h> | 24 | #include <linux/fb.h> |
25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
26 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
27 | #include <linux/reservation.h> | ||
28 | #include <linux/dma-buf.h> | ||
29 | #include <drm/drm_gem_cma_helper.h> | 27 | #include <drm/drm_gem_cma_helper.h> |
30 | #include <drm/drm_fb_cma_helper.h> | 28 | #include <drm/drm_fb_cma_helper.h> |
31 | 29 | ||
@@ -35,23 +33,6 @@ | |||
35 | 33 | ||
36 | #define DRIVER_DESC "i.MX IPUv3 Graphics" | 34 | #define DRIVER_DESC "i.MX IPUv3 Graphics" |
37 | 35 | ||
38 | enum ipu_flip_status { | ||
39 | IPU_FLIP_NONE, | ||
40 | IPU_FLIP_PENDING, | ||
41 | IPU_FLIP_SUBMITTED, | ||
42 | }; | ||
43 | |||
44 | struct ipu_flip_work { | ||
45 | struct work_struct unref_work; | ||
46 | struct drm_gem_object *bo; | ||
47 | struct drm_pending_vblank_event *page_flip_event; | ||
48 | struct work_struct fence_work; | ||
49 | struct ipu_crtc *crtc; | ||
50 | struct fence *excl; | ||
51 | unsigned shared_count; | ||
52 | struct fence **shared; | ||
53 | }; | ||
54 | |||
55 | struct ipu_crtc { | 36 | struct ipu_crtc { |
56 | struct device *dev; | 37 | struct device *dev; |
57 | struct drm_crtc base; | 38 | struct drm_crtc base; |
@@ -62,10 +43,6 @@ struct ipu_crtc { | |||
62 | 43 | ||
63 | struct ipu_dc *dc; | 44 | struct ipu_dc *dc; |
64 | struct ipu_di *di; | 45 | struct ipu_di *di; |
65 | int enabled; | ||
66 | enum ipu_flip_status flip_state; | ||
67 | struct workqueue_struct *flip_queue; | ||
68 | struct ipu_flip_work *flip_work; | ||
69 | int irq; | 46 | int irq; |
70 | }; | 47 | }; |
71 | 48 | ||
@@ -75,34 +52,26 @@ static void ipu_crtc_enable(struct ipu_crtc *ipu_crtc) | |||
75 | { | 52 | { |
76 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); | 53 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); |
77 | 54 | ||
78 | if (ipu_crtc->enabled) | ||
79 | return; | ||
80 | |||
81 | ipu_dc_enable(ipu); | 55 | ipu_dc_enable(ipu); |
82 | ipu_dc_enable_channel(ipu_crtc->dc); | 56 | ipu_dc_enable_channel(ipu_crtc->dc); |
83 | ipu_di_enable(ipu_crtc->di); | 57 | ipu_di_enable(ipu_crtc->di); |
84 | ipu_crtc->enabled = 1; | ||
85 | |||
86 | /* | ||
87 | * In order not to be warned on enabling vblank failure, | ||
88 | * we should call drm_crtc_vblank_on() after ->enabled is set to 1. | ||
89 | */ | ||
90 | drm_crtc_vblank_on(&ipu_crtc->base); | ||
91 | } | 58 | } |
92 | 59 | ||
93 | static void ipu_crtc_disable(struct ipu_crtc *ipu_crtc) | 60 | static void ipu_crtc_disable(struct ipu_crtc *ipu_crtc) |
94 | { | 61 | { |
95 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); | 62 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); |
96 | 63 | struct drm_crtc *crtc = &ipu_crtc->base; | |
97 | if (!ipu_crtc->enabled) | ||
98 | return; | ||
99 | 64 | ||
100 | ipu_dc_disable_channel(ipu_crtc->dc); | 65 | ipu_dc_disable_channel(ipu_crtc->dc); |
101 | ipu_di_disable(ipu_crtc->di); | 66 | ipu_di_disable(ipu_crtc->di); |
102 | ipu_dc_disable(ipu); | 67 | ipu_dc_disable(ipu); |
103 | ipu_crtc->enabled = 0; | ||
104 | 68 | ||
105 | drm_crtc_vblank_off(&ipu_crtc->base); | 69 | spin_lock_irq(&crtc->dev->event_lock); |
70 | if (crtc->state->event) { | ||
71 | drm_crtc_send_vblank_event(crtc, crtc->state->event); | ||
72 | crtc->state->event = NULL; | ||
73 | } | ||
74 | spin_unlock_irq(&crtc->dev->event_lock); | ||
106 | } | 75 | } |
107 | 76 | ||
108 | static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) | 77 | static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) |
@@ -123,151 +92,21 @@ static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
123 | } | 92 | } |
124 | } | 93 | } |
125 | 94 | ||
126 | static void ipu_flip_unref_work_func(struct work_struct *__work) | ||
127 | { | ||
128 | struct ipu_flip_work *work = | ||
129 | container_of(__work, struct ipu_flip_work, unref_work); | ||
130 | |||
131 | drm_gem_object_unreference_unlocked(work->bo); | ||
132 | kfree(work); | ||
133 | } | ||
134 | |||
135 | static void ipu_flip_fence_work_func(struct work_struct *__work) | ||
136 | { | ||
137 | struct ipu_flip_work *work = | ||
138 | container_of(__work, struct ipu_flip_work, fence_work); | ||
139 | int i; | ||
140 | |||
141 | /* wait for all fences attached to the FB obj to signal */ | ||
142 | if (work->excl) { | ||
143 | fence_wait(work->excl, false); | ||
144 | fence_put(work->excl); | ||
145 | } | ||
146 | for (i = 0; i < work->shared_count; i++) { | ||
147 | fence_wait(work->shared[i], false); | ||
148 | fence_put(work->shared[i]); | ||
149 | } | ||
150 | |||
151 | work->crtc->flip_state = IPU_FLIP_SUBMITTED; | ||
152 | } | ||
153 | |||
154 | static int ipu_page_flip(struct drm_crtc *crtc, | ||
155 | struct drm_framebuffer *fb, | ||
156 | struct drm_pending_vblank_event *event, | ||
157 | uint32_t page_flip_flags) | ||
158 | { | ||
159 | struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
160 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
161 | struct ipu_flip_work *flip_work; | ||
162 | int ret; | ||
163 | |||
164 | if (ipu_crtc->flip_state != IPU_FLIP_NONE) | ||
165 | return -EBUSY; | ||
166 | |||
167 | ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc); | ||
168 | if (ret) { | ||
169 | dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n"); | ||
170 | list_del(&event->base.link); | ||
171 | |||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | flip_work = kzalloc(sizeof *flip_work, GFP_KERNEL); | ||
176 | if (!flip_work) { | ||
177 | ret = -ENOMEM; | ||
178 | goto put_vblank; | ||
179 | } | ||
180 | INIT_WORK(&flip_work->unref_work, ipu_flip_unref_work_func); | ||
181 | flip_work->page_flip_event = event; | ||
182 | |||
183 | /* get BO backing the old framebuffer and take a reference */ | ||
184 | flip_work->bo = &drm_fb_cma_get_gem_obj(crtc->primary->fb, 0)->base; | ||
185 | drm_gem_object_reference(flip_work->bo); | ||
186 | |||
187 | ipu_crtc->flip_work = flip_work; | ||
188 | /* | ||
189 | * If the object has a DMABUF attached, we need to wait on its fences | ||
190 | * if there are any. | ||
191 | */ | ||
192 | if (cma_obj->base.dma_buf) { | ||
193 | INIT_WORK(&flip_work->fence_work, ipu_flip_fence_work_func); | ||
194 | flip_work->crtc = ipu_crtc; | ||
195 | |||
196 | ret = reservation_object_get_fences_rcu( | ||
197 | cma_obj->base.dma_buf->resv, &flip_work->excl, | ||
198 | &flip_work->shared_count, &flip_work->shared); | ||
199 | |||
200 | if (unlikely(ret)) { | ||
201 | DRM_ERROR("failed to get fences for buffer\n"); | ||
202 | goto free_flip_work; | ||
203 | } | ||
204 | |||
205 | /* No need to queue the worker if the are no fences */ | ||
206 | if (!flip_work->excl && !flip_work->shared_count) { | ||
207 | ipu_crtc->flip_state = IPU_FLIP_SUBMITTED; | ||
208 | } else { | ||
209 | ipu_crtc->flip_state = IPU_FLIP_PENDING; | ||
210 | queue_work(ipu_crtc->flip_queue, | ||
211 | &flip_work->fence_work); | ||
212 | } | ||
213 | } else { | ||
214 | ipu_crtc->flip_state = IPU_FLIP_SUBMITTED; | ||
215 | } | ||
216 | |||
217 | if (crtc->primary->state) | ||
218 | drm_atomic_set_fb_for_plane(crtc->primary->state, fb); | ||
219 | |||
220 | return 0; | ||
221 | |||
222 | free_flip_work: | ||
223 | drm_gem_object_unreference_unlocked(flip_work->bo); | ||
224 | kfree(flip_work); | ||
225 | ipu_crtc->flip_work = NULL; | ||
226 | put_vblank: | ||
227 | imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); | ||
228 | |||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static const struct drm_crtc_funcs ipu_crtc_funcs = { | 95 | static const struct drm_crtc_funcs ipu_crtc_funcs = { |
233 | .set_config = drm_crtc_helper_set_config, | 96 | .set_config = drm_atomic_helper_set_config, |
234 | .destroy = drm_crtc_cleanup, | 97 | .destroy = drm_crtc_cleanup, |
235 | .page_flip = ipu_page_flip, | 98 | .page_flip = drm_atomic_helper_page_flip, |
236 | .reset = drm_atomic_helper_crtc_reset, | 99 | .reset = drm_atomic_helper_crtc_reset, |
237 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | 100 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
238 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | 101 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
239 | }; | 102 | }; |
240 | 103 | ||
241 | static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) | ||
242 | { | ||
243 | unsigned long flags; | ||
244 | struct drm_device *drm = ipu_crtc->base.dev; | ||
245 | struct ipu_flip_work *work = ipu_crtc->flip_work; | ||
246 | |||
247 | spin_lock_irqsave(&drm->event_lock, flags); | ||
248 | if (work->page_flip_event) | ||
249 | drm_crtc_send_vblank_event(&ipu_crtc->base, | ||
250 | work->page_flip_event); | ||
251 | imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); | ||
252 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
253 | } | ||
254 | |||
255 | static irqreturn_t ipu_irq_handler(int irq, void *dev_id) | 104 | static irqreturn_t ipu_irq_handler(int irq, void *dev_id) |
256 | { | 105 | { |
257 | struct ipu_crtc *ipu_crtc = dev_id; | 106 | struct ipu_crtc *ipu_crtc = dev_id; |
258 | 107 | ||
259 | imx_drm_handle_vblank(ipu_crtc->imx_crtc); | 108 | imx_drm_handle_vblank(ipu_crtc->imx_crtc); |
260 | 109 | ||
261 | if (ipu_crtc->flip_state == IPU_FLIP_SUBMITTED) { | ||
262 | struct ipu_plane *plane = ipu_crtc->plane[0]; | ||
263 | |||
264 | ipu_plane_set_base(plane, ipu_crtc->base.primary->fb); | ||
265 | ipu_crtc_handle_pageflip(ipu_crtc); | ||
266 | queue_work(ipu_crtc->flip_queue, | ||
267 | &ipu_crtc->flip_work->unref_work); | ||
268 | ipu_crtc->flip_state = IPU_FLIP_NONE; | ||
269 | } | ||
270 | |||
271 | return IRQ_HANDLED; | 110 | return IRQ_HANDLED; |
272 | } | 111 | } |
273 | 112 | ||
@@ -310,9 +149,26 @@ static void ipu_crtc_commit(struct drm_crtc *crtc) | |||
310 | static int ipu_crtc_atomic_check(struct drm_crtc *crtc, | 149 | static int ipu_crtc_atomic_check(struct drm_crtc *crtc, |
311 | struct drm_crtc_state *state) | 150 | struct drm_crtc_state *state) |
312 | { | 151 | { |
152 | u32 primary_plane_mask = 1 << drm_plane_index(crtc->primary); | ||
153 | |||
154 | if (state->active && (primary_plane_mask & state->plane_mask) == 0) | ||
155 | return -EINVAL; | ||
156 | |||
313 | return 0; | 157 | return 0; |
314 | } | 158 | } |
315 | 159 | ||
160 | static void ipu_crtc_atomic_begin(struct drm_crtc *crtc, | ||
161 | struct drm_crtc_state *old_crtc_state) | ||
162 | { | ||
163 | spin_lock_irq(&crtc->dev->event_lock); | ||
164 | if (crtc->state->event) { | ||
165 | WARN_ON(drm_crtc_vblank_get(crtc)); | ||
166 | drm_crtc_arm_vblank_event(crtc, crtc->state->event); | ||
167 | crtc->state->event = NULL; | ||
168 | } | ||
169 | spin_unlock_irq(&crtc->dev->event_lock); | ||
170 | } | ||
171 | |||
316 | static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) | 172 | static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) |
317 | { | 173 | { |
318 | struct drm_device *dev = crtc->dev; | 174 | struct drm_device *dev = crtc->dev; |
@@ -371,25 +227,17 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
371 | static const struct drm_crtc_helper_funcs ipu_helper_funcs = { | 227 | static const struct drm_crtc_helper_funcs ipu_helper_funcs = { |
372 | .dpms = ipu_crtc_dpms, | 228 | .dpms = ipu_crtc_dpms, |
373 | .mode_fixup = ipu_crtc_mode_fixup, | 229 | .mode_fixup = ipu_crtc_mode_fixup, |
374 | .mode_set = drm_helper_crtc_mode_set, | ||
375 | .mode_set_nofb = ipu_crtc_mode_set_nofb, | 230 | .mode_set_nofb = ipu_crtc_mode_set_nofb, |
376 | .prepare = ipu_crtc_prepare, | 231 | .prepare = ipu_crtc_prepare, |
377 | .commit = ipu_crtc_commit, | 232 | .commit = ipu_crtc_commit, |
378 | .atomic_check = ipu_crtc_atomic_check, | 233 | .atomic_check = ipu_crtc_atomic_check, |
234 | .atomic_begin = ipu_crtc_atomic_begin, | ||
379 | }; | 235 | }; |
380 | 236 | ||
381 | static int ipu_enable_vblank(struct drm_crtc *crtc) | 237 | static int ipu_enable_vblank(struct drm_crtc *crtc) |
382 | { | 238 | { |
383 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | 239 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); |
384 | 240 | ||
385 | /* | ||
386 | * ->commit is done after ->mode_set in drm_crtc_helper_set_mode(), | ||
387 | * so waiting for vblank in drm_plane_helper_commit() will timeout. | ||
388 | * Check the state here to avoid the waiting. | ||
389 | */ | ||
390 | if (!ipu_crtc->enabled) | ||
391 | return -EINVAL; | ||
392 | |||
393 | enable_irq(ipu_crtc->irq); | 241 | enable_irq(ipu_crtc->irq); |
394 | 242 | ||
395 | return 0; | 243 | return 0; |
@@ -508,8 +356,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, | |||
508 | /* Only enable IRQ when we actually need it to trigger work. */ | 356 | /* Only enable IRQ when we actually need it to trigger work. */ |
509 | disable_irq(ipu_crtc->irq); | 357 | disable_irq(ipu_crtc->irq); |
510 | 358 | ||
511 | ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip"); | ||
512 | |||
513 | return 0; | 359 | return 0; |
514 | 360 | ||
515 | err_put_plane1_res: | 361 | err_put_plane1_res: |
@@ -554,7 +400,6 @@ static void ipu_drm_unbind(struct device *dev, struct device *master, | |||
554 | 400 | ||
555 | imx_drm_remove_crtc(ipu_crtc->imx_crtc); | 401 | imx_drm_remove_crtc(ipu_crtc->imx_crtc); |
556 | 402 | ||
557 | destroy_workqueue(ipu_crtc->flip_queue); | ||
558 | ipu_put_resources(ipu_crtc); | 403 | ipu_put_resources(ipu_crtc); |
559 | if (ipu_crtc->plane[1]) | 404 | if (ipu_crtc->plane[1]) |
560 | ipu_plane_put_resources(ipu_crtc->plane[1]); | 405 | ipu_plane_put_resources(ipu_crtc->plane[1]); |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index afbc7402bff1..3f5f9566b152 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <drm/drm_atomic.h> | ||
17 | #include <drm/drm_atomic_helper.h> | 18 | #include <drm/drm_atomic_helper.h> |
18 | #include <drm/drm_fb_cma_helper.h> | 19 | #include <drm/drm_fb_cma_helper.h> |
19 | #include <drm/drm_gem_cma_helper.h> | 20 | #include <drm/drm_gem_cma_helper.h> |
@@ -55,122 +56,6 @@ int ipu_plane_irq(struct ipu_plane *ipu_plane) | |||
55 | IPU_IRQ_EOF); | 56 | IPU_IRQ_EOF); |
56 | } | 57 | } |
57 | 58 | ||
58 | int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb) | ||
59 | { | ||
60 | struct drm_gem_cma_object *cma_obj[3], *old_cma_obj[3]; | ||
61 | struct drm_plane_state *state = ipu_plane->base.state; | ||
62 | struct drm_framebuffer *old_fb = state->fb; | ||
63 | unsigned long eba, ubo, vbo, old_eba, old_ubo, old_vbo; | ||
64 | int active, i; | ||
65 | int x = state->src_x >> 16; | ||
66 | int y = state->src_y >> 16; | ||
67 | |||
68 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { | ||
69 | cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i); | ||
70 | if (!cma_obj[i]) { | ||
71 | DRM_DEBUG_KMS("plane %d entry is null.\n", i); | ||
72 | return -EFAULT; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | for (i = 0; i < drm_format_num_planes(old_fb->pixel_format); i++) { | ||
77 | old_cma_obj[i] = drm_fb_cma_get_gem_obj(old_fb, i); | ||
78 | if (!old_cma_obj[i]) { | ||
79 | DRM_DEBUG_KMS("plane %d entry is null.\n", i); | ||
80 | return -EFAULT; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | eba = cma_obj[0]->paddr + fb->offsets[0] + | ||
85 | fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; | ||
86 | |||
87 | if (eba & 0x7) { | ||
88 | DRM_DEBUG_KMS("base address must be a multiple of 8.\n"); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) { | ||
93 | DRM_DEBUG_KMS("pitches out of range.\n"); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | if (fb->pitches[0] != old_fb->pitches[0]) { | ||
98 | DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n"); | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | |||
102 | switch (fb->pixel_format) { | ||
103 | case DRM_FORMAT_YUV420: | ||
104 | case DRM_FORMAT_YVU420: | ||
105 | /* | ||
106 | * Multiplanar formats have to meet the following restrictions: | ||
107 | * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO | ||
108 | * - EBA, UBO and VBO are a multiple of 8 | ||
109 | * - UBO and VBO are unsigned and not larger than 0xfffff8 | ||
110 | * - Only EBA may be changed while scanout is active | ||
111 | * - The strides of U and V planes must be identical. | ||
112 | */ | ||
113 | ubo = cma_obj[1]->paddr + fb->offsets[1] + | ||
114 | fb->pitches[1] * y / 2 + x / 2 - eba; | ||
115 | vbo = cma_obj[2]->paddr + fb->offsets[2] + | ||
116 | fb->pitches[2] * y / 2 + x / 2 - eba; | ||
117 | |||
118 | old_eba = old_cma_obj[0]->paddr + old_fb->offsets[0] + | ||
119 | old_fb->pitches[0] * y + | ||
120 | (old_fb->bits_per_pixel >> 3) * x; | ||
121 | old_ubo = old_cma_obj[1]->paddr + old_fb->offsets[1] + | ||
122 | old_fb->pitches[1] * y / 2 + x / 2 - old_eba; | ||
123 | old_vbo = old_cma_obj[2]->paddr + old_fb->offsets[2] + | ||
124 | old_fb->pitches[2] * y / 2 + x / 2 - old_eba; | ||
125 | |||
126 | if ((ubo & 0x7) || (vbo & 0x7)) { | ||
127 | DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n"); | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | |||
131 | if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) { | ||
132 | DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n"); | ||
133 | return -EINVAL; | ||
134 | } | ||
135 | |||
136 | if (old_ubo != ubo || old_vbo != vbo) { | ||
137 | DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n"); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | if (fb->pitches[1] != fb->pitches[2]) { | ||
142 | DRM_DEBUG_KMS("U/V pitches must be identical.\n"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) { | ||
147 | DRM_DEBUG_KMS("U/V pitches out of range.\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | if (old_fb->pitches[1] != fb->pitches[1]) { | ||
152 | DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n"); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | dev_dbg(ipu_plane->base.dev->dev, | ||
157 | "phys = %pad %pad %pad, x = %d, y = %d", | ||
158 | &cma_obj[0]->paddr, &cma_obj[1]->paddr, | ||
159 | &cma_obj[2]->paddr, x, y); | ||
160 | break; | ||
161 | default: | ||
162 | dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", | ||
163 | &cma_obj[0]->paddr, x, y); | ||
164 | break; | ||
165 | } | ||
166 | |||
167 | active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); | ||
168 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); | ||
169 | ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static inline unsigned long | 59 | static inline unsigned long |
175 | drm_plane_state_to_eba(struct drm_plane_state *state) | 60 | drm_plane_state_to_eba(struct drm_plane_state *state) |
176 | { | 61 | { |
@@ -360,8 +245,8 @@ static void ipu_plane_destroy(struct drm_plane *plane) | |||
360 | } | 245 | } |
361 | 246 | ||
362 | static const struct drm_plane_funcs ipu_plane_funcs = { | 247 | static const struct drm_plane_funcs ipu_plane_funcs = { |
363 | .update_plane = drm_plane_helper_update, | 248 | .update_plane = drm_atomic_helper_update_plane, |
364 | .disable_plane = drm_plane_helper_disable, | 249 | .disable_plane = drm_atomic_helper_disable_plane, |
365 | .destroy = ipu_plane_destroy, | 250 | .destroy = ipu_plane_destroy, |
366 | .reset = drm_atomic_helper_plane_reset, | 251 | .reset = drm_atomic_helper_plane_reset, |
367 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | 252 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
@@ -380,10 +265,18 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, | |||
380 | 265 | ||
381 | /* Ok to disable */ | 266 | /* Ok to disable */ |
382 | if (!fb) | 267 | if (!fb) |
383 | return old_fb ? 0 : -EINVAL; | 268 | return 0; |
269 | |||
270 | if (!state->crtc) | ||
271 | return -EINVAL; | ||
272 | |||
273 | crtc_state = | ||
274 | drm_atomic_get_existing_crtc_state(state->state, state->crtc); | ||
275 | if (WARN_ON(!crtc_state)) | ||
276 | return -EINVAL; | ||
384 | 277 | ||
385 | /* CRTC should be enabled */ | 278 | /* CRTC should be enabled */ |
386 | if (!state->crtc->enabled) | 279 | if (!crtc_state->enable) |
387 | return -EINVAL; | 280 | return -EINVAL; |
388 | 281 | ||
389 | /* no scaling */ | 282 | /* no scaling */ |
@@ -391,8 +284,6 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, | |||
391 | state->src_h >> 16 != state->crtc_h) | 284 | state->src_h >> 16 != state->crtc_h) |
392 | return -EINVAL; | 285 | return -EINVAL; |
393 | 286 | ||
394 | crtc_state = state->crtc->state; | ||
395 | |||
396 | switch (plane->type) { | 287 | switch (plane->type) { |
397 | case DRM_PLANE_TYPE_PRIMARY: | 288 | case DRM_PLANE_TYPE_PRIMARY: |
398 | /* full plane doesn't support partial off screen */ | 289 | /* full plane doesn't support partial off screen */ |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index c51a44ba3ddd..338b88a74eb6 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h | |||
@@ -37,8 +37,6 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, | |||
37 | uint32_t src_x, uint32_t src_y, uint32_t src_w, | 37 | uint32_t src_x, uint32_t src_y, uint32_t src_w, |
38 | uint32_t src_h, bool interlaced); | 38 | uint32_t src_h, bool interlaced); |
39 | 39 | ||
40 | int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb); | ||
41 | |||
42 | int ipu_plane_get_resources(struct ipu_plane *plane); | 40 | int ipu_plane_get_resources(struct ipu_plane *plane); |
43 | void ipu_plane_put_resources(struct ipu_plane *plane); | 41 | void ipu_plane_put_resources(struct ipu_plane *plane); |
44 | 42 | ||