1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2cf3a7e4cSRob Clark /* 3cf3a7e4cSRob Clark * Copyright (C) 2014 Red Hat 4cf3a7e4cSRob Clark * Author: Rob Clark <robdclark@gmail.com> 5cf3a7e4cSRob Clark */ 6cf3a7e4cSRob Clark 772fdb40cSDaniel Vetter #include <drm/drm_atomic_uapi.h> 8feea39a8SSam Ravnborg #include <drm/drm_vblank.h> 972fdb40cSDaniel Vetter 10d934a712SRob Clark #include "msm_atomic_trace.h" 11cf3a7e4cSRob Clark #include "msm_drv.h" 12db8f4d5dSSean Paul #include "msm_gem.h" 13cf3a7e4cSRob Clark #include "msm_kms.h" 14cf3a7e4cSRob Clark 1543906812SRob Clark /* 1643906812SRob Clark * Helpers to control vblanks while we flush.. basically just to ensure 1743906812SRob Clark * that vblank accounting is switched on, so we get valid seqn/timestamp 1843906812SRob Clark * on pageflip events (if requested) 1943906812SRob Clark */ 2043906812SRob Clark 2143906812SRob Clark static void vblank_get(struct msm_kms *kms, unsigned crtc_mask) 2243906812SRob Clark { 2343906812SRob Clark struct drm_crtc *crtc; 2443906812SRob Clark 2543906812SRob Clark for_each_crtc_mask(kms->dev, crtc, crtc_mask) { 2643906812SRob Clark if (!crtc->state->active) 2743906812SRob Clark continue; 2843906812SRob Clark drm_crtc_vblank_get(crtc); 2943906812SRob Clark } 3043906812SRob Clark } 3143906812SRob Clark 3243906812SRob Clark static void vblank_put(struct msm_kms *kms, unsigned crtc_mask) 3343906812SRob Clark { 3443906812SRob Clark struct drm_crtc *crtc; 3543906812SRob Clark 3643906812SRob Clark for_each_crtc_mask(kms->dev, crtc, crtc_mask) { 3743906812SRob Clark if (!crtc->state->active) 3843906812SRob Clark continue; 3943906812SRob Clark drm_crtc_vblank_put(crtc); 4043906812SRob Clark } 4143906812SRob Clark } 4243906812SRob Clark 43b3d91800SKrishna Manikandan static void lock_crtcs(struct msm_kms *kms, unsigned int crtc_mask) 44b3d91800SKrishna Manikandan { 45743c97caSStephen Boyd int crtc_index; 46b3d91800SKrishna Manikandan struct drm_crtc *crtc; 47b3d91800SKrishna Manikandan 48743c97caSStephen Boyd for_each_crtc_mask(kms->dev, crtc, crtc_mask) { 49743c97caSStephen Boyd crtc_index = drm_crtc_index(crtc); 50743c97caSStephen Boyd mutex_lock_nested(&kms->commit_lock[crtc_index], crtc_index); 51743c97caSStephen Boyd } 52b3d91800SKrishna Manikandan } 53b3d91800SKrishna Manikandan 54b3d91800SKrishna Manikandan static void unlock_crtcs(struct msm_kms *kms, unsigned int crtc_mask) 55b3d91800SKrishna Manikandan { 56b3d91800SKrishna Manikandan struct drm_crtc *crtc; 57b3d91800SKrishna Manikandan 58cb21f3f8SRob Clark for_each_crtc_mask_reverse(kms->dev, crtc, crtc_mask) 59b3d91800SKrishna Manikandan mutex_unlock(&kms->commit_lock[drm_crtc_index(crtc)]); 60b3d91800SKrishna Manikandan } 61b3d91800SKrishna Manikandan 622d99ced7SRob Clark static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx) 632d99ced7SRob Clark { 642d99ced7SRob Clark unsigned crtc_mask = BIT(crtc_idx); 652d99ced7SRob Clark 66d934a712SRob Clark trace_msm_atomic_async_commit_start(crtc_mask); 67d934a712SRob Clark 68b3d91800SKrishna Manikandan lock_crtcs(kms, crtc_mask); 692d99ced7SRob Clark 702d99ced7SRob Clark if (!(kms->pending_crtc_mask & crtc_mask)) { 71b3d91800SKrishna Manikandan unlock_crtcs(kms, crtc_mask); 72d934a712SRob Clark goto out; 732d99ced7SRob Clark } 742d99ced7SRob Clark 752d99ced7SRob Clark kms->pending_crtc_mask &= ~crtc_mask; 762d99ced7SRob Clark 772d99ced7SRob Clark kms->funcs->enable_commit(kms); 782d99ced7SRob Clark 7943906812SRob Clark vblank_get(kms, crtc_mask); 8043906812SRob Clark 812d99ced7SRob Clark /* 822d99ced7SRob Clark * Flush hardware updates: 832d99ced7SRob Clark */ 84d934a712SRob Clark trace_msm_atomic_flush_commit(crtc_mask); 852d99ced7SRob Clark kms->funcs->flush_commit(kms, crtc_mask); 862d99ced7SRob Clark 872d99ced7SRob Clark /* 882d99ced7SRob Clark * Wait for flush to complete: 892d99ced7SRob Clark */ 90d934a712SRob Clark trace_msm_atomic_wait_flush_start(crtc_mask); 912d99ced7SRob Clark kms->funcs->wait_flush(kms, crtc_mask); 92d934a712SRob Clark trace_msm_atomic_wait_flush_finish(crtc_mask); 932d99ced7SRob Clark 9443906812SRob Clark vblank_put(kms, crtc_mask); 9543906812SRob Clark 962d99ced7SRob Clark kms->funcs->complete_commit(kms, crtc_mask); 97b3d91800SKrishna Manikandan unlock_crtcs(kms, crtc_mask); 982d99ced7SRob Clark kms->funcs->disable_commit(kms); 99d934a712SRob Clark 100d934a712SRob Clark out: 101d934a712SRob Clark trace_msm_atomic_async_commit_finish(crtc_mask); 1022d99ced7SRob Clark } 1032d99ced7SRob Clark 104363bcec9SRob Clark static void msm_atomic_pending_work(struct kthread_work *work) 1052d99ced7SRob Clark { 1062d99ced7SRob Clark struct msm_pending_timer *timer = container_of(work, 107ddb6e37aSRob Clark struct msm_pending_timer, work.work); 1082d99ced7SRob Clark 1092d99ced7SRob Clark msm_atomic_async_commit(timer->kms, timer->crtc_idx); 1102d99ced7SRob Clark } 1112d99ced7SRob Clark 112363bcec9SRob Clark int msm_atomic_init_pending_timer(struct msm_pending_timer *timer, 1132d99ced7SRob Clark struct msm_kms *kms, int crtc_idx) 1142d99ced7SRob Clark { 1152d99ced7SRob Clark timer->kms = kms; 1162d99ced7SRob Clark timer->crtc_idx = crtc_idx; 117363bcec9SRob Clark 118363bcec9SRob Clark timer->worker = kthread_create_worker(0, "atomic-worker-%d", crtc_idx); 119363bcec9SRob Clark if (IS_ERR(timer->worker)) { 120363bcec9SRob Clark int ret = PTR_ERR(timer->worker); 121363bcec9SRob Clark timer->worker = NULL; 122363bcec9SRob Clark return ret; 123363bcec9SRob Clark } 124363bcec9SRob Clark sched_set_fifo(timer->worker->task); 125ddb6e37aSRob Clark 126ddb6e37aSRob Clark msm_hrtimer_work_init(&timer->work, timer->worker, 127ddb6e37aSRob Clark msm_atomic_pending_work, 128ddb6e37aSRob Clark CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 129363bcec9SRob Clark 130363bcec9SRob Clark return 0; 131363bcec9SRob Clark } 132363bcec9SRob Clark 133363bcec9SRob Clark void msm_atomic_destroy_pending_timer(struct msm_pending_timer *timer) 134363bcec9SRob Clark { 135363bcec9SRob Clark if (timer->worker) 136363bcec9SRob Clark kthread_destroy_worker(timer->worker); 1372d99ced7SRob Clark } 1382d99ced7SRob Clark 1392d99ced7SRob Clark static bool can_do_async(struct drm_atomic_state *state, 1402d99ced7SRob Clark struct drm_crtc **async_crtc) 1412d99ced7SRob Clark { 1422d99ced7SRob Clark struct drm_connector_state *connector_state; 1432d99ced7SRob Clark struct drm_connector *connector; 1442d99ced7SRob Clark struct drm_crtc_state *crtc_state; 1452d99ced7SRob Clark struct drm_crtc *crtc; 1462d99ced7SRob Clark int i, num_crtcs = 0; 1472d99ced7SRob Clark 1482d99ced7SRob Clark if (!(state->legacy_cursor_update || state->async_update)) 1492d99ced7SRob Clark return false; 1502d99ced7SRob Clark 1512d99ced7SRob Clark /* any connector change, means slow path: */ 1522d99ced7SRob Clark for_each_new_connector_in_state(state, connector, connector_state, i) 1532d99ced7SRob Clark return false; 1542d99ced7SRob Clark 1552d99ced7SRob Clark for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 1562d99ced7SRob Clark if (drm_atomic_crtc_needs_modeset(crtc_state)) 1572d99ced7SRob Clark return false; 1582d99ced7SRob Clark if (++num_crtcs > 1) 1592d99ced7SRob Clark return false; 1602d99ced7SRob Clark *async_crtc = crtc; 1612d99ced7SRob Clark } 1622d99ced7SRob Clark 1632d99ced7SRob Clark return true; 1642d99ced7SRob Clark } 1652d99ced7SRob Clark 166d4d2c604SRob Clark /* Get bitmask of crtcs that will need to be flushed. The bitmask 167d4d2c604SRob Clark * can be used with for_each_crtc_mask() iterator, to iterate 168d4d2c604SRob Clark * effected crtcs without needing to preserve the atomic state. 169d4d2c604SRob Clark */ 170d4d2c604SRob Clark static unsigned get_crtc_mask(struct drm_atomic_state *state) 171d4d2c604SRob Clark { 172d4d2c604SRob Clark struct drm_crtc_state *crtc_state; 173d4d2c604SRob Clark struct drm_crtc *crtc; 174d4d2c604SRob Clark unsigned i, mask = 0; 175d4d2c604SRob Clark 176d4d2c604SRob Clark for_each_new_crtc_in_state(state, crtc, crtc_state, i) 177d4d2c604SRob Clark mask |= drm_crtc_mask(crtc); 178d4d2c604SRob Clark 179d4d2c604SRob Clark return mask; 180d4d2c604SRob Clark } 181d4d2c604SRob Clark 182d14659f5SSean Paul void msm_atomic_commit_tail(struct drm_atomic_state *state) 183cf3a7e4cSRob Clark { 184cf3a7e4cSRob Clark struct drm_device *dev = state->dev; 1850b776d45SRob Clark struct msm_drm_private *priv = dev->dev_private; 1860b776d45SRob Clark struct msm_kms *kms = priv->kms; 1872d99ced7SRob Clark struct drm_crtc *async_crtc = NULL; 188d4d2c604SRob Clark unsigned crtc_mask = get_crtc_mask(state); 18952ff0d30SRob Clark bool async = can_do_async(state, &async_crtc); 1900b776d45SRob Clark 191d934a712SRob Clark trace_msm_atomic_commit_tail_start(async, crtc_mask); 192d934a712SRob Clark 193e35a29d5SRob Clark kms->funcs->enable_commit(kms); 1942d99ced7SRob Clark 1952d99ced7SRob Clark /* 1962d99ced7SRob Clark * Ensure any previous (potentially async) commit has 1972d99ced7SRob Clark * completed: 1982d99ced7SRob Clark */ 199b3d91800SKrishna Manikandan lock_crtcs(kms, crtc_mask); 200d934a712SRob Clark trace_msm_atomic_wait_flush_start(crtc_mask); 2012d99ced7SRob Clark kms->funcs->wait_flush(kms, crtc_mask); 202d934a712SRob Clark trace_msm_atomic_wait_flush_finish(crtc_mask); 2032d99ced7SRob Clark 2042d99ced7SRob Clark /* 2052d99ced7SRob Clark * Now that there is no in-progress flush, prepare the 2062d99ced7SRob Clark * current update: 2072d99ced7SRob Clark */ 208*078f6ec8SJessica Zhang if (kms->funcs->prepare_commit) 2090b776d45SRob Clark kms->funcs->prepare_commit(kms, state); 210cf3a7e4cSRob Clark 2119f6b6564SRob Clark /* 2129f6b6564SRob Clark * Push atomic updates down to hardware: 2139f6b6564SRob Clark */ 2141af434a9SDaniel Vetter drm_atomic_helper_commit_modeset_disables(dev, state); 2152b58e98dSLiu Ying drm_atomic_helper_commit_planes(dev, state, 0); 2161af434a9SDaniel Vetter drm_atomic_helper_commit_modeset_enables(dev, state); 217cf3a7e4cSRob Clark 2182d99ced7SRob Clark if (async) { 2192d99ced7SRob Clark struct msm_pending_timer *timer = 2202d99ced7SRob Clark &kms->pending_timers[drm_crtc_index(async_crtc)]; 2212d99ced7SRob Clark 2222d99ced7SRob Clark /* async updates are limited to single-crtc updates: */ 2232d99ced7SRob Clark WARN_ON(crtc_mask != drm_crtc_mask(async_crtc)); 2242d99ced7SRob Clark 2252d99ced7SRob Clark /* 2262d99ced7SRob Clark * Start timer if we don't already have an update pending 2272d99ced7SRob Clark * on this crtc: 2282d99ced7SRob Clark */ 2292d99ced7SRob Clark if (!(kms->pending_crtc_mask & crtc_mask)) { 2302d99ced7SRob Clark ktime_t vsync_time, wakeup_time; 2312d99ced7SRob Clark 2322d99ced7SRob Clark kms->pending_crtc_mask |= crtc_mask; 2332d99ced7SRob Clark 23452ff0d30SRob Clark if (drm_crtc_next_vblank_start(async_crtc, &vsync_time)) 23552ff0d30SRob Clark goto fallback; 23652ff0d30SRob Clark 2372d99ced7SRob Clark wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1)); 2382d99ced7SRob Clark 239ddb6e37aSRob Clark msm_hrtimer_queue_work(&timer->work, wakeup_time, 2402d99ced7SRob Clark HRTIMER_MODE_ABS); 2412d99ced7SRob Clark } 2422d99ced7SRob Clark 2432d99ced7SRob Clark kms->funcs->disable_commit(kms); 244b3d91800SKrishna Manikandan unlock_crtcs(kms, crtc_mask); 2452d99ced7SRob Clark /* 2462d99ced7SRob Clark * At this point, from drm core's perspective, we 2472d99ced7SRob Clark * are done with the atomic update, so we can just 2482d99ced7SRob Clark * go ahead and signal that it is done: 2492d99ced7SRob Clark */ 2502d99ced7SRob Clark drm_atomic_helper_commit_hw_done(state); 2512d99ced7SRob Clark drm_atomic_helper_cleanup_planes(dev, state); 2522d99ced7SRob Clark 253d934a712SRob Clark trace_msm_atomic_commit_tail_finish(async, crtc_mask); 254d934a712SRob Clark 2552d99ced7SRob Clark return; 2562d99ced7SRob Clark } 2572d99ced7SRob Clark 25852ff0d30SRob Clark fallback: 2592d99ced7SRob Clark /* 2602d99ced7SRob Clark * If there is any async flush pending on updated crtcs, fold 2612d99ced7SRob Clark * them into the current flush. 2622d99ced7SRob Clark */ 2632d99ced7SRob Clark kms->pending_crtc_mask &= ~crtc_mask; 2642d99ced7SRob Clark 26543906812SRob Clark vblank_get(kms, crtc_mask); 26643906812SRob Clark 2679f6b6564SRob Clark /* 2689f6b6564SRob Clark * Flush hardware updates: 2699f6b6564SRob Clark */ 270d934a712SRob Clark trace_msm_atomic_flush_commit(crtc_mask); 2719f6b6564SRob Clark kms->funcs->flush_commit(kms, crtc_mask); 272b3d91800SKrishna Manikandan unlock_crtcs(kms, crtc_mask); 2732d99ced7SRob Clark /* 2742d99ced7SRob Clark * Wait for flush to complete: 2752d99ced7SRob Clark */ 276d934a712SRob Clark trace_msm_atomic_wait_flush_start(crtc_mask); 277d4d2c604SRob Clark kms->funcs->wait_flush(kms, crtc_mask); 278d934a712SRob Clark trace_msm_atomic_wait_flush_finish(crtc_mask); 2792d99ced7SRob Clark 28043906812SRob Clark vblank_put(kms, crtc_mask); 28143906812SRob Clark 282b3d91800SKrishna Manikandan lock_crtcs(kms, crtc_mask); 28380b4b4a7SRob Clark kms->funcs->complete_commit(kms, crtc_mask); 284b3d91800SKrishna Manikandan unlock_crtcs(kms, crtc_mask); 285e35a29d5SRob Clark kms->funcs->disable_commit(kms); 28670db18dcSSean Paul 28770db18dcSSean Paul drm_atomic_helper_commit_hw_done(state); 28870db18dcSSean Paul drm_atomic_helper_cleanup_planes(dev, state); 289d934a712SRob Clark 290d934a712SRob Clark trace_msm_atomic_commit_tail_finish(async, crtc_mask); 291347b90b4SSean Paul } 292