1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2014 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
7 #include <drm/drm_atomic_uapi.h>
8 #include <drm/drm_gem_framebuffer_helper.h>
9 #include <drm/drm_vblank.h>
11 #include "msm_atomic_trace.h"
16 int msm_atomic_prepare_fb(struct drm_plane
*plane
,
17 struct drm_plane_state
*new_state
)
19 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
20 struct msm_kms
*kms
= priv
->kms
;
25 drm_gem_fb_prepare_fb(plane
, new_state
);
27 return msm_framebuffer_prepare(new_state
->fb
, kms
->aspace
);
30 static void msm_atomic_async_commit(struct msm_kms
*kms
, int crtc_idx
)
32 unsigned crtc_mask
= BIT(crtc_idx
);
34 trace_msm_atomic_async_commit_start(crtc_mask
);
36 mutex_lock(&kms
->commit_lock
);
38 if (!(kms
->pending_crtc_mask
& crtc_mask
)) {
39 mutex_unlock(&kms
->commit_lock
);
43 kms
->pending_crtc_mask
&= ~crtc_mask
;
45 kms
->funcs
->enable_commit(kms
);
48 * Flush hardware updates:
50 trace_msm_atomic_flush_commit(crtc_mask
);
51 kms
->funcs
->flush_commit(kms
, crtc_mask
);
52 mutex_unlock(&kms
->commit_lock
);
55 * Wait for flush to complete:
57 trace_msm_atomic_wait_flush_start(crtc_mask
);
58 kms
->funcs
->wait_flush(kms
, crtc_mask
);
59 trace_msm_atomic_wait_flush_finish(crtc_mask
);
61 mutex_lock(&kms
->commit_lock
);
62 kms
->funcs
->complete_commit(kms
, crtc_mask
);
63 mutex_unlock(&kms
->commit_lock
);
64 kms
->funcs
->disable_commit(kms
);
67 trace_msm_atomic_async_commit_finish(crtc_mask
);
70 static enum hrtimer_restart
msm_atomic_pending_timer(struct hrtimer
*t
)
72 struct msm_pending_timer
*timer
= container_of(t
,
73 struct msm_pending_timer
, timer
);
74 struct msm_drm_private
*priv
= timer
->kms
->dev
->dev_private
;
76 queue_work(priv
->wq
, &timer
->work
);
78 return HRTIMER_NORESTART
;
81 static void msm_atomic_pending_work(struct work_struct
*work
)
83 struct msm_pending_timer
*timer
= container_of(work
,
84 struct msm_pending_timer
, work
);
86 msm_atomic_async_commit(timer
->kms
, timer
->crtc_idx
);
89 void msm_atomic_init_pending_timer(struct msm_pending_timer
*timer
,
90 struct msm_kms
*kms
, int crtc_idx
)
93 timer
->crtc_idx
= crtc_idx
;
94 hrtimer_init(&timer
->timer
, CLOCK_MONOTONIC
, HRTIMER_MODE_ABS
);
95 timer
->timer
.function
= msm_atomic_pending_timer
;
96 INIT_WORK(&timer
->work
, msm_atomic_pending_work
);
99 static bool can_do_async(struct drm_atomic_state
*state
,
100 struct drm_crtc
**async_crtc
)
102 struct drm_connector_state
*connector_state
;
103 struct drm_connector
*connector
;
104 struct drm_crtc_state
*crtc_state
;
105 struct drm_crtc
*crtc
;
106 int i
, num_crtcs
= 0;
108 if (!(state
->legacy_cursor_update
|| state
->async_update
))
111 /* any connector change, means slow path: */
112 for_each_new_connector_in_state(state
, connector
, connector_state
, i
)
115 for_each_new_crtc_in_state(state
, crtc
, crtc_state
, i
) {
116 if (drm_atomic_crtc_needs_modeset(crtc_state
))
126 /* Get bitmask of crtcs that will need to be flushed. The bitmask
127 * can be used with for_each_crtc_mask() iterator, to iterate
128 * effected crtcs without needing to preserve the atomic state.
130 static unsigned get_crtc_mask(struct drm_atomic_state
*state
)
132 struct drm_crtc_state
*crtc_state
;
133 struct drm_crtc
*crtc
;
134 unsigned i
, mask
= 0;
136 for_each_new_crtc_in_state(state
, crtc
, crtc_state
, i
)
137 mask
|= drm_crtc_mask(crtc
);
142 void msm_atomic_commit_tail(struct drm_atomic_state
*state
)
144 struct drm_device
*dev
= state
->dev
;
145 struct msm_drm_private
*priv
= dev
->dev_private
;
146 struct msm_kms
*kms
= priv
->kms
;
147 struct drm_crtc
*async_crtc
= NULL
;
148 unsigned crtc_mask
= get_crtc_mask(state
);
149 bool async
= kms
->funcs
->vsync_time
&&
150 can_do_async(state
, &async_crtc
);
152 trace_msm_atomic_commit_tail_start(async
, crtc_mask
);
154 kms
->funcs
->enable_commit(kms
);
157 * Ensure any previous (potentially async) commit has
160 trace_msm_atomic_wait_flush_start(crtc_mask
);
161 kms
->funcs
->wait_flush(kms
, crtc_mask
);
162 trace_msm_atomic_wait_flush_finish(crtc_mask
);
164 mutex_lock(&kms
->commit_lock
);
167 * Now that there is no in-progress flush, prepare the
170 kms
->funcs
->prepare_commit(kms
, state
);
173 * Push atomic updates down to hardware:
175 drm_atomic_helper_commit_modeset_disables(dev
, state
);
176 drm_atomic_helper_commit_planes(dev
, state
, 0);
177 drm_atomic_helper_commit_modeset_enables(dev
, state
);
180 struct msm_pending_timer
*timer
=
181 &kms
->pending_timers
[drm_crtc_index(async_crtc
)];
183 /* async updates are limited to single-crtc updates: */
184 WARN_ON(crtc_mask
!= drm_crtc_mask(async_crtc
));
187 * Start timer if we don't already have an update pending
190 if (!(kms
->pending_crtc_mask
& crtc_mask
)) {
191 ktime_t vsync_time
, wakeup_time
;
193 kms
->pending_crtc_mask
|= crtc_mask
;
195 vsync_time
= kms
->funcs
->vsync_time(kms
, async_crtc
);
196 wakeup_time
= ktime_sub(vsync_time
, ms_to_ktime(1));
198 hrtimer_start(&timer
->timer
, wakeup_time
,
202 kms
->funcs
->disable_commit(kms
);
203 mutex_unlock(&kms
->commit_lock
);
206 * At this point, from drm core's perspective, we
207 * are done with the atomic update, so we can just
208 * go ahead and signal that it is done:
210 drm_atomic_helper_commit_hw_done(state
);
211 drm_atomic_helper_cleanup_planes(dev
, state
);
213 trace_msm_atomic_commit_tail_finish(async
, crtc_mask
);
219 * If there is any async flush pending on updated crtcs, fold
220 * them into the current flush.
222 kms
->pending_crtc_mask
&= ~crtc_mask
;
225 * Flush hardware updates:
227 trace_msm_atomic_flush_commit(crtc_mask
);
228 kms
->funcs
->flush_commit(kms
, crtc_mask
);
229 mutex_unlock(&kms
->commit_lock
);
232 * Wait for flush to complete:
234 trace_msm_atomic_wait_flush_start(crtc_mask
);
235 kms
->funcs
->wait_flush(kms
, crtc_mask
);
236 trace_msm_atomic_wait_flush_finish(crtc_mask
);
238 mutex_lock(&kms
->commit_lock
);
239 kms
->funcs
->complete_commit(kms
, crtc_mask
);
240 mutex_unlock(&kms
->commit_lock
);
241 kms
->funcs
->disable_commit(kms
);
243 drm_atomic_helper_commit_hw_done(state
);
244 drm_atomic_helper_cleanup_planes(dev
, state
);
246 trace_msm_atomic_commit_tail_finish(async
, crtc_mask
);