diff options
author | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2015-08-15 12:26:18 -0400 |
---|---|---|
committer | Inki Dae <daeinki@gmail.com> | 2015-08-30 11:27:38 -0400 |
commit | c4533665d819271dad890440b887776ac3d5f265 (patch) | |
tree | a4c545175fba766dfdbabf21487f6347d869db54 | |
parent | a379df19356de97afdca37c4e8f5e8729215d6ea (diff) |
drm/exynos: wait all planes updates to finish
Add infrastructure to wait for all planes updates to finish by using
an atomic_t variable to track how many pending updates we are waiting
plus a wait_queue for the wait part.
It also changes vblank behaviour and keeps it enabled for all types
of updates
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 4 |
4 files changed, 61 insertions, 6 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 582e041a9356..d6c2c3f8bc6e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c | |||
@@ -75,10 +75,7 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, | |||
75 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 75 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); |
76 | struct drm_plane *plane; | 76 | struct drm_plane *plane; |
77 | 77 | ||
78 | if (crtc->state->event) { | 78 | exynos_crtc->event = crtc->state->event; |
79 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); | ||
80 | exynos_crtc->event = crtc->state->event; | ||
81 | } | ||
82 | 79 | ||
83 | drm_atomic_crtc_for_each_plane(plane, crtc) { | 80 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
84 | struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); | 81 | struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); |
@@ -156,6 +153,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, | |||
156 | exynos_crtc->ops = ops; | 153 | exynos_crtc->ops = ops; |
157 | exynos_crtc->ctx = ctx; | 154 | exynos_crtc->ctx = ctx; |
158 | 155 | ||
156 | init_waitqueue_head(&exynos_crtc->wait_update); | ||
157 | |||
159 | crtc = &exynos_crtc->base; | 158 | crtc = &exynos_crtc->base; |
160 | 159 | ||
161 | private->crtc[pipe] = crtc; | 160 | private->crtc[pipe] = crtc; |
@@ -197,6 +196,13 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) | |||
197 | exynos_crtc->ops->disable_vblank(exynos_crtc); | 196 | exynos_crtc->ops->disable_vblank(exynos_crtc); |
198 | } | 197 | } |
199 | 198 | ||
199 | void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc) | ||
200 | { | ||
201 | wait_event_timeout(exynos_crtc->wait_update, | ||
202 | (atomic_read(&exynos_crtc->pending_update) == 0), | ||
203 | msecs_to_jiffies(50)); | ||
204 | } | ||
205 | |||
200 | void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, | 206 | void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, |
201 | struct exynos_drm_plane *exynos_plane) | 207 | struct exynos_drm_plane *exynos_plane) |
202 | { | 208 | { |
@@ -205,10 +211,12 @@ void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, | |||
205 | 211 | ||
206 | exynos_plane->pending_fb = NULL; | 212 | exynos_plane->pending_fb = NULL; |
207 | 213 | ||
214 | if (atomic_dec_and_test(&exynos_crtc->pending_update)) | ||
215 | wake_up(&exynos_crtc->wait_update); | ||
216 | |||
208 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | 217 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
209 | if (exynos_crtc->event) { | 218 | if (exynos_crtc->event) { |
210 | drm_crtc_send_vblank_event(crtc, exynos_crtc->event); | 219 | drm_crtc_send_vblank_event(crtc, exynos_crtc->event); |
211 | drm_crtc_vblank_put(crtc); | ||
212 | wake_up(&exynos_crtc->pending_flip_queue); | 220 | wake_up(&exynos_crtc->pending_flip_queue); |
213 | } | 221 | } |
214 | 222 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 8bedfde2084a..f87d4abda6f7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h | |||
@@ -25,6 +25,7 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, | |||
25 | void *context); | 25 | void *context); |
26 | int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); | 26 | int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); |
27 | void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); | 27 | void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); |
28 | void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); | ||
28 | void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, | 29 | void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, |
29 | struct exynos_drm_plane *exynos_plane); | 30 | struct exynos_drm_plane *exynos_plane); |
30 | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); | 31 | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 898591792b12..1350c8e2d587 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -45,11 +45,37 @@ struct exynos_atomic_commit { | |||
45 | u32 crtcs; | 45 | u32 crtcs; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static void exynos_atomic_wait_for_commit(struct drm_atomic_state *state) | ||
49 | { | ||
50 | struct drm_crtc_state *crtc_state; | ||
51 | struct drm_crtc *crtc; | ||
52 | int i, ret; | ||
53 | |||
54 | for_each_crtc_in_state(state, crtc, crtc_state, i) { | ||
55 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | ||
56 | |||
57 | if (!crtc->state->enable) | ||
58 | continue; | ||
59 | |||
60 | ret = drm_crtc_vblank_get(crtc); | ||
61 | if (ret) | ||
62 | continue; | ||
63 | |||
64 | exynos_drm_crtc_wait_pending_update(exynos_crtc); | ||
65 | drm_crtc_vblank_put(crtc); | ||
66 | } | ||
67 | } | ||
68 | |||
48 | static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) | 69 | static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) |
49 | { | 70 | { |
50 | struct drm_device *dev = commit->dev; | 71 | struct drm_device *dev = commit->dev; |
51 | struct exynos_drm_private *priv = dev->dev_private; | 72 | struct exynos_drm_private *priv = dev->dev_private; |
52 | struct drm_atomic_state *state = commit->state; | 73 | struct drm_atomic_state *state = commit->state; |
74 | struct drm_plane *plane; | ||
75 | struct drm_crtc *crtc; | ||
76 | struct drm_plane_state *plane_state; | ||
77 | struct drm_crtc_state *crtc_state; | ||
78 | int i; | ||
53 | 79 | ||
54 | drm_atomic_helper_commit_modeset_disables(dev, state); | 80 | drm_atomic_helper_commit_modeset_disables(dev, state); |
55 | 81 | ||
@@ -63,9 +89,25 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) | |||
63 | * have the relevant clocks enabled to perform the update. | 89 | * have the relevant clocks enabled to perform the update. |
64 | */ | 90 | */ |
65 | 91 | ||
92 | for_each_crtc_in_state(state, crtc, crtc_state, i) { | ||
93 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | ||
94 | |||
95 | atomic_set(&exynos_crtc->pending_update, 0); | ||
96 | } | ||
97 | |||
98 | for_each_plane_in_state(state, plane, plane_state, i) { | ||
99 | struct exynos_drm_crtc *exynos_crtc = | ||
100 | to_exynos_crtc(plane->crtc); | ||
101 | |||
102 | if (!plane->crtc) | ||
103 | continue; | ||
104 | |||
105 | atomic_inc(&exynos_crtc->pending_update); | ||
106 | } | ||
107 | |||
66 | drm_atomic_helper_commit_planes(dev, state); | 108 | drm_atomic_helper_commit_planes(dev, state); |
67 | 109 | ||
68 | drm_atomic_helper_wait_for_vblanks(dev, state); | 110 | exynos_atomic_wait_for_commit(state); |
69 | 111 | ||
70 | drm_atomic_helper_cleanup_planes(dev, state); | 112 | drm_atomic_helper_cleanup_planes(dev, state); |
71 | 113 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b06fbd43b475..7193d94fde3b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -136,6 +136,8 @@ struct exynos_drm_crtc_ops { | |||
136 | * this pipe value. | 136 | * this pipe value. |
137 | * @enabled: if the crtc is enabled or not | 137 | * @enabled: if the crtc is enabled or not |
138 | * @event: vblank event that is currently queued for flip | 138 | * @event: vblank event that is currently queued for flip |
139 | * @wait_update: wait all pending planes updates to finish | ||
140 | * @pending_update: number of pending plane updates in this crtc | ||
139 | * @ops: pointer to callbacks for exynos drm specific functionality | 141 | * @ops: pointer to callbacks for exynos drm specific functionality |
140 | * @ctx: A pointer to the crtc's implementation specific context | 142 | * @ctx: A pointer to the crtc's implementation specific context |
141 | */ | 143 | */ |
@@ -145,6 +147,8 @@ struct exynos_drm_crtc { | |||
145 | unsigned int pipe; | 147 | unsigned int pipe; |
146 | wait_queue_head_t pending_flip_queue; | 148 | wait_queue_head_t pending_flip_queue; |
147 | struct drm_pending_vblank_event *event; | 149 | struct drm_pending_vblank_event *event; |
150 | wait_queue_head_t wait_update; | ||
151 | atomic_t pending_update; | ||
148 | const struct exynos_drm_crtc_ops *ops; | 152 | const struct exynos_drm_crtc_ops *ops; |
149 | void *ctx; | 153 | void *ctx; |
150 | }; | 154 | }; |