aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2017-01-19 22:51:41 -0500
committerInki Dae <inki.dae@samsung.com>2017-01-30 18:49:47 -0500
commit41cbf0fdaa2886241f92f014ae1fd12bd5689af4 (patch)
treec93fdeb656dc8cdb6c86c204448594ed18d5cb12
parent9db41d43236411d38778eda2b5987f9b65498c48 (diff)
drm/exynos: use atomic helper commit
This patch replaces specific atomic commit function with atomic helper commit one. For this, it removes existing atomic commit function and relevant code specific to Exynos DRM and makes atomic helper commit to be used instead. Below are changes for the use of atomic helper commit: - add atomic_commit_tail callback specific to Exynos DRM . default implemention of atomic helper doesn't mesh well with runtime PM so the device driver which supports runtime PM should call drm_atomic_helper_commit_modeset_enables function prior to drm_atomic_helper_commit_planes function call. atomic_commit_tail callback implements this call ordering. - allow plane commit only in case that CRTC device is enabled. . for this, it calls atomic_helper_commit_planes function with DRM_PLANE_COMMIT_ACTIVE_ONLY flag in atomic_commit_tail callback. Signed-off-by: Inki Dae <inki.dae@samsung.com> Reviewed-by: Gustavo Padovan <gustavo.padovan@collabora.com>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c109
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c32
3 files changed, 39 insertions, 110 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 8dd59b9e5694..5367b6664fe3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -39,6 +39,14 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
39 39
40 if (exynos_crtc->ops->disable) 40 if (exynos_crtc->ops->disable)
41 exynos_crtc->ops->disable(exynos_crtc); 41 exynos_crtc->ops->disable(exynos_crtc);
42
43 if (crtc->state->event && !crtc->state->active) {
44 spin_lock_irq(&crtc->dev->event_lock);
45 drm_crtc_send_vblank_event(crtc, crtc->state->event);
46 spin_unlock_irq(&crtc->dev->event_lock);
47
48 crtc->state->event = NULL;
49 }
42} 50}
43 51
44static void 52static void
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 34e13422852e..035d02ecffcd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -38,56 +38,6 @@
38#define DRIVER_MAJOR 1 38#define DRIVER_MAJOR 1
39#define DRIVER_MINOR 0 39#define DRIVER_MINOR 0
40 40
41struct exynos_atomic_commit {
42 struct work_struct work;
43 struct drm_device *dev;
44 struct drm_atomic_state *state;
45 u32 crtcs;
46};
47
48static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
49{
50 struct drm_device *dev = commit->dev;
51 struct exynos_drm_private *priv = dev->dev_private;
52 struct drm_atomic_state *state = commit->state;
53
54 drm_atomic_helper_commit_modeset_disables(dev, state);
55
56 drm_atomic_helper_commit_modeset_enables(dev, state);
57
58 /*
59 * Exynos can't update planes with CRTCs and encoders disabled,
60 * its updates routines, specially for FIMD, requires the clocks
61 * to be enabled. So it is necessary to handle the modeset operations
62 * *before* the commit_planes() step, this way it will always
63 * have the relevant clocks enabled to perform the update.
64 */
65
66 drm_atomic_helper_commit_planes(dev, state, 0);
67
68 drm_atomic_helper_wait_for_vblanks(dev, state);
69
70 drm_atomic_helper_cleanup_planes(dev, state);
71
72 drm_atomic_state_put(state);
73
74 spin_lock(&priv->lock);
75 priv->pending &= ~commit->crtcs;
76 spin_unlock(&priv->lock);
77
78 wake_up_all(&priv->wait);
79
80 kfree(commit);
81}
82
83static void exynos_drm_atomic_work(struct work_struct *work)
84{
85 struct exynos_atomic_commit *commit = container_of(work,
86 struct exynos_atomic_commit, work);
87
88 exynos_atomic_commit_complete(commit);
89}
90
91static struct device *exynos_drm_get_dma_device(void); 41static struct device *exynos_drm_get_dma_device(void);
92 42
93static int exynos_drm_load(struct drm_device *dev, unsigned long flags) 43static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
@@ -202,65 +152,6 @@ static void exynos_drm_unload(struct drm_device *dev)
202 dev->dev_private = NULL; 152 dev->dev_private = NULL;
203} 153}
204 154
205static int commit_is_pending(struct exynos_drm_private *priv, u32 crtcs)
206{
207 bool pending;
208
209 spin_lock(&priv->lock);
210 pending = priv->pending & crtcs;
211 spin_unlock(&priv->lock);
212
213 return pending;
214}
215
216int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
217 bool nonblock)
218{
219 struct exynos_drm_private *priv = dev->dev_private;
220 struct exynos_atomic_commit *commit;
221 struct drm_crtc *crtc;
222 struct drm_crtc_state *crtc_state;
223 int i, ret;
224
225 commit = kzalloc(sizeof(*commit), GFP_KERNEL);
226 if (!commit)
227 return -ENOMEM;
228
229 ret = drm_atomic_helper_prepare_planes(dev, state);
230 if (ret) {
231 kfree(commit);
232 return ret;
233 }
234
235 /* This is the point of no return */
236
237 INIT_WORK(&commit->work, exynos_drm_atomic_work);
238 commit->dev = dev;
239 commit->state = state;
240
241 /* Wait until all affected CRTCs have completed previous commits and
242 * mark them as pending.
243 */
244 for_each_crtc_in_state(state, crtc, crtc_state, i)
245 commit->crtcs |= drm_crtc_mask(crtc);
246
247 wait_event(priv->wait, !commit_is_pending(priv, commit->crtcs));
248
249 spin_lock(&priv->lock);
250 priv->pending |= commit->crtcs;
251 spin_unlock(&priv->lock);
252
253 drm_atomic_helper_swap_state(state, true);
254
255 drm_atomic_state_get(state);
256 if (nonblock)
257 schedule_work(&commit->work);
258 else
259 exynos_atomic_commit_complete(commit);
260
261 return 0;
262}
263
264int exynos_atomic_check(struct drm_device *dev, 155int exynos_atomic_check(struct drm_device *dev,
265 struct drm_atomic_state *state) 156 struct drm_atomic_state *state)
266{ 157{
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 68d414227533..c77a5aced81a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -187,11 +187,40 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
187 return exynos_fb->dma_addr[index]; 187 return exynos_fb->dma_addr[index];
188} 188}
189 189
190static void exynos_drm_atomic_commit_tail(struct drm_atomic_state *state)
191{
192 struct drm_device *dev = state->dev;
193
194 drm_atomic_helper_commit_modeset_disables(dev, state);
195
196 drm_atomic_helper_commit_modeset_enables(dev, state);
197
198 /*
199 * Exynos can't update planes with CRTCs and encoders disabled,
200 * its updates routines, specially for FIMD, requires the clocks
201 * to be enabled. So it is necessary to handle the modeset operations
202 * *before* the commit_planes() step, this way it will always
203 * have the relevant clocks enabled to perform the update.
204 */
205 drm_atomic_helper_commit_planes(dev, state,
206 DRM_PLANE_COMMIT_ACTIVE_ONLY);
207
208 drm_atomic_helper_commit_hw_done(state);
209
210 drm_atomic_helper_wait_for_vblanks(dev, state);
211
212 drm_atomic_helper_cleanup_planes(dev, state);
213}
214
215static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
216 .atomic_commit_tail = exynos_drm_atomic_commit_tail,
217};
218
190static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { 219static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
191 .fb_create = exynos_user_fb_create, 220 .fb_create = exynos_user_fb_create,
192 .output_poll_changed = exynos_drm_output_poll_changed, 221 .output_poll_changed = exynos_drm_output_poll_changed,
193 .atomic_check = exynos_atomic_check, 222 .atomic_check = exynos_atomic_check,
194 .atomic_commit = exynos_atomic_commit, 223 .atomic_commit = drm_atomic_helper_commit,
195}; 224};
196 225
197void exynos_drm_mode_config_init(struct drm_device *dev) 226void exynos_drm_mode_config_init(struct drm_device *dev)
@@ -208,4 +237,5 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
208 dev->mode_config.max_height = 4096; 237 dev->mode_config.max_height = 4096;
209 238
210 dev->mode_config.funcs = &exynos_drm_mode_config_funcs; 239 dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
240 dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
211} 241}