aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/msm_atomic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/msm_atomic.c')
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c69
1 files changed, 68 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index f0de412e13dc..191968256c58 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -23,10 +23,41 @@ struct msm_commit {
23 struct drm_atomic_state *state; 23 struct drm_atomic_state *state;
24 uint32_t fence; 24 uint32_t fence;
25 struct msm_fence_cb fence_cb; 25 struct msm_fence_cb fence_cb;
26 uint32_t crtc_mask;
26}; 27};
27 28
28static void fence_cb(struct msm_fence_cb *cb); 29static void fence_cb(struct msm_fence_cb *cb);
29 30
31/* block until specified crtcs are no longer pending update, and
32 * atomically mark them as pending update
33 */
34static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
35{
36 int ret;
37
38 spin_lock(&priv->pending_crtcs_event.lock);
39 ret = wait_event_interruptible_locked(priv->pending_crtcs_event,
40 !(priv->pending_crtcs & crtc_mask));
41 if (ret == 0) {
42 DBG("start: %08x", crtc_mask);
43 priv->pending_crtcs |= crtc_mask;
44 }
45 spin_unlock(&priv->pending_crtcs_event.lock);
46
47 return ret;
48}
49
50/* clear specified crtcs (no longer pending update)
51 */
52static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
53{
54 spin_lock(&priv->pending_crtcs_event.lock);
55 DBG("end: %08x", crtc_mask);
56 priv->pending_crtcs &= ~crtc_mask;
57 wake_up_all_locked(&priv->pending_crtcs_event);
58 spin_unlock(&priv->pending_crtcs_event.lock);
59}
60
30static struct msm_commit *new_commit(struct drm_atomic_state *state) 61static struct msm_commit *new_commit(struct drm_atomic_state *state)
31{ 62{
32 struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); 63 struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
@@ -58,12 +89,27 @@ static void complete_commit(struct msm_commit *c)
58 89
59 drm_atomic_helper_commit_post_planes(dev, state); 90 drm_atomic_helper_commit_post_planes(dev, state);
60 91
92 /* NOTE: _wait_for_vblanks() only waits for vblank on
93 * enabled CRTCs. So we end up faulting when disabling
94 * due to (potentially) unref'ing the outgoing fb's
95 * before the vblank when the disable has latched.
96 *
97 * But if it did wait on disabled (or newly disabled)
98 * CRTCs, that would be racy (ie. we could have missed
99 * the irq. We need some way to poll for pipe shut
100 * down. Or just live with occasionally hitting the
101 * timeout in the CRTC disable path (which really should
102 * not be critical path)
103 */
104
61 drm_atomic_helper_wait_for_vblanks(dev, state); 105 drm_atomic_helper_wait_for_vblanks(dev, state);
62 106
63 drm_atomic_helper_cleanup_planes(dev, state); 107 drm_atomic_helper_cleanup_planes(dev, state);
64 108
65 drm_atomic_state_free(state); 109 drm_atomic_state_free(state);
66 110
111 end_atomic(dev->dev_private, c->crtc_mask);
112
67 kfree(c); 113 kfree(c);
68} 114}
69 115
@@ -97,8 +143,9 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb)
97int msm_atomic_commit(struct drm_device *dev, 143int msm_atomic_commit(struct drm_device *dev,
98 struct drm_atomic_state *state, bool async) 144 struct drm_atomic_state *state, bool async)
99{ 145{
100 struct msm_commit *c;
101 int nplanes = dev->mode_config.num_total_plane; 146 int nplanes = dev->mode_config.num_total_plane;
147 int ncrtcs = dev->mode_config.num_crtc;
148 struct msm_commit *c;
102 int i, ret; 149 int i, ret;
103 150
104 ret = drm_atomic_helper_prepare_planes(dev, state); 151 ret = drm_atomic_helper_prepare_planes(dev, state);
@@ -106,6 +153,18 @@ int msm_atomic_commit(struct drm_device *dev,
106 return ret; 153 return ret;
107 154
108 c = new_commit(state); 155 c = new_commit(state);
156 if (!c)
157 return -ENOMEM;
158
159 /*
160 * Figure out what crtcs we have:
161 */
162 for (i = 0; i < ncrtcs; i++) {
163 struct drm_crtc *crtc = state->crtcs[i];
164 if (!crtc)
165 continue;
166 c->crtc_mask |= (1 << drm_crtc_index(crtc));
167 }
109 168
110 /* 169 /*
111 * Figure out what fence to wait for: 170 * Figure out what fence to wait for:
@@ -122,6 +181,14 @@ int msm_atomic_commit(struct drm_device *dev,
122 } 181 }
123 182
124 /* 183 /*
184 * Wait for pending updates on any of the same crtc's and then
185 * mark our set of crtc's as busy:
186 */
187 ret = start_atomic(dev->dev_private, c->crtc_mask);
188 if (ret)
189 return ret;
190
191 /*
125 * This is the point of no return - everything below never fails except 192 * This is the point of no return - everything below never fails except
126 * when the hw goes bonghits. Which means we can commit the new state on 193 * when the hw goes bonghits. Which means we can commit the new state on
127 * the software side now. 194 * the software side now.