1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2014 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 */ 6 7 #include <drm/drm_atomic_uapi.h> 8 #include <drm/drm_gem_framebuffer_helper.h> 9 #include <drm/drm_vblank.h> 10 11 #include "msm_atomic_trace.h" 12 #include "msm_drv.h" 13 #include "msm_gem.h" 14 #include "msm_kms.h" 15 16 int msm_atomic_prepare_fb(struct drm_plane *plane, 17 struct drm_plane_state *new_state) 18 { 19 struct msm_drm_private *priv = plane->dev->dev_private; 20 struct msm_kms *kms = priv->kms; 21 22 if (!new_state->fb) 23 return 0; 24 25 drm_gem_fb_prepare_fb(plane, new_state); 26 27 return msm_framebuffer_prepare(new_state->fb, kms->aspace); 28 } 29 30 static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx) 31 { 32 unsigned crtc_mask = BIT(crtc_idx); 33 34 trace_msm_atomic_async_commit_start(crtc_mask); 35 36 mutex_lock(&kms->commit_lock); 37 38 if (!(kms->pending_crtc_mask & crtc_mask)) { 39 mutex_unlock(&kms->commit_lock); 40 goto out; 41 } 42 43 kms->pending_crtc_mask &= ~crtc_mask; 44 45 kms->funcs->enable_commit(kms); 46 47 /* 48 * Flush hardware updates: 49 */ 50 trace_msm_atomic_flush_commit(crtc_mask); 51 kms->funcs->flush_commit(kms, crtc_mask); 52 mutex_unlock(&kms->commit_lock); 53 54 /* 55 * Wait for flush to complete: 56 */ 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); 60 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); 65 66 out: 67 trace_msm_atomic_async_commit_finish(crtc_mask); 68 } 69 70 static enum hrtimer_restart msm_atomic_pending_timer(struct hrtimer *t) 71 { 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; 75 76 queue_work(priv->wq, &timer->work); 77 78 return HRTIMER_NORESTART; 79 } 80 81 static void msm_atomic_pending_work(struct work_struct *work) 82 { 83 struct msm_pending_timer *timer = container_of(work, 84 struct msm_pending_timer, work); 85 86 msm_atomic_async_commit(timer->kms, timer->crtc_idx); 87 } 88 89 void msm_atomic_init_pending_timer(struct msm_pending_timer *timer, 90 struct msm_kms *kms, int crtc_idx) 91 { 92 timer->kms = kms; 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); 97 } 98 99 static bool can_do_async(struct drm_atomic_state *state, 100 struct drm_crtc **async_crtc) 101 { 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; 107 108 if (!(state->legacy_cursor_update || state->async_update)) 109 return false; 110 111 /* any connector change, means slow path: */ 112 for_each_new_connector_in_state(state, connector, connector_state, i) 113 return false; 114 115 for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 116 if (drm_atomic_crtc_needs_modeset(crtc_state)) 117 return false; 118 if (++num_crtcs > 1) 119 return false; 120 *async_crtc = crtc; 121 } 122 123 return true; 124 } 125 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. 129 */ 130 static unsigned get_crtc_mask(struct drm_atomic_state *state) 131 { 132 struct drm_crtc_state *crtc_state; 133 struct drm_crtc *crtc; 134 unsigned i, mask = 0; 135 136 for_each_new_crtc_in_state(state, crtc, crtc_state, i) 137 mask |= drm_crtc_mask(crtc); 138 139 return mask; 140 } 141 142 void msm_atomic_commit_tail(struct drm_atomic_state *state) 143 { 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); 151 152 trace_msm_atomic_commit_tail_start(async, crtc_mask); 153 154 kms->funcs->enable_commit(kms); 155 156 /* 157 * Ensure any previous (potentially async) commit has 158 * completed: 159 */ 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); 163 164 mutex_lock(&kms->commit_lock); 165 166 /* 167 * Now that there is no in-progress flush, prepare the 168 * current update: 169 */ 170 kms->funcs->prepare_commit(kms, state); 171 172 /* 173 * Push atomic updates down to hardware: 174 */ 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); 178 179 if (async) { 180 struct msm_pending_timer *timer = 181 &kms->pending_timers[drm_crtc_index(async_crtc)]; 182 183 /* async updates are limited to single-crtc updates: */ 184 WARN_ON(crtc_mask != drm_crtc_mask(async_crtc)); 185 186 /* 187 * Start timer if we don't already have an update pending 188 * on this crtc: 189 */ 190 if (!(kms->pending_crtc_mask & crtc_mask)) { 191 ktime_t vsync_time, wakeup_time; 192 193 kms->pending_crtc_mask |= crtc_mask; 194 195 vsync_time = kms->funcs->vsync_time(kms, async_crtc); 196 wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1)); 197 198 hrtimer_start(&timer->timer, wakeup_time, 199 HRTIMER_MODE_ABS); 200 } 201 202 kms->funcs->disable_commit(kms); 203 mutex_unlock(&kms->commit_lock); 204 205 /* 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: 209 */ 210 drm_atomic_helper_commit_hw_done(state); 211 drm_atomic_helper_cleanup_planes(dev, state); 212 213 trace_msm_atomic_commit_tail_finish(async, crtc_mask); 214 215 return; 216 } 217 218 /* 219 * If there is any async flush pending on updated crtcs, fold 220 * them into the current flush. 221 */ 222 kms->pending_crtc_mask &= ~crtc_mask; 223 224 /* 225 * Flush hardware updates: 226 */ 227 trace_msm_atomic_flush_commit(crtc_mask); 228 kms->funcs->flush_commit(kms, crtc_mask); 229 mutex_unlock(&kms->commit_lock); 230 231 /* 232 * Wait for flush to complete: 233 */ 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); 237 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); 242 243 drm_atomic_helper_commit_hw_done(state); 244 drm_atomic_helper_cleanup_planes(dev, state); 245 246 trace_msm_atomic_commit_tail_finish(async, crtc_mask); 247 } 248